欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

JDK1.8 Stream & Optional & Consumer/Supplier/Predicate/Function

程序员文章站 2022-06-04 19:31:55
...

JDK1.8 Stream & Optional & Consumer/Supplier/Predicate/Function

常量词解释

@FunctionalInterface注解

​ FunctionalInterface 顾名知义是函数式接口的。函数式接口首先它得是一个接口,然后就是在这个接口里面只能有一个抽象方法。这种类型的接口也称为SAM接口,即Single Abstract Method interfaces。
​ 注意:虽然它只能有一个抽象方法,但是他允许定义默认方法和静态方法。例如下述的 Consumer 就是一个典型的函数式接口

Consumer接口(消费者)

​ consumer接口就是一个消费型的接口,通过传入参数,然后处理此参数。即可写作 (T t) -> {}。与之相同的有DoubleConsumer、IntConsumer、LongConsumer 与之类似的有BiConsumerBiConsumer 为两个参数

@FunctionalInterface
public interface Consumer<T> {

    //抽象接口
    void accept(T t);
    
    //默认的方法 处理后置组成
    default Consumer<T> andThen(Consumer<? super T> after) {
        Objects.requireNonNull(after);
        return (T t) -> { accept(t); after.accept(t); };
	}
}

e.g.:

Consumer<Engineer> engineerConsumer = new Consumer<Engineer>() {
    @Override
    public void accept(Engineer e) {
        if (e.getName() == null) {
            e.setName("张阿三");
        }else{
            e.setName(e.getName()+"accept");
        }
    }
    @Override
    public Consumer<Engineer> andThen(Consumer<? super Engineer> after) {
        return (Engineer t) -> {
            t.setName(t.getName()+"andThen");
            //此处的 accept 相当于是直接方法调用
            after.accept(t);
        };
    }
};
Stream<Engineer> engineerStream = Stream.of(new Engineer().setAge(12).setName("张三").setSalary(new BigDecimal("1000")),
    new Engineer().setAge(12).setName("李四").setSalary(new BigDecimal("2000")),
    new Engineer().setAge(12).setName("钱八").setSalary(new BigDecimal("4000")),
    new Engineer());
engineerStream
    // 使用了自定义得andThen
    .peek(engineerConsumer.andThen((Engineer e) -> e.setName(e.getName()+"哈哈哈")))
    .forEach((t) -> System.out.println(t.getName()));
System.out.println("====================================");
// Consumer 接口可以转成 lambda 表达式  (T t) -> {}
Stream.of(new Engineer().setAge(12).setName("张三").setSalary(new BigDecimal("1000")),
    new Engineer().setAge(12).setName("李四").setSalary(new BigDecimal("2000"))).forEach((Engineer t) -> {
    t.setAge(10000);
    System.out.println(t);
});

结果:

张三andThen哈哈哈
李四andThen哈哈哈
钱八andThen哈哈哈
nullandThen哈哈哈
====================================
Engineer(age=10000, name=张三, salary=1000)
Engineer(age=10000, name=李四, salary=2000)

Supplier(提供者)

​ supplier 是一个类似于参数构建的接口,仅有一个 get()方法会返回一个参数。其可以提供一个参数供其他方法调用。即可写作 () -> return T;与之相同的接口还有IntSupplier 、DoubleSupplier 、LongSupplier 、BooleanSupplier;orEleseGet就是一个Supplier参数

@FunctionalInterface
public interface Supplier<T> {
	//抽象接口
    T get();
}

e.g.:

Engineer engineer = null;
Supplier<Engineer> supplier = new Supplier<Engineer>() {
    @Override
    public Engineer get() {
        // 返回一个对象
        return new Engineer().setName("张三").setSalary(new BigDecimal(new Random().nextInt()));
    }
};
engineer = Optional.ofNullable(engineer).orElseGet(supplier);
System.out.println(engineer);

结果:

Engineer(age=null, name=张三, salary=-120016191)

Predicate (谓语;条件判断)

​ Predicate 接口是一个谓词型接口,其实,这个就是一个类似于 bool 类型的条件判断的接口。提供接口test传入一个参数返回一个boolean值。用lambda表达式可以写作(T t) -> return true|false.其内部自身还维护了条件运算符的一些功能及一个hashCode判断的静态方法。

@FunctionalInterface
public interface Predicate<T> {

   // 抽象的校验方法
    boolean test(T t);

    //条件与
    default Predicate<T> and(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) && other.test(t);
    }

		
	//条件否定
	default Predicate<T> negate() {
        return (t) -> !test(t);
    }

    //条件或
    default Predicate<T> or(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) || other.test(t);
    }

    //参数等比
	//不同于以上这个是一个静态方法用以对比对象hashCode
    static <T> Predicate<T> isEqual(Object targetRef) {
        return (null == targetRef)
                ? Objects::isNull
                : object -> targetRef.equals(object);
    }
}

e.g.:

Predicate<Engineer> predicate = new Predicate<Engineer>() {
    @Override
    public boolean test(Engineer engineer) {
        return engineer.getName()!= null && engineer.getName().equals("张三");
    }
};
engineerList.stream().filter(predicate).forEach(System.out::println);
//条件与
System.out.println("========= 条件与 =========");
Predicate<Engineer> andPredicate = predicate.and((t) -> t.getAge() == 40);
engineerList.stream().filter(andPredicate).forEach(System.out::println);
//条件或
System.out.println("========= 条件或 =========");
Predicate<Engineer> orPredicate = predicate.or((t) -> t.getAge() == 40);
engineerList.stream().filter(orPredicate).forEach(System.out::println);
//条件否定
System.out.println("========= 条件否定 =========");
engineerList.stream().filter(predicate.negate()).forEach(System.out::println);
//传参对比
System.out.println("========= 传参对比 =========");
Engineer targetCompareEngineer = new Engineer().setAge(20).setName("钱八").setSalary(new BigDecimal("17000"));
engineerList.stream().filter(Predicate.isEqual(targetCompareEngineer)).forEach(System.out::println);

结果:

Engineer(age=12, name=张三, salary=1000)
========= 条件与 =========
========= 条件或 =========
Engineer(age=12, name=张三, salary=1000)
Engineer(age=40, name=陈七, salary=20000)
========= 条件否定 =========
Engineer(age=14, name=李四, salary=2000)
Engineer(age=20, name=王五, salary=5000)
Engineer(age=18, name=赵六, salary=8000)
Engineer(age=40, name=陈七, salary=20000)
Engineer(age=20, name=钱八, salary=17000)
========= 传参对比 =========
Engineer(age=20, name=钱八, salary=17000)

