欢迎来到 Kong Xiangqun 的博客

25、stream api、自定义注解

一、什么是Stream API

A sequence of elements supporting sequential and parallel
aggregate operations
Stream是一组用来处理数组、集合的API
 
▪ Java 8之所以费这么大功夫引入函数式编程,原因有二:
  – 代码简洁函数式编程写出的代码简洁且意图明确,使用stream接口让你从
    此告别for循环。
  – 多核友好,Java函数式编程使得编写并行程序从未如此简单,你需要的全部
    就是调用一下parallel()方法。
 

二、Stream特性

1:不是数据结构,没有内部存储
2:不支持索引访问
3:延迟计算
4:支持并行
5:很容易生成数组或集合(List,Set)
6:支持过滤,查找,转换,汇总,聚合等操作
 

三、Stream运行机制

Stream分为 源source,中间操作,终止操作
流的源可以是一个数组、一个集合、一个生成器方法,一个I/O通道等等。
一个流可以有零个和或者多个中间操作,每一个中间操作都会返回
一个新的流,供下一个操作使用。一个流只会有一个终止操作
Stream只有遇到终止操作,它的源才开始执行遍历操作
 

四、Stream的创建

 

 

 

1、通过数组
2、通过集合来
3、通过Stream.generate方法来创建
4、通过Stream.iterate方法来创建
5、其他API创建

 

 

public class StreamDemo {

    //通过数组来生成
    static void gen1(){
        String[] strs = {"a","b","c","d"};
        Stream<String> strs1 = Stream.of(strs);
        strs1.forEach(System.out::println);
    }

    //通过集合来生成
    static void gen2(){
        List<String> list = Arrays.asList("1","2","3","4");
        Stream<String> stream = list.stream();
        stream.forEach(System.out::println);
    }

    //generate
    static void gen3(){
        Stream<Integer> generate = Stream.generate(() -> 1); // generate(Supplier<T> s)返回无限顺序无序流, 其中每个元素由提供的Suppliter
        generate.limit(5).forEach(System.out::println); // 没有limit 程序就不会中断 无限的
    }

    //使用iterator
    static void gen4() {
        Stream<Integer> iterate = Stream.iterate(1, x -> x + 1);
        iterate.limit(5).forEach(System.out::println);
    }


    //其他方式
    static void gen5(){
        String str = "abcd";
        IntStream stream =str.chars();
        stream.forEach(System.out::println);
    }
    public static void main(String[] args) {
        //stream生成的操作
        gen1();
        gen2();
        gen3();
        gen4();
        gen5();
    }  
}

打印结果为:

/*
a
b
c
d
1
2
3
4
1
1
1
1
2
3
97
98
99
100

Process finished with exit code 0
*/

 

五、Stream常用API

中间操作
  过滤 filter
  去重 distinct
  排序 sorted
  截取 limit、skip
  转换 map/flatMap
  其他 peek
 
终止操作
  循环 forEach
  计算 min、max、count、 average
  匹配 anyMatch、 allMatch、 noneMatch、 findFirst、 findAny
  汇聚 reduce
  收集器 toArray collect
 
示例1:
public class StreamDemo {
    public static void main(String[] args) {//中间操作:如果调用方法之后返回的结果是Stream对象就意味着是一个中间操作
        Arrays.asList(1,2,3,4,5).stream().filter((x)->x%2==0).forEach(System.out::println);
        //求出结果集中所有偶数的和
        int count = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9).stream().filter(x -> x % 2 == 0).mapToInt(x->x).sum();
        System.out.println(count);
        //求集合中的最大值
        List<Integer> list = Arrays.asList(1,2, 3,4, 5, 6);
        Optional<Integer> max = list.stream().max((a, b) -> a - b);
        System.out.println(max.get());
        //求集合的最小值
        System.out.println(list.stream().min((a, b) -> a-b).get());

        Optional<Integer> any = list.stream().filter(x -> x % 2 == 0).findAny(); // 任意取一个
        System.out.println(any.get());

        Optional<Integer> first = list.stream().filter(x -> x % 10 == 6).findFirst();
        System.out.println(first.get());

        Stream<Integer> integerStream = list.stream().filter(i -> {
            System.out.println("运行代码");
            return i % 2 == 0;
        });
        System.out.println(integerStream.findAny().get());
    }  
}

打印结果为:

/*
2
4
20
6
1
2
6
运行代码
运行代码
2
*/

为什么会打印两次 “运行代码”

