java1.8的Optional和Stream流的简单运用

问题:为什么要用Optional这个类?

说是解决空指针异常,大致是这个意思,这个问题先留着,先看用法
用法:
Optional name = Optional.of(“”) 创建对象传入的参数不能为null,否则就会报空指针异常

疑问:不是解决空指针异常吗,怎么自己又搞出个空指针?

Optional name = Optional.ofNullable(null) 创建对象传入的值可以为null

创建完之后我们就可以调用对象的相关方法了:
isPresent():
如果值存在就返回true, 不存在就返回false

疑问:这个和 if (name = null) 有啥区别吗?这不是麻烦了吗?

get():
如果里面有值,就返回,否则就抛出NoSuchElementException异常

疑问:是没有空指针异常了,但是又出现个这个异常,就是改下名,该出错还是会出错

ifPresent()
如果里面有值则调用里面的consumer,也就是lambda表达式,否则不做处理
解惑:哦,原来如此,以往我们要处理一个值,如果为空的话就报空指针异常了,但是如果把值放在Optional里,然后要处理的时候,直接调用这个方法,即使为空,就不做任何处理了,但是只能放lambda表达式啊,如果我逻辑复杂,并且需要修改值,怎么办,还有就是不报异常,我上哪找错误

orElse():
如果Optional实例有值则将其返回,否则返回orElse方法传入的参数。

疑惑:这个三元表达式就可以完成,我为什么要用这个方法呢?

orElseGet:
orElseGet与orElse方法类似,区别在于得到的默认值。orElse方法将传入的字符串作为默认值,orElseGet方法可以接受Supplier接口的实现用来生成默认值。

疑惑:不管是用函数引用或者lambda表达式,不都是生成默认值吗,没啥区别啊

orElseThrow:
和上面的一样,但是Supplier接口实现的是指定的异常,就是如果为空,就抛出指定的异常

疑惑:还是抛异常,感觉把空指针异常转换成了各种异常

map() 如果有值,则调用里面的lambda表达式进行更改,否则就返回空的Optional
想法:这个map可以对其进行更改,并且返回Optional,也就是我可以无限串联的执行逻辑

flatMap():
他和map的区别就是,map返回值类型可以是任何类型,但是最后会用Optional封装,
也就是说如果返回值类型是Optional,那么封装完之后就是Optional
但是flatMap必须返回的是Optional类型,没什么封不封装的

filter()
就是传入一个lambda表达式进行过滤,如果满足条件则返回这个Optional,否则返回空Optional

我了解的方法就是这些了

思考

前面的get() 和 isPresent() 方法没啥用,一个没值就抛异常,一个判断是否有值,这跟之前的if(value = null)一样

相比来说: orElse
orElseGet
orElseThrow
虽然三元表达式也可以完成,但是这个起码是个方法,勉强可以接受吧

然后ifPresent 就是存在对他做点什么,但是无法改变传入的值

而map,filter我认为还是很有用处的,
return user.map(u -> u.getOrders()).orElse(Collections.emptyList())

//上面避免了我们类似 Java 8 之前的做法

if(user.isPresent()) {
  return user.get().getOrders();
} else {
  return Collections.emptyList();
}
并且map返回的还是Optional,也就可以级联调用
看下这个:
return user.map(u -> u.getUsername())
           .map(name -> name.toUpperCase())
           .orElse(null);

User user = .....
if(user != null) {
    String name = user.getUsername();
    if(name != null) {
        return name.toUpperCase();
    } else {
        return null;
    }
} else {
    return null;
}

总结:

就是可能我们会对为空的字段做操作,这样就会报空指针异常,但是我觉得应该都会考虑空指针异常,那么这个Optional类只是让我们把那些if val == null else 这样的语句省去了,这样代码就变得简洁了,但是我总感觉其实这个类没太大必要,因为如果简单的逻辑完全可以用三元运算符代替,如果有那种if else 嵌套多的,并且还是判断为空的可以考虑,其他的我觉得没必要换,但是如果觉得高大上,可以用

二, Stream

什么是Stream? 文件流?字符流?字节流?我暂且认为就是对集合的再一次封装。

问题:为什么要有Stream?
遍历集合需要使用for,foreach,迭代器,这些难道我们都不需要写了吗?

先看用法:
分三部分
首先得需要拿一个集合对象来获取自己的流
然后一顿中间操作,就是你要对集合进行什么操作,你就写什么,但是这时候其实还没有执行这些方法
最后是终止操作,执行这个才将所有的操作一起执行

首先要获取流,获取流的方法有很多种
Collection接口就提供了两个获取流的方法,一个顺序流,一个是并行流
所以你可以像这样获取流:
List list = new ArrayList<>();
Stream stream = list.stream(); // 获取一个顺序流
其他的方法就不介绍了

那么拿到流之后,就可以一顿中间操作了
比如你要筛选就可以用filter方法,接受lambda表达式
比如去重那么就可以用distinct方法,根据hashCode和equals
比如你不想操作所有元素,那么就用limit(n)方法,给定一个最大值
skip(n)返回一个扔掉了前n个元素的流,与limit互补

上面的方法大概就是过滤和筛选吧,但真正要执行一些业务逻辑的话应该是下面的方法:
比如你想好了怎么处理函数,那么就自己写一个函数,然后传到map里,你写的函数的参数类型和个数要和遍历的集合元素一致,然后返回Stream这类型就好了,如果逻辑简单的话,或者现有函数可以完成,直接传入就可以了

还有一种flatmap方法,它和map的区别我看别人写的代码
它是可以把多个流连接成一个流:

  1. List words = new ArrayList();

  2. words.add(“your”);

  3. words.add(“name”);

  4. public static Stream characterStream(String s){

  5.  List<Character> result = new ArrayList<>();  
    
  6.  for (char c : s.toCharArray()) 
    
  7.      result.add(c);
    
  8. return result.stream();  
    
  9. }

  10. Stream<Stream> result = words.map(w -> characterStream(w));

  11. Stream letters = words.flatMap(w -> characterStream(w));
    如果使用的是map方法,返回的是[ …[‘y’, ‘o’, ‘u’, ‘r’], [‘n’, ‘a’, ‘m’, ‘e’]]
    如果使用的是flatMap方法,返回的是[‘y’, ‘o’, ‘u’, ‘r’, ‘n’, ‘a’, ‘m’, ‘e’]

最后还有个排序的方法:
sorted()

不传参数就是默认排序,传参数就是自定义排序

最后就是终止操作了:
执行这个操作,才真的执行上述一系列的中间操作:
比如你想要知道流中经历了层层筛选最后剩下多少数目,就可以用count方法
求最大值max,最小值min, 返回第一个元素findFirst, 或者做一些匹配,比如剩下的元素还是不是你想要的,则可以用allMatch, anyMath noneMatch方法

但是上述方法你可能都不想要,把stream转化为集合类型也是终止操作
方法是collect
例如如果想把流转化成list类型可以用:
collect(Collectors.toList())

总结:
因为不可以map里不可以改变外部的局部变量,所以有些for不可以被stream取代
性能问题:https://blog.csdn.net/caoxiaohong1005/article/details/79091946 你可以去这里面具体看一下

  1. 对于简单操作推荐使用外部迭代手动实现,
  2. 对于复杂操作,推荐使用Stream API,
  3. 在多核情况下,推荐使用并行Stream API来发挥多核优势,
    4.单核情况下不建议使用并行Stream API。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值