Function(中转器)

Function<T,R> 接口为一个功能型接口。提供接口apply传入一个参数R转换成参数T。用lambda表达式可以写作(R r)-> return t.

@FunctionalInterface
public interface Function<T, R> {

   //抽象的校验方法
    R apply(T t);

	//前置处理 接受一个方法返回一个参数并把返回参数带入到apply参与处理
    default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
        Objects.requireNonNull(before);
        return (V v) -> apply(before.apply(v));
    }

    //后置处理 接受一个参数返回一个参数将当前的apply的运算结果带入其中参与处理
    default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
        Objects.requireNonNull(after);
        return (T t) -> after.apply(apply(t));
    }

    
	//静态方法返回一个输入和输出一致的Function
    static <T> Function<T, T> identity() {
        return t -> t;
    }
}

e.g.:

Function<Engineer,String > engineerStringFunction = new Function<Engineer,String>(){
    @Override
    public String apply(Engineer e) {
        return e.getName();
    }
};
Stream<String> stringStream = engineerList.stream().map(engineerStringFunction);
stringStream.forEach(System.out::println);
//出入参一致
System.out.println("========= 出入参一致 =========");
Map<BigDecimal, Engineer> collect = engineerList.stream().collect(Collectors.toMap(Engineer::getSalary, Function.identity()));
Map<BigDecimal, String> collect1 = engineerList.stream().collect(Collectors.toMap(Engineer::getSalary, engineerStringFunction));
collect.forEach((k,v) -> System.out.println("使用 identity 时 =>["+k+":"+v+"]"));
collect1.forEach((k,v) -> System.out.println("使用 engineerStringFunction 时 =>["+k+":"+v+"]"));
//处理前置组成  compose 前置处理
System.out.println("========= 处理前置组成 =========");
Stream<String> stringStream1 = engineerList.stream().map(engineerStringFunction.compose((e) -> e.setName(e.getName() + "-compose")));
stringStream1.forEach(System.out::println);
//处理后置组成
System.out.println("========= 处理后置组成 =========");
Stream<String> stringStream2 = engineerList.stream().map(engineerStringFunction.andThen((e) -> e + "-andThen"));
stringStream2.forEach(System.out::println);

结果:

张三
李四
王五
赵六
陈七
钱八
========= 出入参一致 =========
使用 identity 时 =>[17000:Engineer(age=20, name=钱八, salary=17000)]
使用 identity 时 =>[2000:Engineer(age=14, name=李四, salary=2000)]
使用 identity 时 =>[8000:Engineer(age=18, name=赵六, salary=8000)]
使用 identity 时 =>[1000:Engineer(age=12, name=张三, salary=1000)]
使用 identity 时 =>[20000:Engineer(age=40, name=陈七, salary=20000)]
使用 identity 时 =>[5000:Engineer(age=20, name=王五, salary=5000)]
使用 engineerStringFunction 时 =>[17000:钱八]
使用 engineerStringFunction 时 =>[2000:李四]
使用 engineerStringFunction 时 =>[8000:赵六]
使用 engineerStringFunction 时 =>[1000:张三]
使用 engineerStringFunction 时 =>[20000:陈七]
使用 engineerStringFunction 时 =>[5000:王五]
========= 处理前置组成 =========
张三-compose
李四-compose
王五-compose
赵六-compose
陈七-compose
钱八-compose
========= 处理后置组成 =========
张三-compose-andThen
李四-compose-andThen
王五-compose-andThen
赵六-compose-andThen
陈七-compose-andThen
钱八-compose-andThen

Stream

流 -Stream

构造方法

list.stream();//通过list获得
Stream.of(T t...); // 通过Stream.of 获得与 Arrays.asList() 累死
Stream.if(T[]);//通过Stream.of 数组获得

相当于迭代器,其不可逆,串行执行。后面可以接多个 Intermediate (中间)操作、Terminal (终端)及short-circuiting操作。stream操作后的元素其本体也会跟着变化。后文会对每个各个操作进行解释。其操作都以 lambda 表达式呈现。

各种操作的列表如下:

  1. Intermediate(中间):
操作 含义
map (mapToInt, flatMap 等) 对象属性刷选
filter 条件过滤
distinct 去重
sorted;Comparator;sort 排序
peek 循环处理元素
limit 获取前n个元素
skip 删除前n个元素
parallel stream转为并行流
sequential stream转为串行流
unordered 将流无序化,
用于对顺序无要求的Stream
例如并行流其可以提升性能
  1. Terminal(中间):
操作 含义
forEach 循环处理元素
forEachOrdered 有序循环处理元素
toArray 流转为数组
reduce 逻辑计算返回一个对象
collect 集合操作
min 获得最小
max 获得最大
count 获得条数
anyMatch 只要有一个满足则返回true
allMatch 全部满足则返回true
noneMatch 全部不满足则返回true
findFirst 获得流的第一个元素
findAny 获得流的任意一元素
iterator 返回流的迭代器
  1. Short-circuiting:
操作 含义
anyMatch
noneMatch
findAny
allMatch
findFirst
limit

注意:
Stream不具有复用性,使用一次下次若再次使用会报错stream has already been operated upon or closed

​ Strem中 如果没有Terminal 语句Intermediate 语句将不会运行,没有终端去输出,过程将不会运行

并行处理流 -parallelStream

构造方法

List.parallelStream();//通过List获得
Stream.of(T t...).parallel();//将Stream转为并行流

可以做到将一个St’re’a’m转为并行的多个stream流,其开辟线程数默认和CPU 核数一致。其默认通过JDK1.7的ForJoinPool来实现的多线程任务。

System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism","12")可以做到修改其线程数,不推荐修改。

e.g.:

System.out.println("the list size is ["+engineers.size()+"]");
long beginTime = System.currentTimeMillis();
engineers.parallelStream().forEach(engineer -> engineer.setAge(20));
long endTime = System.currentTimeMillis();
System.out.println("the stream run time is ["+(endTime-beginTime)+"]");
System.out.println("******************");
engineers.parallelStream().forEach(engineer -> System.out.println(engineer));

//为了更好的体现结果将 enginner.setAge 的运行每次都等待1秒
 public void setAge(Integer age) {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        this.age = age;
}

