Java 8 函数式编程 如何优雅的使用Optional
Optional
Optional是Java8提供的为了解决null安全问题的一个API。
1. Optional 应该只用于返回类型
而不是参数和属性,不然会使代码变的繁琐,影响可读性
2 你不应该简单的调用 get()
Optinal的目的是为了表示此值有可能为空,在某些情况下简单的调用get()而没有先使用isPresent()进行检查是一样会导致空指针问题。
3 使用Optional
我们就可以把下面这样的代码进行改写。
public static String getName(User u) { if (u == null) return "Unknown"; return u.name; }
不过,千万不要改写成这副样子。
public static String getName(User u) { Optional<User> user = Optional.ofNullable(u); if (!user.isPresent()) return "Unknown"; return user.get().name; }
这样改写非但不简洁,而且其操作还是和第一段代码一样。无非就是用isPresent方法来替代u==null。这样的改写并不是Optional正确的用法,我们再来改写一次。
public static String getName(User u) { return Optional.ofNullable(u) .map(user->user.name) .orElse("Unknown"); }
这样才是正确使用Optional的姿势。
那么按照这种思路,我们可以安心的进行链式调用,而不是一层层判断了。看一段代码:
public static String getChampionName(Competition comp) throws IllegalArgumentException { if (comp != null) { CompResult result = comp.getResult(); if (result != null) { User champion = result.getChampion(); if (champion != null) { return champion.getName(); } } } throw new IllegalArgumentException("The value of param comp isn't available."); }
由于种种原因,我们并不能开心的一路comp.getResult().getChampion().getName()到底。而其他语言比如kotlin,就提供了在语法层面的操作符加持:comp?.getResult()?.getChampion()?.getName()。所以讲道理在Java里我们怎么办!
让我们看看经过Optional加持过后,这些代码会变成什么样子。
public static String getChampionName(Competition comp) throws IllegalArgumentException { return Optional.ofNullable(comp) .map(c->c.getResult()) .map(r->r.getChampion()) .map(u->u.getName()) .orElseThrow(()->new IllegalArgumentException("The value of param comp isn't available.")); }
这就很舒服了。Optional给了我们一个真正优雅的Java风格的方法来解决null安全问题。虽然没有直接提供一个操作符写起来短,但是代码看起来依然很爽很舒服。更何况?.这样的语法好不好看还见仁见智呢。
还有一种实现相同作用的方式就是通过利用一个 supplier 接口来解决嵌套路径的问题:
Outer obj = new Outer(); resolve(() -> obj.getNested().getInner().getFoo()); .ifPresent(System.out::println);
还有很多不错的使用姿势,比如为空则不打印可以这么写:
string.ifPresent(System.out::println);
Optional的魅力还不止于此,Optional还有一些神奇的用法,比如Optional可以用来检验参数的合法性。
orElseThrow(Supplier<? extends T> supplier)、orElseGet(Supplier<? extends T> supplier):
使用 Supplier供给型函数式接口:无参数,返回一个结果。
public void setName(String name) throws IllegalArgumentException { this.name = Optional.ofNullable(name).filter(User::isNameValid) .orElseThrow(()->new IllegalArgumentException("Invalid username.")); }
参考资料
http://coyee.com/article/10666-java-8-top-tips
https://blog.kaaass.net/archives/764
- Java8 如何正确使用Optional
- Java多线程与并发应用-(5)-如何优雅的使用ThreadLocal类
- 6.如何正确使用Optional-java8新特性
- 如何使用Java编写NT服务
- 如何使用Java中取得Win2000系统当前登录帐户和主文件夹
- Java初学者如何迈出AOP第一步--使用Java 动态代理实现AOP(转)
- 如何使用Java读取串口的程序
- 如何使用Java POI生成Excel表文件 !
- Java中如何正确使用字体编码`
- Java中如何正确使用字体编码
- JAVA流使用总结——如何选择合适的流
- 没有Rails Java程序员如何使用Ruby
- 转:如何在JAVA中使用日期 (一)
- 如何让Linux下的Java程序使用中文
- 如何使用Java操作文本文件的方法详解 (转)
- 如何使用java程序界面上的按钮启动外部的exe程序
- 如何让Linux下的Java程序使用中文
- [摘录]JAVA如何使用相对路径
- Java中如何正确使用字体编码
- Java初学者如何迈出AOP第一步--使用Java 动态代理实现AOP