把每一个元素分别取出来,执行中间操作到终止操作
1 拿出来 中间操作 打印一次 “运行代码”
2 拿出来 中间操作 打印一次 “运行代码”
满足条件,findAny终止操作,不再继续向下
如果是
List<Integer> list = Arrays.asList(1, 3, 5, 6);
呢, 打印几次?
结果是四次
6满足条件终止操作
 
相当于流水线,拿出1个 走完全部过程 走filter、FindAny

 

 示例2:

public class StreamDemo {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1,2, 3,4, 5, 6);
        //获取最大值和最小值但是不使用min和max方法
        Optional<Integer> min = list.stream().sorted().findFirst();
        System.out.println(min.get());
        Optional<Integer> max2 = list.stream().sorted((a, b) -> b - a).findFirst();
        System.out.println(max2.get());

        Arrays.asList("java","c#","python","scala").stream().sorted().forEach(System.out::println);
        Arrays.asList("java","c#","python","scala").stream().sorted((a,b)->a.length()-b.length()).forEach(System.out::println);
    } 

}

打印结果为:

/*
1
6
c#
java
python
scala
c#
java
scala
python

Process finished with exit code 0
*/

 示例3:

public class StreamDemo {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1,2, 3,4, 5, 6);
        //想将集合中的元素进行过滤同时返回一个集合对象
        List<Integer> collect = list.stream().filter(x -> x % 2 == 0).collect(Collectors.toList());
        collect.forEach(System.out::println);
    } 

}

打印结果为:

/*
2
4
6

Process finished with exit code 0
*/

 示例4:

public class StreamDemo {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1,2, 3,4, 5, 6);
        //去重操作
        Arrays.asList(1,2,3,3,3,4,5,2).stream().distinct().forEach(System.out::println);
        System.out.println("---------------");
        Arrays.asList(1,2,3,3,3,4,5,2).stream().collect(Collectors.toSet()).forEach(System.out::println);
    } 

}

 示例5:

public class StreamDemo {
    public static void main(String[] args) {
        //打印20-30这样的集合数据
        Stream.iterate(1,x->x+1).limit(50).skip(20).limit(10).forEach(System.out::println); // skip跳过20个输出10个

        String str ="11,22,33,44,55"; // 求和
        System.out.println(Stream.of(str.split(",")).mapToInt(x -> Integer.valueOf(x)).sum());
        System.out.println(Stream.of(str.split(",")).mapToInt(Integer::valueOf).sum());
        System.out.println(Stream.of(str.split(",")).map(x -> Integer.valueOf(x)).mapToInt(x -> x).sum());
        System.out.println(Stream.of(str.split(",")).map(Integer::valueOf).mapToInt(x -> x).sum());
    } 

}

打印结果为:

/*
21
22
23
24
25
26
27
28
29
30
165
165
165
165

Process finished with exit code 0
*/

 示例6:

public class StreamDemo {
    public static void main(String[] args) {
        //创建一组自定义对象
        String str2 = "java,scala,python";
        Stream.of(str2.split(",")).map(x->new com.mashibing.stream.Person(x)).forEach(System.out::println);
        Stream.of(str2.split(",")).map(com.mashibing.stream.Person::new).forEach(System.out::println);
        Stream.of(str2.split(",")).map(x-> com.mashibing.stream.Person.build(x)).forEach(System.out::println);
        Stream.of(str2.split(",")).map(com.mashibing.stream.Person::build).forEach(System.out::println); // 静态方法的方式
    } 

}
public class Person {
    private String name;

    public Person() {
    }
public Person(String name) { this.name = name; } public static Person build(String name){ Person p = new Person(); p.setName(name); return p; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Deprecated public static void show(){ System.out.println("show"); } @Override public String toString() { return "Person{" + "name='" + name + '\'' + '}'; } public static void main(String[] args) { Person p = new Person(); show(); Date date = new Date(); System.out.println(date.getMinutes()); } }

打印结果为:

/*
Person{name='java'}
Person{name='scala'}
Person{name='python'}
Person{name='java'}
Person{name='scala'}
Person{name='python'}
Person{name='java'}
Person{name='scala'}
Person{name='python'}
Person{name='java'}
Person{name='scala'}
Person{name='python'}

Process finished with exit code 0
*/

 

示例7:

public class StreamDemo {
    public static void main(String[] args) {
        String str ="11,22,33,44,55";
        //将str中的每一个数值都打印出来,同时算出最终的求和结果
        System.out.println(Stream.of(str.split(",")).peek(System.out::println).mapToInt(Integer::valueOf).sum());
    } 

}

打印结果为:

/*
11
22
33
44
55
165

Process finished with exit code 0
*/

示例8:

public class StreamDemo {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1,2, 3,4, 5, 6);
        System.out.println(list.stream().allMatch(x -> x>=0));
}