运行结果:

the list size is [9] //集合长度为 9
the stream run time is [3082] //运行时长≈ 3秒  如果是全为串行执行此结果因 ≈ 9秒
****************** //观察下述结果发现age已全部被更改
Engineer{name='虚竹', age=20, salary=6574}
Engineer{name='乔峰', age=20, salary=7600}
Engineer{name='虚竹', age=20, salary=9327}
Engineer{name='张三', age=20, salary=2057}
Engineer{name='赵六', age=20, salary=2754}
Engineer{name='李四', age=20, salary=5907}
Engineer{name='王五', age=20, salary=2863}

注意:

  1. 在使用Stream.parallel()得到并行流以后。其两者本质还是使用的同一个流,如果本体被使用复制体也将会收到影响。

Intermediate 组


Map;mapToInt;mapToDouble;…

其可以对Stream进行数据的刷选映射到另一个Strem对象上去(新对象为新创建),新的Stream对象的类型与提取值得类型有关。其内置了Int、Double和Long三个Map。

用法

//通过 lambda去提取值,如果对提取值有更多处理可用此方式
Stream stream1 = stream.mapToInt(engineers -> engineers.getAge()); 
//通过 Function 函数去获取参数值。
Stream stream2 = stream.mapToInt(Engineer::getAge);

e.g.:

Stream<Engineer> stream = engineers.parallelStream();
IntStream intStream = stream.mapToInt(engineers -> engineers.getAge());
intStream.forEach(e -> System.out.println(e));

运行结果:

the age is =>20
the age is =>18
the age is =>15
the age is =>14

map函数也可以用于 Optional.但是两者用法不一样;其用于对对象中的某个参数进行校验。返回的为这个对象的参数的Optional 如下:

注意: Optional的map是对整个引入的对象做的判断

Optional Optin = Optional.ofNullable(engineer)
	.map(enginnerTest -> enginnerTest.getAget());
Integer integer1 = Optin.orElseGet(() -> 10000);

e.g.:

// -------获取enginner 的 age 如果为空则设置值为100
Engineer engineer = engineers.get(0);
Optional<Integer> integer = Optional.ofNullable(engineer).map(enginnerTest -> {
		System.out.println("the age original is =>"+enginnerTest);
        //故意设置为Null
		return null;
	});
Integer integer1 = integer.orElseGet(() -> 100);//如果optional为空则采用orElseGet中的值
System.out.println("the age last is =>"+integer1);

运行结果:

the age original is =>Engineer{name='张三', age=12, salary=6206}
the age last is =>100

filter

其可以对Stream中的对象进行条件过滤,输出过滤后的结果

用法

Stream<T> stream = = stream.filter(Predicate<T>); //传入一个Predicate 函数 其会要求返回一个boolean值
Stream<T> stream = = stream.filter(engineer -> engineer.getAge() >= 18);//直接使用lambda进行

Predicate源码

@FunctionalInterface
public interface Predicate<T> {
    boolean test(T t);
}

e.g.:

// ------- 获取age 大于等于18的 对象
Stream<Engineer> stream = engineers.stream(); //获得stream流
//过滤enginner取出age大于等于18的转为stream流
Stream<Engineer> engineerStream = stream.filter(engineer -> engineer.getAge() >= 18);
//循环输出
engineerStream.forEach(engineer -> System.out.println(engineer));

运行结果:

Engineer{name='陈七', age=18, salary=2244}
Engineer{name='段誉', age=20, salary=7386}
Engineer{name='虚竹', age=21, salary=5648}

distinct

数据去重,与mysql的DISTINCT() 函数等意。其会根据hashCode 进行去重和Set类似

用法:

Stream<T> distinctStream = Stream.distinct();

e.g.:

//将integer去重
Stream<Integer> intStream = Stream.of(1, 2, 3, 4, 5, 6, 7, 7, 7, 7, 8, 9, 10).parallel();
Stream<Integer> distinct = intStream.distinct();
distinct.forEach(t -> System.out.println("result =>"+t));

运行结果:

result =>7
result =>6
result =>2
result =>3
result =>1
result =>8
result =>4
result =>9
result =>10
result =>5

sorted;Comparator;sort;

数据排序,其会根据 java.util.Comparator 进行排序,也可以自行重写排序规则。Comparator 接口为一个函数式接口,可以使用lambda表达式。sortsorted 的区别在于 sort用于集合 list.sort(...)sorted 用于流stream.

用法:

Stream<Engineer> sorted = stream.sorted((e1,e2) -> Comparator<T>);//要求Comparator 返回一个Integer
list.sort(Comparator<T>);
objects.sort(Comparator.comparing(T::getXX()));//根据对象 T 的xx 属性来排序
objects.sort(Comparator.comparing(T::getXX()).reversed());//根据对象 T 的xx 属性来排序然后取反

注意: stored因涉及多参数的比较,故不要使用并行流 ParallelStream来进行操作。

Comparator 可以使用 reversed()来取反。

Comparator函数源码如下:

@FunctionalInterface
public interface Comparator<T> {
	int compare(T o1, T o2);
}

e.g.:

ArrayList<Engineer> objects = Lists.newArrayList();
objects.add(new Engineer().setName("段誉").setAge(20).setSalary(4581L));
objects.add(new Engineer().setName("王五").setAge(14).setSalary(4481L));
objects.add(new Engineer().setName("陈六").setAge(30).setSalary(5581L));
objects.add(new Engineer().setName("虚竹").setAge(18).setSalary(9581L));
objects.sort(Comparator.comparing(Engineer::getAge));
System.out.println("age升序:"+objects);
 objects.sort(Comparator.comparing(Engineer::getAge).reversed());
System.out.println("age降序:"+objects);

运行结果:

age升序:[
AutoGenerate.Engineer(name=王五, age=14, salary=4481),
AutoGenerate.Engineer(name=虚竹, age=18, salary=9581), 
AutoGenerate.Engineer(name=段誉, age=20, salary=4581), 
AutoGenerate.Engineer(name=陈六, age=30, salary=5581)
]
age降序:[
AutoGenerate.Engineer(name=陈六, age=30, salary=5581), 
AutoGenerate.Engineer(name=段誉, age=20, salary=4581), 
AutoGenerate.Engineer(name=虚竹, age=18, salary=9581), 
AutoGenerate.Engineer(name=王五, age=14, salary=4481)
]

