Java 8 Optional 的用法
认识Optional
Optionals是用于防止 NullPointerException 的漂亮工具。让我们快速了解一下Optionals的工作原理。
Optional 是一个简单的容器,其值可能是null或者不是null。在Java 8之前一般某个函数应该返回非空对象但是有时却什么也没有返回,而在Java 8中,你应该返回 Optional 而不是 null。
可以大概瞥一眼官方文档:https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html
先看几个传统if判空用法:
public static String getName(User u) { if (u == null || u.name == null) return "Unknown"; return u.name; } 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."); }
Optional改写:
public static String getName(User u) { return Optional.ofNullable(u) .map(user->user.name) .orElse("Unknown"); } 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.")); }
是不是看着很简洁舒服,可读性也提高了一个档次。
核心常用方法介绍:
如何生成一个Optenal对象?
Optional<String> s2 = Optional.ofNullable(s);// Returns anOptional
describing the specified value, if non-null, otherwise returns an emptyOptional
.
Optional<Object> empty = Optional.empty();//Returns an emptyOptional
instance.
//of():为非null的值创建一个Optional
Optional<String> optional = Optional.of("bam");
// isPresent(): 如果值存在返回true,否则返回false
optional.isPresent(); // true
//get():如果Optional有值则将其返回,否则抛出NoSuchElementException
optional.get(); // "bam"
//orElse():如果有值则将其返回,否则返回指定的其它值
optional.orElse("fallback"); // "bam"
//ifPresent():如果Optional实例有值则为其调用consumer,否则不做处理
optional.ifPresent((s) -> System.out.println(s.charAt(0))); // "b"
一般使用Optional.ofNullable(s) 即可 ,返回一个不确定的Optional。
map () 映射出一个对象放入Optional容器。
Optional<String> s = Optional.ofNullable(Arrays.asList("1,2,3".split(",")))
.map(li -> li.get(0));
String s3 = Optional.ofNullable(Arrays.asList("1,2,3".split(",")))
.map(li -> li.get(0))
.orElse("4");
.filter()过滤出符合条件的
List<String> list==Optional.ofNullable(Arrays.asList("1,2,3".split(","))) .filter(str->str.equals("2")).orElseThrow(()->new IllegalArgumentException("IllegalArgument"));
Optional.filter() 可以用于参数校验 如:
public void setName(String name) throws IllegalArgumentException { this.name = Optional.ofNullable(name).filter(User::isNameValid) .orElseThrow(()->new IllegalArgumentException("Invalid username.")); }
Optional就像一个处理不确定性的管道,我们在一头丢进一个可能是null的东西(接口返回结果),经过层层处理,最后消除不确定性。Optional在过程中保留了不确定性,从而把对null的处理移到了若干次操作的最后,以减少出现NPE错误的可能。
于是,Optional应用的建议也呼之欲出了:
- 适用于层级处理(依赖上一步操作)的场合。
- 产生对象的方法若可能返回null,可以用Optional包装。
- 尽可能延后处理null的时机,在过程中使用Optional保留不确定性。
- 尽量避免使用Optional作为字段类型。
这种依赖上一步的操作也叫Continuation。而Optional的这种接受并组合多个Continuation的设计风格就是Continuation-passing style(CPS)。