日常编码过程中,空指针异常非常常见。在jdk8以后,添加了Optional,用来解决这个问题。
Optional简单来说可以类比成操作单个对象的Stream
接下来介绍一下Optional:
创建Optional
其中第一行创建了一个空Optional,get()是从 Optional 实例中取回实际值对象的方法之一:
public static void main(String[] args) {
Optional<Haozi> emptyOpt = Optional.empty();
emptyOpt.get();
}
而如果这是这样,运行结果会报错:
看源码可以看出,empty()只是返回了一个空对象。
所以我们需要另外的方式:
of()和ofNullable(),二者的区别是如果把null作为参数传进去,of()还是会报空指针异常。
public static void main(String[] args) {
Optional<Haozi> emptyOpt = Optional.of(null);
// Optional<Haozi> emptyOpt = Optional.ofNullable(null);
}
看下of()的源码
再看下ofNullable()
通过源码可以看出,ofNullable()还是调用的empty(),所以并不是说用了ofNullable就无敌了,这个情况下再get(),还是会有问题,他只是整合了判断非空的问题。
所以在对象明确不为null的时候再用of(),不然就用ofNullable()。
获取Optional的值
从上面我们大致了解了get():
public static void main(String[] args) {
Haozi haozi = new Haozi("haozi" , "home");
Optional<Haozi> optional = Optional.ofNullable(haozi);
System.out.println(optional.get());
}
当然,我们已经知道,如果是null一样会报错,因此我们可以先进行判断非空,Optional提供了一个api:isPresent()
接下来引申出来另一个:ifPresent(),有值就执行断言:
public static void main(String[] args) {
Haozi haozi = new Haozi("haozi" , "home");
Optional<Haozi> optional = Optional.ofNullable(haozi);
optional.ifPresent(u -> System.out.println("is true"));
}
一直在说非空非空,如果有空值应该怎么处理?
orElse()
很简单,但要注意的是,他返回的是泛型类,并非Optional
public static void main(String[] args) {
Haozi haozi = new Haozi("haozi" , "home");
Haozi result = (Haozi) Optional.ofNullable(null)
.orElse(haozi);
System.out.println(result);
}
同类型的还有orElseGet()
public static void main(String[] args) {
Haozi haozi = new Haozi("haozi" , "home");
Haozi result = (Haozi) Optional.ofNullable(null)
.orElseGet(() -> haozi);
System.out.println(result);
}
异同点:这两个方式在前面条件是null的情况下,结果是一样的。而如果前面不为null:
public static void main(String[] args) {
Haozi haozi = new Haozi("haozi" , "home");
Haozi result = (Haozi) Optional.ofNullable(haozi)
.orElse(creatHaozi());
System.out.println(result);
}
private static Haozi creatHaozi(){
System.out.println("creating");
return null;
}
返回值:
public static void main(String[] args) {
Haozi haozi = new Haozi("haozi" , "home");
Haozi result = (Haozi) Optional.ofNullable(haozi)
.orElseGet(() -> creatHaozi());
System.out.println(result);
}
private static Haozi creatHaozi(){
System.out.println("creating");
return null;
}
返回值:
由此可见,orElse()不管前面是不是空,都会执行后面的内容。所以二者用起来还是要注意。
返回异常:
除了orElse()和orElseGet(),还提供了orElseThrow(),作用是当前面为null时抛出异常,这样我们可以自由的定义异常内容,而不仅仅是空指针
public static void main(String[] args) {
Haozi haozi = new Haozi("haozi" , "home");
Haozi result = (Haozi) Optional.ofNullable(null)
.orElseThrow(() -> new IllegalArgumentException());
System.out.println(result);
}
Optional其他api
Optional提供了好多api进行值的操作:
map()与flatMap()
public static void main(String[] args) {
Haozi haozi = new Haozi("haozi" , "home");
String result = Optional.ofNullable(haozi)
.map(h -> h.getName())
.orElse("abc");
System.out.println(result);
}
map()比较简单,不多说了
public class Haozi {
private String name;
private String address;
public Optional<String> getName() {
return Optional.ofNullable(name);
}
//...
}
public static void main(String[] args) {
Haozi haozi = new Haozi("haozi" , "home");
String result = Optional.ofNullable(haozi)
.flatMap(h -> h.getName())
.orElse("abc");
System.out.println(result);
}
map()与flatMap()的异同
对比可以知道,这两个作用是一样的。区别就是:
如果返回值不是Optional类型数据的时候,用map,map会进行一次Optional包装
如果返回值是Optional类型数据的时候,用flatMap,直接返回。
filter()
public static void main(String[] args) {
Haozi haozi = new Haozi("haozi" , null);
Optional<Haozi> result = Optional.ofNullable(haozi)
.filter(h -> h.getAddress() != null);
System.out.println(result.get());
}
很简单的一个过滤操作,如果通过就返回,不通过返回空Optional
Java9增强
java9新增了3中方法:or()、ifPresentOrElse() 和 stream()
or()与orElse() 和 orElseGet() 类似,它们都在对象为空的时候提供了替代情况。or() 的返回值是由 Supplier 参数产生的另一个 Optional 对象。
public static void main(String[] args) {
Haozi result = (Haozi) Optional.ofNullable(null)
.or(() -> Optional.of(new Haozi("haozi","home")))
.get();
System.out.println(result);
}
ifPresentOrElse()
public static void main(String[] args) {
Haozi haozi = new Haozi("haozi" , null);
Optional.ofNullable(null)
.ifPresentOrElse(
h -> System.out.println("true"),
() -> System.out.println("false"));
}
如果非空,执行逗号前面的,反之执行后面的。该方法在有值的时候执行某个动作,或者只是跟踪是否定义了某个值的时候非常有用。
stream()
可以把实例转换成stream流,从而使用stream的各种api
public static void main(String[] args) {
Haozi haozi = new Haozi("haozi" , "home");
List<String> addressList = Optional.ofNullable(haozi)
.stream()
.filter(h -> h.getAddress() != null)
.map(h -> h.getAddress())
.collect(Collectors.toList());
System.out.println(addressList.size());
}
综上,关于Optional的用法就说到这里,接下来多多实践。