peek

循环处理元素与ForEach类似,区别是ForEach操作是属于Terminal操作,元素将会被消费,其后无法进行任何元素的逻辑。

用法

stream.peek(e -> {});
stream.peek(e -> peek(Consumer<T> action)); //接一个Consumer表达式

e.g.:

Stream<Engineer> stream = engineers.stream();
Stream<Engineer> peek =stream.sorted((e1, e2) -> (e1.getAge() - e2.getAge()))
    .peek(e -> {
        System.out.println("peek -->" + e);
        e.setAge(1000); //测试 peek 对象循环修改会真实修改对象
    }); //有返回值 Stream
Integer ageSum = peek.map(Engineer::getAge).reduce(Integer::sum).get(); //消费了 stream
System.out.println("ageSum -->"+ageSum);
try {
    stream.forEach(e -> System.out.println(e)); //此处会报错因为stream已被消费再次使用会出现错误
} catch (Exception e) {
    e.printStackTrace();
}
engineers.stream().forEach(e -> System.out.println("forEach -->"+e)); //无返回值

返回结果:

peek -->Engineer{name='张三', age=12, salary=4863}
peek -->Engineer{name='李四', age=14, salary=6538}
peek -->Engineer{name='王五', age=15, salary=7757}
peek -->Engineer{name='赵六', age=17, salary=406}
ageSum -->4000
java.lang.IllegalStateException: stream has already been operated upon or closed
.
. 缩减篇幅
.
ntellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
	at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
forEach -->Engineer{name='张三', age=1000, salary=4863}
forEach -->Engineer{name='李四', age=1000, salary=6538}
forEach -->Engineer{name='王五', age=1000, salary=7757}
forEach -->Engineer{name='赵六', age=1000, salary=406}

limit | skip

limt 获得前面指定个数元素,skip 删除前面指定个数元素

用法:

stream.limit(Num);//获得0-num个元素
stream.skip(Num);//删除0-num个元素

注意: limit或skip不可小于0,否则会抛出异常IllegalArgumentException

e.g.:

Stream<Engineer> engineerStream = engineers.stream();
engineerStream.sorted((e1,e2) -> e1.getAge() -e2.getAge())
        .forEach(e -> System.out.println(e));
System.out.println("*****************************");
engineerStream = engineers.stream();
engineerStream.sorted((e1,e2) -> e1.getAge() -e2.getAge())
        .limit(3).forEach(e -> System.out.println(e));//获得前面4个元素
System.out.println("*****************************");
engineerStream = engineers.stream();
engineerStream.sorted((e1,e2) -> e1.getAge() -e2.getAge())
        .skip(3).forEach(e -> System.out.println(e));//扔掉前面4个元素

返回结果:

Engineer{name='张三', age=12, salary=4013}
Engineer{name='李四', age=14, salary=1152}
Engineer{name='王五', age=15, salary=4836}
Engineer{name='赵六', age=17, salary=835}
*****************************
Engineer{name='张三', age=12, salary=4013}
Engineer{name='李四', age=14, salary=1152}
Engineer{name='王五', age=15, salary=4836}
*****************************
Engineer{name='赵六', age=17, salary=835}

Terminal 组


forEachOrdered

有序遍历,对并行流parallelStream 依然有效

e.g.:

Stream<Engineer> engineerStream = engineers.parallelStream();
engineerStream.sorted((e1, e2) -> e1.getAge() - e2.getAge())        
			  .peek(engineer -> System.out.println("peek ->"+engineer))
              .forEachOrdered(System.out::println);

输出结果:

peek ->Engineer{name='李四', age=14, salary=4729}
Engineer{name='李四', age=14, salary=4729}
peek ->Engineer{name='王五', age=15, salary=586}
Engineer{name='王五', age=15, salary=586}
peek ->Engineer{name='赵六', age=17, salary=7339}
peek ->Engineer{name='张三', age=21, salary=1555}
Engineer{name='赵六', age=17, salary=7339}
Engineer{name='张三', age=21, salary=1555}

toArray

将Stream输出成数组

用法

Stream.toArray(T::new);//T::new 等同于  new T()

e.g.:

Stream<Engineer> stream = engineers.stream();
Engineer[] engineers = stream.peek(engineer -> engineer.setAge(200)).toArray(Engineer[]::new);
for (Engineer engineer : engineers) {
     System.out.println(engineer);
}

返回结果:

Engineer{name='张三', age=200, salary=7416}
Engineer{name='李四', age=200, salary=491}
Engineer{name='王五', age=200, salary=3507}
Engineer{name='赵六', age=200, salary=5509}

reduce

计算汇总,可以对流进行数据的计算逻辑从而得到一个结果

用法:

sequential(串型)流中

/**
取出流中的头两个元素然后通过后述的lambda表达式,算出记为 新的t1,紧接着取出流中的第三个元素记为t2。最终将值返回,含义如下:
stream 			-> v1,v2,v3,v4,v...
第一步运行 reduce->  v1(t1),v2(t2) 算出等于vTemp
第二步运行 reduce->  vTemp(t1),v3(t2) 算出等于vTemp
第三步运算 reduce->  vTemp(t1),v4(t2) 算出等于vTemp
.
.
.
**/
Optional opt = seqStream.reduce((t1,t2) -> { return T});//返回值为opt,可以使用.orElseGet(() -> lambda)判断后获得结果

//---------------------------------------------------------------------------------
/**
取出startT 和流的第一个元素通过后述的lambda表达式,算出记为 新的t1,紧接着取出流中的第二个元素记为t2。最终将值返回,含义如下:
stream 			-> v1,v2,v3,v4,v...
第一步运行 reduce->  startT(t1),v1(t2) 算出等于vTemp
第二步运行 reduce->  vTemp(t1),v2(t2) 算出等于vTemp
第三步运算 reduce->  vTemp(t1),v3(t2) 算出等于vTemp
**/
T t = seqStream.reduce(startT,(t1,t2) -> {return T}); //返回值为 T

parallel(并型)流中

