吾尝终日而思矣,不如须臾之所学以。
这个流是干啥的?
流可以简单理解为,把我们业务中数据过滤,分页,求和,分类汇总等一些类似于mysql中的一些聚合函数功能给封装了一下,在写类似功能的时候直接. stream.grougbying()
,需要干啥就点啥就行了,写的时候比较丝滑,另外还提供了对fork/join
的封装,数据量大的时候直接.stream()
换成,. paraealStream()
就可以了,让CPU都忙起来,这操作我就问你,丝滑不?
这个流有啥特点?
- 只会执行一次(只会循环一次)。
- 结束操作才会执行。
- 不会影响原值。
只会执行一次如何理解呢?
List<Integer> integers = Arrays.asList(1, 2, 3);
long count = integers.stream().filter(x -> {
System.out.println("a");
return x > 1;
}).filter(x ->
{
System.out.println("b");
return x < 3;
}).count();
会打印aaabbb? aaabb?
不对的。会打印aabab
。一个元素只会过一遍,被pass,就下一个元素继续。
第二个惰性加载就是要执行到结束操作才会执行,把上面的例子改一下:
List<Integer> integers = Arrays.asList(1, 2, 3);
Stream<Integer> integerStream = integers.stream().filter(x -> {
System.out.println("a");
return x > 1;
}).filter(x ->
{
System.out.println("b");
return x < 3;
});
少个count()
方法的调用,那么会打印什么的?是啥都不打印。因为没有执行终止操作,只有中间操作,那哪些是中间操作哪些是终止操作呢?后面会说。
第三条不会影响原值就很好理解了,不管经历流的操作,integers
这个list
是不会发生变化的。
流方法分类?
大致是这么分类的,中间操作不会触发执行,结束操作才会。
有无状态可以理解为处理元素是否受前后元素的影响,
sorted()
排序操作肯定是受前后元素影响啊,所以是划分为有状态。短路非短路就类似
java
中的&
和&&
,|
和||
区别。
基于什么实现的?
因为jdk1.8
的函数式接口和lambda
表达式的支持。
有且仅有一个抽象方法的接口一般会有@FunctionalInterface
注解函数式接口可以被隐式转换为lambda
表达式,可以有多个默认方法。
lambda
表达式:
(parameters)->expression
(parameters)->{statements;}
而lambda
又可以简化为方法引用更简洁:ClassName::methodName
- 4大神兽(函数式接口):
Function(有进有出)、Predicate(有进但出来是个boolean)、Consumer(只进不出)、Supplier(之出不进)
optional嵌套用法
// 第一种方式:各种if判断避免了空指针,但是if层级太深,代码冗长
if (user != null) {
Address address = user.getAddress();
if (address != null) {
Country country = address.getCountry();
if (country != null) {
String couName = country.getCountryName();
System.out.println( "第二种方式:" + couName );
}
}
}
// 第二种方式:代码简洁,避免空指针
String counName = Optional.ofNullable( user )
.map( User::getAddress )
.map( Address::getCountry )
.map( Country::getCountryName )
.orElse( "china" );
System.out.println( "第三种方式:" + counName );
// 第三种方式:代码简洁,避免空指针,武林那一步为空都会返回自定义异常
String countryNameEx = Optional.ofNullable( user )
.map( User::getAddress )
.map( Address::getCountry )
.map( Country::getCountryName )
.orElseThrow( () -> new RuntimeException( "countryId is null" ) );
有啥需要注意的?
- 在
lambda
表达式中变量会隐性的添加final
关键字的,所以如果你要重新赋值就会报错:
-
流不能重复消费还不能修改原值,要不运行就抛异常:
- 不能像
for循环
一样直接return
退出方法 - 异常相关,增加了异常堆栈的深度,受检异常还不能委托给方法向上抛出,只能自己在
lambda
中处理:
integers.stream().forEach(x->{
try {
throw new Exception("dfd");
} catch (Exception e) {
e.printStackTrace();
}
});
感觉好用是好用,但是当我一不注意踩到坑的时候。不知道为啥,我就会想到这张图:
参考:
https://www.jianshu.com/p/3d4e76467990
https://www.cnblogs.com/xzy-/p/10915920.html
https://blog.csdn.net/Goodbye_Youth/article/details/106879287
https://www.jianshu.com/p/e81f2f2f68b8
https://www.cnblogs.com/CarpenterLee/p/6637118.html
https://blog.csdn.net/iteye_1287/article/details/82540162?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase
网友评论