Java8 Optional 使用
Optional是Java8提供的为了解决null安全问题的一个API。善用Optional可以使我们代码中很多繁琐、丑陋的设计变得十分优雅。我个人觉得,java8之所以要提出这个对象,是因为java8中主要引入了lambda表达式,这种函数式编程中大量的链式调用,如果用原始的方法去判断nullpointException,会破坏lambda这种风格。还有一个原因是,其他语言比如kotlin,就提供了在语法层面的操作符加持:comp?.getResult()?.getChampion()?.getName()。
Optional 一个可以为 null 的容器,所在包:import java.util.Optional;
1、基本方法:
of() 为非 null 的值创建一个 Optional 实例
isPresent() 如果值存在,返回 true,否则返回 false
get() 返回该对象,有可能返回 null
Optional<String> op1 = Optional.of("Hello");
System.out.println(op1.isPresent()); // 输出 true
System.out.println(op1.get()); // 输出 Hello
Optional<String> op2 = Optional.of(null); // 抛出异常
OfNullable() 如果指定的值为 null,返回一个空的 Optional
Optional<String> op2 = Optional.ofNullable(null);
System.out.println(op2.isPresent()); // 输出 false
ifPresent() 如果实例非空,调用 Comsumer Lambda 表达式
Optional<String> op1 = Optional.of("Hello");
op1.ifPresent((s) -> {
System.out.println(s); // 输出 Hello
});
map() 如果实例非空,调用 Function Lambda 表达式
api如下:
public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
Objects.requireNonNull(mapper);
if (!isPresent())
return empty();
else {
return Optional.ofNullable(mapper.apply(value));
}
}
使用:
Optional<String> op1 = Optional.of("Hello");
Optional<String> op2 = op1.map((s) -> s.toUpperCase());
op2.ifPresent((s) -> {
System.out.println(s); // 输出 HELLO
});
orElse(obj) 如果实例非空,返回该实例,否则返回 obj
Optional<String> op1 = Optional.of("Hello");
System.out.println(op1.orElse("World")); // 输出 Hello
Optional<String> op2 = Optional.ofNullable(null);
System.out.println(op2.orElse("World")); // 输出 World
orElseGet(Supplier<? extends T> other) 如果实例非空,返回该实例,否则返回 Supplier
Optional<String> op1 = Optional.of("Hello");
System.out.println(op1.orElseGet(() -> {return new String("World");})); // 输出 Hello
Optional<String> op2 = Optional.ofNullable(null);
System.out.println(op2.orElseGet(() -> {return new String("World");})); // 输出 World
2、示例:
一般,我们判断对象null的代码如下:
public static String getName(User u) {
if (u == null)
return "Unknown";
return u.name;
}
有了optional后,我们千万不要改写成下面这种方式:
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安全问题。虽然没有直接提供一个操作符写起来短,但是代码看起来依然很爽很舒服。更何况?.这样的语法好不好看还见仁见智呢。
Optional的魅力还不止于此,Optional还有一些神奇的用法,比如Optional可以用来检验参数的合法性。
public void setName(String name) throws IllegalArgumentException {
this.name = Optional.ofNullable(name).filter(User::isNameValid)
.orElseThrow(()->new IllegalArgumentException("Invalid username."));
}
推荐阅读
-
SpringBoot + Spring Security 基本使用及个性化登录配置详解
-
深入浅析C#中单点登录的原理和使用
-
C#连接Oracle数据库使用Oracle.ManagedDataAccess.dll
-
python中的字典使用分享
-
详解C#使用AD(Active Directory)验证内网用户名密码
-
使用SpringBoot Actuator监控应用示例
-
使用navicat 8实现创建数据库和导入数据 管理用户与权限[图文方法]
-
使用Java7的Files工具类和Path接口来访问文件的方法
-
Spring Boot中配置文件application.properties使用
-
从零开始使用IDEA创建SpringBoot项目(图文)