/**
取出流中的两个元素然后通过后述的lambda表达式,算出记为结果r1,同时另一条线程获得流中的另外两个元素通过计算得r2,最后将所有得结果进行递归合并得r1+r2+...(注意:此处不可单纯认为是r1+r2..,其类似于JDK1.7得Fork/join 模式将任务分给多个线程去运行然后各个线程内部合并运算后最终外部再进行合并运算),含义如下
原有元素: 		 ->v1,v2,v3,v4,v...
stream--Thread1 	-> v1,v2,...
stream--Thread2 	-> v3,v5,...
stream--Thread3 	-> v4,v5,...
... more 

第一步运行 Thread1 - reduce ->  v1(t1),v2(t2) 算出等于r1
	同时  Thread2 - reduce ->  v3(t1),v5(t2) 算出等于r2
	...more
第二步运行 Thread1 - reduce ->  v18(t1),r1(t2) 算出等于r1 (此处得v18为假设)
	同时  Thread2 - reduce ->  v9(t1),r2(t2)  算出等于r2 (此处得v5为假设)
	...more
.
.
.
第n步运算  reduce->  r1(t1),r2(t2) 算出等于 result
**/
Optional opt = parStream.reduce((t1,t2) -> { return T});//返回值为opt,可以使用.orElseGet(() -> lambda)判断后获得结果


//---------------------------------------------------------------------------------
/**
取出流中的1个元素然后与startT通过后述的lambda表达式,算出记为结果r1,同时另一条线程获得流中的另外1个元素与startT通过计算得r2,后多条线程又去流中各自获取一个元素与startT进行运算得出结果r3,r4,r5...,最后将所有得结果进行递归合并得r1+r2+...(注意:此处不可单纯认为是r1+r2..,其类似于JDK1.7得Fork/join 模式将任务分给多个线程去运行然后各个线程内部合并运算后最终外部再进行合并运算),含义如下
原有元素: 		 ->v1,v2,v3,v4,v...
stream--Thread1 	-> v1,v2,...
stream--Thread2 	-> v3,v5,...
stream--Thread3 	-> v4,v5,...
... more 

第一步运行 Thread1 - reduce ->  startT(t1),v2(t2) 算出等于threadResult1[0] = r1
	同时  Thread2 - reduce ->  startT(t1),v3(t2) 算出等于threadResult2[0] = r2
	...more
第二步运行 Thread1 - reduce ->  startT(t1),v18(t2) 算出等于threadResult1[1] = r18
	同时  Thread2 - reduce ->  startT(t1),v5(t2)  算出等于threadResult2[1] = r5
	...more
.
.
.
第n步运算  reduce->  算出等于threadResult1[0]+hreadResult1[1]+...+hreadResult2[0]+hreadResult2[1]... 算出等于 result
**/
T t = parStream.reduce(startT,(t1,t2) -> {return T});//返回值为 T

区别: 并行流时,起始数将会被计算 stream的长度次。而在串行时其只会被计算一次。由上述过程也可得知,在处理逻辑复杂并涉及到其他元素的结果时请慎重考虑使用并行计算。

上述的(t1,t2) -> {return T} 为 BinaryOperator lambda函数,源码如下:

@FunctionalInterface
public interface BinaryOperator<T> extends BiFunction<T,T,T>  {
    /**
     * 从中可以看到其返回值需要和表达式的值一致,传入内容为一个  lambda函数
     */
    public static <T> BinaryOperator<T> minBy(Comparator<? super T> comparator) {
        Objects.requireNonNull(comparator);
        return (a, b) -> comparator.compare(a, b) <= 0 ? a : b;
    }
}

//Comparator表达式
@FunctionalInterface
public interface Comparator<T> {
    int compare(T o1, T o2);
}

 基本类型可使用的函数列表

函数 含义
Number::min 最小
Number::max 最大
Number::sum 求和
String::concat 字符串拼接

串行和并行的效果测试:

e.g.:

 System.out.println("***********************************");
 Stream<Integer> stream = Stream.of(1, 3, 5, 7, 9).sequential();
 Integer sum = stream.reduce((t1, t2) -> {
     System.out.println(t1 + "<=>" + t2);
     return t1 + t2;
 }).orElseGet(() -> Integer.MAX_VALUE); //串行时求和
 System.out.println("求和 (sequential-lambda) ==>" + sum);
 System.out.println("***********************************");
 stream = Stream.of(1, 3, 5, 7, 9).parallel();
 sum = stream.reduce((t1, t2) -> {
     System.out.println(t1 + "<=>" + t2);
     return t1 + t2;
 }).orElseGet(() -> Integer.MAX_VALUE); //并行时求和
 System.out.println("求和 (parallel-lambda) ==>" + sum);
 System.out.println("***********************************");
 stream = Stream.of(1, 3, 5, 7, 9).sequential();
 sum = stream.reduce(5, (t1, t2) -> {
     System.out.println(t1 + "<=>" + t2);
     return t1 + t2;
 });//有起始数,并行时求和
 System.out.println("求和 begin+5(sequential-lambda) ==>" + sum);
 System.out.println("***********************************");
 stream = Stream.of(1, 3, 5, 7, 9).parallel();
 sum = stream.reduce(5, (t1, t2) -> {
     System.out.println(t1 + "<=>" + t2);
     return t1 + t2;
 });//有起始数,串行时求和
 System.out.println("求和 begin+5(parallel-lambda) ==>" + sum);

返回结果:

***********************************
1<=>3
4<=>5
9<=>7
16<=>9
求和 (sequential-lambda) ==>25
***********************************
7<=>9
5<=>16
1<=>3
4<=>21
求和 (parallel-lambda) ==>25
***********************************
5<=>1
6<=>3
9<=>5
14<=>7
21<=>9
求和 begin+5(sequential-lambda) ==>30
***********************************
5<=>5
5<=>7
5<=>3
5<=>9
5<=>1
6<=>8
12<=>14
10<=>26
14<=>36
求和 begin+5(parallel-lambda) ==>50

内置函数:

e.g.:

Double[] doubles = new Double[]{1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0};
Integer[] integers = new Integer[]{1, 2, 3, 4, 5, 6, 7, 8, 9};
Stream<Double> stream = Stream.of(doubles).parallel();
Double min = stream.reduce(Double.MAX_VALUE, Double::min);
System.out.println("最小值 ===>" + min);
stream = Stream.of(doubles).parallel();
Double max = stream.reduce(Double.MIN_VALUE, Double::max);
System.out.println("最大值 ===>" + max);
Stream<Integer> streamInteger = Stream.of(integers).parallel();
Integer sum = streamInteger.reduce(10, Integer::sum);
System.out.println("求和 ===>" + sum);
Stream<String> streamStr = Stream.of("a", "b", "c", "d").parallel();
String concatStr = streamStr.reduce("BEGIN-", String::concat);
System.out.println("字符串拼接 ==>" + concatStr);

