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

JDK1.8 Stream & Optional

程序员文章站 2022-03-03 23:06:49
...

JDK1.8 Stream & Optional

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 排序
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进行数据的刷选映射到另一个Stream对象上去(新对象为新创建),新的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

数据排序,其会根据Compare进行排序。也可以自行重写排序规则

用法:

Stream<Engineer> sorted = stream.storted((e1,e2) -> Comparator<T>);//要求Comparator 返回一个Integer

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

Comparator函数源码如下:

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

e.g.:

Stream<Engineer> stream = engineers.stream();
Stream<Engineer> sorted = stream.sorted((e1, e2) -> {
		return e1.getAge() - e2.getAge();
	});
sorted.forEach(engineer -> System.out.println(engineer));

运行结果:

Engineer{name='段誉', age=20, salary=4581}
Engineer{name='王五', age=15, salary=1210}
Engineer{name='陈七', age=18, salary=3001}
Engineer{name='赵六', age=17, salary=7450}
Engineer{name='虚竹', age=21, salary=6098}
Engineer{name='乔峰', age=23, salary=8972}
Engineer{name='虚竹', age=21, salary=1554}

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

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();
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);

结果:

[张三, 李四]
相关标签: Stream Optional