JDK1.8 Stream & Optional
文章目录
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
表达式呈现。
各种操作的列表如下:
操作 | 含义 |
---|---|
map (mapToInt, flatMap 等) | 对象属性刷选 |
filter | 条件过滤 |
distinct | 去重 |
sorted | 排序 |
peek | 循环处理元素 |
limit | 获取前n个元素 |
skip | 删除前n个元素 |
parallel | stream转为并行流 |
sequential | stream转为串行流 |
unordered | 将流无序化, 用于对顺序无要求的Stream 例如并行流其可以提升性能 |
操作 | 含义 |
---|---|
forEach | 循环处理元素 |
forEachOrdered | 有序循环处理元素 |
toArray | 流转为数组 |
reduce | 逻辑计算返回一个对象 |
collect | 集合操作 |
min | 获得最小 |
max | 获得最大 |
count | 获得条数 |
anyMatch | 只要有一个满足则返回true |
allMatch | 全部满足则返回true |
noneMatch | 全部不满足则返回true |
findFirst | 获得流的第一个元素 |
findAny | 获得流的任意一元素 |
iterator | 返回流的迭代器 |
- 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}
注意:
- 在使用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);
结果:
[张三, 李四]
上一篇: HashMap源码剖析(Jdk1.8)
下一篇: Excel 删除空白行
推荐阅读
-
php错误提示failed to open stream: HTTP request failed!的完美解决方法
-
java8如何用Stream查List对象某属性是否有重复
-
Java 8 Stream操作类型及peek示例解析
-
利用AdoDb.Stream对象来读取UTF-8格式的文本文件
-
centOS7安装jdk1.8的方法
-
java.io.StreamCorruptedException: invalid stream header: EFBFBDEF
-
Redis入门 - 数据类型:Stream详解
-
java.io.StreamCorruptedException: invalid stream header: EFBFBDEF
-
PHP stream_context_create()函数的使用示例,createfile函数
-
Java自学-I/O Stream流