返回结果:

最小值 ===>1.0
最大值 ===>9.0
求和 ===>135
字符串拼接 ==>BEGIN-aBEGIN-bBEGIN-cBEGIN-d

collect

stream转成集合

用法

stream.collect(Collectors c);//内部可以接 java.util.stream.Collectors 中的方法

已知方法列表:

函数 含义
toList stream转List集合
toSet() stream转Set集合
toSet stream转Set集合
toMap stream转Map集合
joining 分隔符拼接
maxBy 获取最大值
minBy 获取最小值
summing 获取特殊值(均值、最大值、最小值…)
averaging 获取平均值
counting 获取长度
groupBy 指定key进行分组
partitioningBy 根据true|false进行分组
mapping 指定key转为Map
reducing 数据汇总
collectingAndThen 操作后接着怎么做

toList

e.g.:

 List<Engineer> collectList = enginnerList.stream().collect(Collectors.toList());
 System.out.println("流转[List]集合(toList)==>"+ JSON.toJSONString(collectList));

console:

流转[List]集合(toList)==>[{"age":50,"name":"张三","salary":50000.00},
{"age":22,"name":"李四","salary":4900.00},
{"age":43,"name":"王五","salary":8000.00},
{"age":18,"name":"赵六","salary":6000.00},
{"age":36,"name":"陈七","salary":14000.00}]

toSet

e.g.:

System.out.println("流转[Set]集合(toSet)==>"+ JSON.toJSONString(enginnerList.stream().collect(Collectors.toSet())));
System.out.println("=== 去重转Set ===");
//此处的set去重用到了Comparator.comparing() 方法
TreeSet<Engineer> collect = enginnerList.stream().collect(Collectors.toCollection(() -> Sets.newTreeSet(Comparator.comparing(Engineer::getAge))));
System.out.println("流转[Set]集合去重(toCollection)==>"+ JSON.toJSONString(collect));

输出:

流转[Set]集合(toSet)==>[
{"age":43,"name":"王五","salary":8000.00},
{"age":50,"name":"张三","salary":50000.00},
{"age":22,"name":"陈七","salary":14000.00},
{"age":22,"name":"李四","salary":4900.00},
{"age":18,"name":"赵六","salary":6000.00}]
=== 去重转Set ===
流转[Set]集合去重(toCollection)==>[
{"age":18,"name":"赵六","salary":6000.00},
{"age":22,"name":"李四","salary":4900.00},
{"age":43,"name":"王五","salary":8000.00},
{"age":50,"name":"张三","salary":50000.00}]

e.g.:

System.out.println("**************************");
Stream<Engineer> stream = engineers.stream();
Set<Engineer> collectSet = stream.collect(Collectors.toSet());
System.out.println("流转[Set]集合==>"+collectSet);
System.out.println("**************************");
stream = engineers.stream();
List<Engineer> collectList = stream.collect(Collectors.toList());
System.out.println("流转[List]集合==>"+collectList);
System.out.println("**************************");
stream = engineers.stream();
// 根据name取map只取一个,如果此处v会有多个会报错
Map<String, Engineer> collect6 = stream.collect(Collectors.toMap(Engineer::getName, Function.identity()));
System.out.println("流转[Map]集合根据key:name ==>"+collect6);
System.out.println("**************************");
stream = engineers.stream();
String collect7 = stream.map(Engineer::getName).collect(Collectors.joining("&"));
System.out.println("使用[Joining]进行拼接 ==>"+collect7);
System.out.println("***********************");
stream = engineers.stream();
Optional<Engineer> collect8 = stream.collect(Collectors.maxBy((e1, e2) -> e1.getAge() - e2.getAge()));
System.out.println("使用[maxBy]进行拼接 按照[age]取大 ==>"+collect8.get());
System.out.println("***********************");
stream = engineers.stream();
collect8 = stream.collect(Collectors.minBy((e1, e2) -> e1.getAge() - e2.getAge()));
System.out.println("使用[minBy]进行拼接,按照[age]取小 ==>"+collect8.get());
System.out.println("***********************");
stream = engineers.stream();
IntSummaryStatistics collect9 = stream.collect(Collectors.summarizingInt(Engineer::getAge));
System.out.println("使用[summarizing]进行[min]取小 ==>"+collect9.getMin());
System.out.println("使用[summarizing]进行[max]取小 ==>"+collect9.getMax());
System.out.println("使用[summarizing]进行[count]取条数 ==>"+collect9.getCount());
System.out.println("使用[summarizing]进行[average]取平均 ==>"+collect9.getAverage());
System.out.println("使用[summarizing]进行[sum]取和 ==>"+collect9.getSum());
System.out.println("***********************");
stream = engineers.stream();
Double collect10 = stream.collect(Collectors.averagingDouble((e1) -> e1.getSalary().doubleValue()));
System.out.println("使用[averaging]进行[salary]的均值 ==>"+collect10);
System.out.println("***********************");
stream = engineers.stream();
Long collect = stream.collect(Collectors.counting());
System.out.println("使用[counting]获得[stream]长度 ==>"+collect);
System.out.println("***********************");
stream = engineers.stream();
Map<Integer, List<Engineer>> collect1 = stream.collect(Collectors.groupingBy(Engineer::getAge));
collect1.forEach((k,v) -> System.out.println("使用[groupBy]根据[age]进行元素分组 ==>"+k+"<===>"+v));
System.out.println("***********************");
stream = engineers.stream();
//groupingBy 分组统计人名
Map<Integer, Set<String>> collect5 = stream.collect(Collectors.groupingBy(Engineer::getAge,
        Collectors.mapping(Engineer::getName, Collectors.toSet())));
collect5.forEach((k,v) -> System.out.println("使用[groupBy]根据[age]分组,value为每组Set<人名> ==>"+k+"<===>"+v));
System.out.println("***********************");
stream = engineers.stream();
Map<Boolean, List<Engineer>> collect11 = stream.collect(Collectors.partitioningBy(e -> e.getSalary().doubleValue() >= 3000));
collect11.forEach((k,v) -> System.out.println("使用[partitioningBy]根据[Salary>= 3000]进行元素分组 ==>"+k+"<===>"+v));
System.out.println("***********************");
stream = engineers.stream();
Map<Boolean, List<String>> collect2 = stream.collect(Collectors.partitioningBy(engineers -> engineers.getAge() >= 18,
        Collectors.mapping(Engineer::getName, Collectors.toList())));
