一、Stream
1、Stream概述
一组用来处理数组、集合的api
java 8之所以引入函数式编程有两个主要原因
- 代码简洁,意图明确,stream接口可以让你告别for循环
- 多核友好,并行程序编写变得极为简单,只需调用一下parallel()方法
stream特性
- 不是数据结构,没有内部存储
- 不支持索引访问
- 延迟计算
- 支持并行
- 很容易生成数组或集合(List,Set)
- 支持过滤,查找,转换,汇总,聚合等操作
stream运行机制
- 分为源source,中间操作,终止操作
- 流的源可以是一个数组、一个集合,一个生成器方法,一个I/O通道等等。
- 一个流可以有零个和或者多个中间操作,每一个中间操作都会返回一个新的流,供下一个操作使用,一个流只会有一个终止操作
- Stream只有遇到终止操作,它的源才开始执行遍历操作
Stream的创建
- 通过数组
- 通过集合
- 通过Stream.generate方法
- 通过Stream.iterate方法
- 其他API创建
中间操作
- 过滤 filter
- 去重 distinct
- 排序 sorted
- 截取 limit、skip
- 转换 map/flatMap
- 其他 peek
终止操作
- 循环 forEach
- 计算 min、max、count、average
- 匹配 anyMatch、allMatch、noneMatch、findFirst、findAny
- 汇聚 reduce
- 收集器 toArray collect
2、创建Stream对象
package com.company;
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.function.Supplier;
import java.util.stream.IntStream;
import java.util.stream.Stream;
public class Main{
//通过数组生成
static void gen1(){
Integer num[] = {1,2,3,4,5};
//Stream类中有静态方法of(T t)返回包含单个元素的顺序Stream,of(T…values)的流返回其元素为指定值的顺序有序流
Stream<Integer> num1 = Stream.of(num);
num1.forEach(System.out::print);//System.out::print 实例方法引用,引用System.out类的print方法
}
//通过集合生成
static void gen2(){
List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5);
Stream<List<Integer>> integers1 = Stream.of(integers);
integers1.forEach(System.out::print);
}
//通过generate
static void gen3(){
//流generate(Supplier s)返回无限顺序无序流,其中每个元素由提供的供应商生成。这适用于生成恒定流,随机元素流等。其中Supplier是函数式接口,表示一个输出
// Supplier supplier = ()->1; 只能有一个输出,不能有输入
Stream<Integer> generate = Stream.generate(() -> (Integer)new Random().nextInt(10));
//limit(Integer i) 规定流生成的个数,因为generate是无限流。如果不规定会一直生产下去
generate.limit(10).forEach((e)->System.out.print(e+" "));
}
//通过iterator
static void gen4(){
//Stream.iterate(常量,一输入一输出函数式接口);通过迭代函数,生成一个有序无限的数据流。(由于是无限流,一般都是配合limit来使用)
Stream<Integer> iterate = Stream.iterate(1, (x) -> x + 1);
iterate.limit(10).forEach((e)-> System.out.print(e+" "));
}
//其他方法
static void gen5(){
String abcdef = "abcdef";
IntStream intStream = abcdef.chars();
intStream.forEach(System.out::print);
}
public static void main(String[] args) {
gen1();
System.out.println();
gen2();
System.out.println();
gen3();
System.out.println();
gen4();
System.out.println();
gen5();
}
}
3、中间操作和终止操作
package com.company;
import org.w3c.dom.ls.LSOutput;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.OptionalInt;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class Main{
public static void main(String[] args) {
List<Integer> integers = Arrays.asList(1, 2, 3, 4,5,6,7,8,9,10);//创建一个包含10个元素的集合
//List.stream()方法,用于将可迭代对象,转换为Stream流对象
//filter()方法是一个过滤方法,用于返回结果为true的对象,比如下面x>5的数返回为true就表示这个x是满足条件的元素,会添加到Stream流中
Stream<Integer> integerStream = integers.stream().filter((x) -> {
return x > 5;//如果条件为false,那么当前元素会被过滤掉,如果为true,当前元素会被留下放在流中
});
integerStream.forEach((e)-> System.out.print(e+" "));
//mapToInt()返回一个IntStream,其中包括将给定函数应用于此流的元素的结果。IntStream中有一些方法,比如sum就是求和方法
int sum = integers.stream().mapToInt(x -> x).sum();
System.out.println("\n"+sum);
//去重,distinct方法用于去重
System.out.println(
Arrays.asList(1, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4, 4, 4, 4).stream().distinct().collect(Collectors.toList()).toString()
);
//max 取最大值,但是返回OptionalInt对象,其中有get方法可以取值
OptionalInt max = integers.stream().mapToInt(x -> x).max();
System.out.println(max.getAsInt());
//我喜欢的取最大值和最小值方法,sorted()排序方法默认自然排序,就是从小到大,需要从大到小需要自己写逻辑,findFitst()返回第一个元素
Optional<Integer> min = integers.stream().sorted().findFirst();
//(a,b) -> b - a,a和b是依次遍历的值,b-a表示如果当前b的值-a的值,是正数,说明b这个值大,放前面
Optional<Integer> Max = integers.stream().sorted((a, b) -> b - a).findAny();
System.out.println(min.get()+"------------"+Max.get());
/**将集合中元素做某些操作,然后重新返回一个集合
* collect方法,将stream对象转换为Collector接口,此接口的toList方法可以将序列转换为List集合
* */
List<Integer> collect = integers.stream().sorted((a,b)->b-a).collect(Collectors.toList());
System.out.println(collect.toString());
//获取20-30集合的三种方式
Stream.iterate(20,x->x+1).limit(11).forEach(e-> System.out.print(e+" "));
System.out.println();
//skip方法用于跳过指定次数的生产
Stream.iterate(1,x->x+1).limit(30).skip(19).forEach(e -> System.out.print(e+" "));
System.out.println();
//下面这种方法其实多余,就是告诉大家,跳过后还可以用limit规定多少个
Stream.iterate(1,x->x+1).limit(100).skip(19).limit(11).forEach(e -> System.out.print(e+" "));
}
}
二、自定义注解
1、注解概述
package com.company;
import java.lang.annotation.*;
public class Main{
@MyAnnotation(int1 = "a",value = "a")
public static void main(String[] args) {
}
}
/**
* 使用@interface定义一个注解
*
* @Taarget注解 标注当前自定义注解的作用范围,只有一个value属性,
* 其中ElementType.METHOD,表示此注解可以用在方法上,
* ElementType.TYPE表示可以用在类上
* 还有其它的请参考源码的注释,都有解释
* @Retention 标注当前自定义注解在什么环境可以被识别
* RetentionPolicy.SOURCE 表示在源码级别可以被识别
* RetentionPolicy.CLASS 表示在类的环境下
* RetentionPolicy.RUNTIME 表示在运行时
*/
@Target(value = {ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.CLASS)
@Documented //标注当前注解在生成java文档时,包含在文档中,就是javadoc中
@Inherited //标注当前注解可以被子类继承
@interface MyAnnotation{
/**
* 这里定义的不是方法了,而是注解的参数值也就是注解后面括号中需要传递的参数
* 默认是value,如果是value可以省略
*/
String[] value();//数组参数,使用时,如果只有一个值,可以直接写,如果有多个参数需要value = {"1","2"}
String int1(); //非数组参数,使用时,直接赋值即可
String int2() default "10";//包含默认值,如果不指定默认值,那么使用注解时,必须为参数赋值,加上default后,可以不赋值,自动使用默认值
}