打印结果为:

/*
true

Process finished with exit code 0
*/

六、自定义注解

1、什么是注解?

▪ Annontation是Java5开始引入的新特征,中文名称叫注解。
▪ 它提供了一种安全的类似注释的机制,用来将任何的信息或元数据(metadata)与程序元素(类、方法、成员变量等)进行关联。
▪ 为程序的元素(类、方法、成员变量)加上更直观更明了的说明,这些说明信息是与程序的业务逻辑无关,并且供指定的工具戒框架使用。
▪ Annontation像一种修饰符一样,应用于包、类型、构造方法、方法、成员变量、参数及本地变量的声明语句中。
▪ Java注解是附加在代码中的一些元信息,用于一些工具在编译、运行时进行解析和使用,起到说明、配置的功能。
▪ 注解不会也不能影响代码的实际逻辑,仅仅起到辅助性的作用。包含在java.lang.annotation 包中。

 

2、注解的作用

▪ 生成文档。这是最常见的,也是java 最早提供的注解。常用的有@param @return 等  /** + 回车就会看到
▪ 跟踪代码依赖性,实现替代配置文件功能。
▪ 在编译时进行格式检查。如@override 放在方法前,如果你这个方法并不是覆盖了超类方法,则编译时就能检查出。

 

3、注解的原理

反射
 

4、内置注解

▪ @Override:定义在java.lang.Override中,此注释叧适用于修饰方法,表示一个方法声明打算重写超类中的另一个方法声明
▪ @Deprecated:定义在java.lang.Deprecated中,此注释可以修饰方法、属性、类,表示不鼓励程序员使用这样的元素,通常
是因为它很危险或者存在更好的选择
▪ @SuppressWarnings:定义在java.lang.SuppressWarnings中,用来抑制编写编译时的警告信息 比如定义一个变量没用到会是灰色,加@SuppressWarnings("all") 就会是正常的黑色

5、元注解

▪ 元注解的做用是负责注解其他注解,java中定义了四个标准的meta-annotation类型,他们被用来提供对其他annotation类型作说明
▪ 这些类型和它们所支持的类在java.lang.annotation包中
– @Target:用来描述注解的使用范围(注解可以用在什么地方)
– @Retention:表示需要在什么级别保存该注释信息,描述注解的生命周期
  ▪ Source < Class < Runtime
– @Document:说明该注解将被包含在javadoc中
– @Inherited:说明子类可以继承父类中的该注解
 
 

6、自定义注解

▪ 使用@interfac自定义注解时,自动继承了
java.lang.annotation.Annotation接口
▪ 使用规则:
– @interface用来声明一个注解,格式:public @interface 注解名{}
– 其中的每一个方法实际上是声明了一个配置参数
– 方法的名称就是参数的名称
– 返回值类型就是参数的类型(返回值叧能是基本类型,Class,String,enum)
– 可以用default来声明参数的默认值
– 如果叧有一个参数成员,一般参数名为value
– 注解元素必须要有值,我们定义注解元素时,经常使用空字符串,0作为默认值
 
//target用来声明当前自定义的注解适合适用于什么地方,类,方法,变量,包。。。。
@Target({ElementType.METHOD,ElementType.TYPE})
//retention用来表示当前注解适用于什么环境,是源码级别还是类级别还是运行时环境,一般都是运行时环境
@Retention(RetentionPolicy.CLASS)
//表示该注解是否是显示在javadoc中
@Documented
//表示当前注解是否能够被继承
@Inherited
@interface MyAnnotation{

    //定义的方式看起来像是方法,但是实际上使用在使用注解的时候填写的参数的名称,默认的名称是value
    //自定义注解中填写的所有方法都需要在使用注解的时候,添加值,很麻烦,因此包含默认值
    String name() default "zhangsan";
    int age() default 12;
    int id() default 1;
    String[] likes() default {"a","b","c"};
}
//@MyAnnotation(name="hehe",age=12,id=3,likes = {"book","lol","movie"})
@MyAnnotation
public class MetaAnnotation {
    public void test(){

    }
}

 

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
posted @ 2022-04-25 21:46  kongxiangqun20220317  阅读(61)  评论(0编辑  收藏  举报