collect2.forEach((k,v) -> System.out.println("使用[partitioningBy]根据[age>= 18]分两组,value每组Set<人名> ==>"+k+"<===>"+v)); //只有两组 true false
System.out.println("*************************");
stream = engineers.stream();
//Collectors.mapping(v1,v2);v1取出来的数据会按照v2指定的格式进行返回
Set<Integer> collect4 = stream.collect(Collectors.mapping(Engineer::getAge, Collectors.toSet()));
System.out.println("使用[mapping]进行指定对象元素,按照指定规定返回 ==>"+collect4);
System.out.println("*************************");
stream = engineers.stream();
Integer collect3 = stream.map(Engineer::getAge).collect(
        Collectors.reducing(1000, (e1, e2) -> {
            //其规则和reducing中类似,将identity带入到首次里面,然后参与后文的计算
            System.out.println(e1 +"<===>"+ e2);
            return e1 - e2;
        }));
System.out.println("使用[reducing]进行在[identity=0]的前提下=>"+collect3);
System.out.println("*************************");
stream = engineers.stream();
Integer integer = stream.map(Engineer::getAge).collect(
        Collectors.reducing((e1, e2) -> {
            //如果不加 identity 首次的e1 和 e2 分别位第一个元素和第二个元素
            System.out.println(e1 + "<===>" + e2);
            return e1 + e2;
        })).get();
System.out.println("使用[reducing]进行 ==>"+integer);
System.out.println("*************************");
stream = engineers.stream();
integer = stream.map(Engineer::getAge).collect(
        Collectors.reducing(0,e -> e+10,(e1, e2) -> {
            //加上identity和第二个元素mapper 后面的运算将会是在取出之前的基础上先去运行 mapper等式
            System.out.println(e1 + "<===>" + e2);
            return e1 + e2;
        }));
System.out.println("使用[reducing]进行在[identity=0,mapper=(e+10)]的前提下=>"+integer);
// collectingAndThen 的含义是将 前者的集带入到后者去计算
stream = engineers.stream();
List<String> collect12 = stream.collect(Collectors.collectingAndThen(
        Collectors.groupingBy(Engineer::getAge),
        /**
        groupBy 导致结果变成 —> Map<age:List<Enginner>>
        values取出的结果变成List<List<Enginner>> 使用flatMap变为多个Stream List<Enginner>
         **/
        e -> e.values().stream().flatMap(List::stream).map(Engineer::getName).collect(Collectors.toList())
));
System.out.println("使用[collectingAndThen]进行==>"+collect12);

返回结果:

流转[Set]集合==>[Engineer{name='王五', age=15, salary=3000}, Engineer{name='李四', age=14, salary=5000}, Engineer{name='张三', age=14, salary=4000}, Engineer{name='赵六', age=20, salary=20000}]
**************************
流转[List]集合==>[Engineer{name='李四', age=14, salary=5000}, Engineer{name='张三', age=14, salary=4000}, Engineer{name='王五', age=15, salary=3000}, Engineer{name='赵六', age=20, salary=20000}]
**************************
流转[Map]集合根据key:name ==>{李四=Engineer{name='李四', age=14, salary=5000}, 张三=Engineer{name='张三', age=14, salary=4000}, 王五=Engineer{name='王五', age=15, salary=3000}, 赵六=Engineer{name='赵六', age=20, salary=20000}}
**************************
使用[Joining]进行拼接 ==>李四&张三&王五&赵六
***********************
使用[maxBy]进行拼接 按照[age]取大 ==>Engineer{name='赵六', age=20, salary=20000}
***********************
使用[minBy]进行拼接,按照[age]取小 ==>Engineer{name='李四', age=14, salary=5000}
***********************
使用[summarizing]进行[min]取小 ==>14
使用[summarizing]进行[max]取小 ==>20
使用[summarizing]进行[count]取条数 ==>4
使用[summarizing]进行[average]取平均 ==>15.75
使用[summarizing]进行[sum]取和 ==>63
***********************
使用[averaging]进行[salary]的均值 ==>8000.0
***********************
使用[counting]获得[stream]长度 ==>4
***********************
使用[groupBy]根据[age]进行元素分组 ==>20<===>[Engineer{name='赵六', age=20, salary=20000}]
使用[groupBy]根据[age]进行元素分组 ==>14<===>[Engineer{name='李四', age=14, salary=5000}, Engineer{name='张三', age=14, salary=4000}]
使用[groupBy]根据[age]进行元素分组 ==>15<===>[Engineer{name='王五', age=15, salary=3000}]
***********************
使用[groupBy]根据[age]分组,value为每组Set<人名> ==>20<===>[赵六]
使用[groupBy]根据[age]分组,value为每组Set<人名> ==>14<===>[李四, 张三]
使用[groupBy]根据[age]分组,value为每组Set<人名> ==>15<===>[王五]
***********************
使用[partitioningBy]根据[Salary>= 3000]进行元素分组 ==>false<===>[]
使用[partitioningBy]根据[Salary>= 3000]进行元素分组 ==>true<===>[Engineer{name='李四', age=14, salary=5000}, Engineer{name='张三', age=14, salary=4000}, Engineer{name='王五', age=15, salary=3000}, Engineer{name='赵六', age=20, salary=20000}]
***********************
使用[partitioningBy]根据[age>= 18]分两组,value每组Set<人名> ==>false<===>[李四, 张三, 王五]
使用[partitioningBy]根据[age>= 18]分两组,value每组Set<人名> ==>true<===>[赵六]
*************************
使用[mapping]进行指定对象元素,按照指定规定返回 ==>[20, 14, 15]
*************************
1000<===>14
986<===>14
972<===>15
957<===>20
使用[reducing]进行在[identity=0]的前提下=>937
*************************
14<===>14
28<===>15
43<===>20
使用[reducing]进行 ==>63
*************************
0<===>24
24<===>24
48<===>25
73<===>30
使用[reducing]进行在[identity=0,mapper=(e+10)]的前提下=>103
使用[collectingAndThen]进行==>[赵六, 李四, 张三, 王五]

min | max

用法:

Optional opt = stream.min((v1,v2) -> return Integer);
Optional opt = stream.max((v1,v2) -> return Integer);

e.g.:

Stream 中只要有一个元素符合传入的 predicate,返回 trueEngineer engineerMin = engineers.stream().min((e1, e2) -> e1.getAge() - e2.getAge()).get();
System.out.println("[min]获得最小 ==>"+engineerMin);
Engineer engineerMax = engineers.stream().max((e1, e2) -> e1.getAge() - e2.getAge()).get();
System.out.println("[max]获得最大 ==>"+engineerMax);

返回结果:

[min]获得最小 ==>Engineer{name='李四', age=14, salary=5000}
[max]获得最大 ==>Engineer{name='赵六', age=20, salary=20000}

anyMatch

用法:

stream.anyMatch(T t -> {return true|false});

Stream 中只要有一个元素符合传入的 Predicate 表达式,则返回 true

e.g.:

final String engineerName="张三";
boolean b = engineers.stream().anyMatch(engineer ->  engineerName.equals(engineer.getName()));
if (b) {
    System.out.println("["+engineerName+"]在集合中");
}

结果:

[张三]在集合中

allMatch | noneMatch

用法:

stream.allMatch(enginner -> {return true|false});//全为true则返true,否者为false
stream.noneMatch(enginner -> {return true|false});//全为false则返回true,否者为true

e.g.:

Map engineerMap = new HashMap<String,Engineer>(engineers.size());
engineers.forEach(engineer -> engineerMap.put(engineer.getName(),engineer));
Set<String> SetKey =  engineerMap.keySet();
boolean b = engineers.parallelStream().allMatch(engineer -> SetKey.contains(engineer.getName()));
if (b) {
    System.out.println("集合所有元素在新集合中都拥有");
}
//重置map
Set<String> finalSetKey =  new HashMap<String,Engineer>(engineers.size()).keySet();
 b = engineers.parallelStream().noneMatch(engineer -> finalSetKey.contains(engineer.getName()));
if (b) {
    System.out.println("集合所有元素在新集合中都[不]拥有");
}

结果:

集合所有元素在新集合中都拥有
集合所有元素在新集合中都[]拥有

findFirst | findAny

用法:

Optional opt = stream.findFirst();//获得流的第一个元素返回Optional 
Optional opt = stream.findAny();//获得流(并行流会有变化)的任意元素返回Optional 

e.g.:

Optional<Engineer> first = engineers.parallelStream().findFirst();
System.out.println("使用[findFirst] ==>"+first.get());
Optional<Engineer> any = engineers.parallelStream().findAny();
System.out.println("使用[findAny] ==>"+any.get());

结果:

使用[findFirst] ==>Engineer{name='李四', age=14, salary=5000}
使用[findAny] ==>Engineer{name='王五', age=15, salary=3000}

Optional

对象校验的一个包装类,包地址java.util.Optional

ofNullable | of

Optional 参数的创建需要时用 ofNullable 或者of 方法来创建,两者都会返回一个 Optional 对象。其区别是:

ofNullable 在校验对象为空时不会抛错,常使用此方式来创建Optional对象,而 of 会直接返回 NullPointerException 异常

e.g.:

Engineer engineer = null;
Optional<Engineer> engineer1 = Optional.ofNullable(engineer);
Optional<Engineer> engineer2 = Optional.of(engineer);

结果:

java.lang.NullPointerException
	at java.util.Objects.requireNonNull(Objects.java:203)
	at java.util.Optional.<init>(Optional.java:96)
	at java.util.Optional.of(Optional.java:108)
    ...

get

获取Optional的值

e.g.:

Engineer engineer = new Engineer("李四", 14, new BigDecimal("5000"));
Optional<Engineer> engineer1 = Optional.ofNullable(engineer);
System.out.println(engineer1.get());

结果:

Engineer{name='李四', age=14, salary=5000}

ifPresent

如果 Optional 有效则会执行ifPresent 中的方法

optional.ifPresent(T t -> {});//此处的t 是校验对象

e.g.:

Engineer engineer = new Engineer("李四", 14, new BigDecimal("5000"));
Optional.ofNullable(engineer).ifPresent(engineer1 ->  engineer.setAge(20));
System.out.println(engineer);

结果:

Engineer{name='李四', age=20, salary=5000}

orElse

optional 校验对象为空时,其会执行此方法里面的内容,其返回值要与校验对象一致

optional.orElse(return T t);

e.g.:

Engineer engineer = null;
engineer = Optional.ofNullable(engineer).orElse(new Engineer("李四", 14, new BigDecimal("5000")));
System.out.println(engineer);

结果:

Engineer{name='李四', age=14, salary=5000}

orElseGet

optional 校验对象为空时,其会执行此方法里面的内容,其返回值要与校验对象一致.

OrElse 的区别是,orElseGet 接一个lambda表达式,表达式默认不执行只在需要的时候被执行,而 orElse 会注定执行

optional.ofElseGet(Supplier sup);//接Supplier 函数接口

e.g.:

Engineer engineer = null;
engineer = Optional.ofNullable(engineer).orElseGet(() -> new Engineer("张三", 12, new BigDecimal("20.5")));
System.out.println(engineer);

结果:

Engineer{name='张三', age=12, salary=20.5}

orElseThrow

前者没达到得情况下会**抛出错误.

optional.orElseThrow(() -> return Exception);

e.g.:

Engineer engineer = null;
engineer = Optional.ofNullable(engineer)
			.orElseThrow(
				() -> new RuntimeException("报错了哦[空指针]!")
			);
System.out.println(engineer);

结果:

java.lang.RuntimeException: 报错了哦[空指针]!
	at OptionalTest.lambda$test2$1(OptionalTest.java:44)
	at java.util.Optional.orElseThrow(Optional.java:290)

map

filter

过滤器,传入一个 Predicate 函数接口,成功则会成功返回Optional,否者返回一个空的 Optional

Optional opt = optional.filter(e -> {return true|false});

e.g.:

ArrayList statusList = new ArrayList<String>();
statusList = Optional.ofNullable(statusList)
     //返回一个 null的optional
        .filter(statuses -> !(statuses == null || statuses.isEmpty()))
    //因为上文返回的null 的optional 则 orElseGet 会被执行填入参数
        .orElseGet(() -> {
            ArrayList arrayList = new ArrayList();
            arrayList.add("张三");
            arrayList.add("李四");
            return arrayList;
        });
System.out.println(statusList);

结果:

[张三, 李四]
相关标签: jdk1.8