Optional类
Optional<T>类是一个容器类,代表一个值存在和不存在,原来用不惯null表示一个值的不存在,现在用Optional可以更好的表达这个概念;是Java1.8之后解决null值判断问题。
常用方法列表
method | desc |
---|---|
Optional.of(T t) | 创建一个非空值的Optional实例 |
Optional.empty() | 创建一个空的Optional实例 |
Optional.ofNullable(T t) | 若t不为null,创建Optional实例,否则创建空实例 |
isPresent() | 判断是否包含值 |
ifPresent(Consumer c) | 如果存在值,则使用该值调用指定的消费者,否则不执行任何操作 |
get() | 如果 Optional 中有值,返回值,否则抛出 NoSuchElementException
|
orElse(T t) | 如果对象包含值,返回该值,否则返回t |
orElseGet(Supplier s) | 如果对象包含值,返回该值,否则返回s中获取的值 |
orElseThrow(Supplier s) | 如果容器为空,返回自定义异常信息 |
filter(Predicate p) | 断言型接口返回true,则返回Optional描述的值;否则返回Optional.empty() |
map(Function f) | 如果有值对其处理,并返回处理后的Optional,否则返回Optional.empty() |
flatmap(Function mapper) | 与map类似,返回值要求必须是Optional |
引入
看一下下面的代码,为了避免空指针异常,我们需要多层的if判断,不利于代码的易读性同时也不利于书写。
if (people != null) {
Country country = people.getCountry();
if (country != null) {
City city = country.getCity();
if (city != null) {
Street street = city.getStreet();
if (street != null) {
String streetName = street.getStreetName();
}
}
}
}
创建实例方式
-
Optional.of(T t)
public void test02() { Optional<People> p = Optional.of(new People()); People people = p.get(); }
若
Optional.of(null)
,无法创建实例,导致NullPointerException
-
Optional.empty()
public void test03() { Optional<People> p = Optional.empty(); People people = p.get(); }
创建Optional的空实例,若使用
p.get()
获取对象,会导致java.util.NoSuchElementException: No value present
-
Optional.ofNullable(T t)
public void test04() { Optional<People> p = Optional.ofNullable(new People()); People people = p.get(); System.out.println(people); }
使用
Optional.ofNullable
构建Optional实例时,参数可以为其他实例,也可以为null
,如果为null
时,默认返回的是Optional.empty
。// 源码 public static <T> Optional<T> ofNullable(T value) { return value == null ? empty() : of(value); }
获取Optional的值
public void test04() {
Optional<People> p = Optional.ofNullable(new People());
People people = p.get();
System.out.println(people);
}
Optional容器类通过get()
方法获取容器中的对象,但若是Optional是个空实例,就会发生NoSuchElementException
异常,所以Optional容器类提供了isPresent()
方法来判断Optional是否是空实例。
public void test04() {
Optional<People> p = Optional.ofNullable(new People());
if (p.isPresent()) {
People people = p.get();
System.out.println(people);
}
}
public void test05() {
String name = "zhangsan";
Optional<String> optional = Optional.ofNullable("zhangsan");
Assert.assertTrue(optional.isPresent());
Assert.assertEquals(name, optional.get());
}
检查Optional容器类是否有值另外一个方法ifPresent(Consumer c); 如果有值则调用消费者代码块,否则不执行任何操作。若有值而Consumer为空,则会导致NullPointerException
public void test06() {
Optional<String> optional = Optional.ofNullable("zhangsan");
optional.ifPresent(System.out::println);
}
兜底函数
兜底函数可以理解为默认值,当Optional容器中没有值,则会返回兜底函数的值,避免获取不到值的情况
orElse(T t)
如果对象包含值,返回该值,否则返回t (注意:返回的是具体的值,而不是Optional容器类)
public void test07() {
String name = null;
String username = Optional.ofNullable(name).orElse("zhangsan");
Assert.assertEquals("zhangsan", username);
}
orElseGet(Supplier s)
如果对象包含值,返回该值,否则执行Supplier代码块
public void test08() {
String name = null;
People people = new People("zhangsan", 18, null);
String username = Optional.ofNullable(name).orElseGet(people::getName);
Assert.assertEquals("zhangsan", username);
}
orElse和orElseGet对比
若传入的值为null时
@Test
public void test09() {
System.out.println("orElse");
String name1 = (String) Optional.ofNullable(null).orElse(getName());
System.out.println("orElseGet");
String name2 = (String) Optional.ofNullable(null).orElseGet(() -> getName());
}
public String getName() {
System.out.println("getName");
return "zhangsan";
}
结果输出
orElse
getName
orElseGet
getName
可以看出,两者并没有差异,都会调用getName()
方法
若传入非null值
public void test10() {
System.out.println("orElse");
String name1 = (String) Optional.ofNullable("lisi").orElse(getName());
System.out.println("orElseGet");
String name2 = (String) Optional.ofNullable("lisi").orElseGet(() -> getName());
}
结果输出
orElse
getName
orElseGet
若传入非null值时,orElse()
还是会调用getName()
,而orElseGet()
则不会执行。
在密集型调用,或者需求量较大时,两者性能上的差异显而易见。
orElseThrow(Supplier s)
如果Optional容器为空,可以返回自定义的异常信息
public void test11() {
Object o = Optional.ofNullable(null).orElseThrow(IllegalArgumentException::new);
}
值过滤
filter(Predicate p)
通过filter(Predicate p)
方法过滤出来符合要求的值,其中当断言型接口p返回true,则返回Optional描述的值;否则返回空的Optional
public void test12() {
People p = new People("zhangsan", 11, null);
Optional<People> people = Optional.ofNullable(p)
.filter(x -> x.getAge() == 11);
Assert.assertTrue(people.isPresent());
}
值转换
map()
如果有值对其处理,并返回处理后的Optional,否则返回Optional.empty();
public void test13() {
People p = new People("zhangsan", 11, null);
Optional<String> optionalS = Optional.ofNullable(p).map(x -> x.getName());
Assert.assertTrue(optionalS.isPresent());
Assert.assertEquals("zhangsan", optionalS.get());
}
flatmap(Function mapper)
与map类似,返回值要求必须是Optional
public void test14() {
People p = new People("zhangsan", 11, null);
Optional<String> optionalS = Optional.ofNullable(p).flatMap(x -> Optional.ofNullable(x.getName()));
Assert.assertTrue(optionalS.isPresent());
Assert.assertEquals("zhangsan", optionalS.get());
}
总结
链式编程
filter,map,fliterMap返回都是Optional描述的值,所以就可以使用链式编程
public void test15() {
People p = null;
String str = Optional.ofNullable(p)
.filter(x -> x.getName() != null)
.flatMap(x -> Optional.ofNullable(x.getName()))
.orElse("lisi");
Assert.assertEquals(str, "lisi");
}
引入
的优化
// 每个属性值都是用Optional封装
private Optional<Country> country;
public void test20() {
People p = null;
String s = Optional.ofNullable(p)
.flatMap(x -> x.getCountry())
.flatMap(x -> x.getCity())
.flatMap(x -> x.getStreet())
.map(x -> x.getStreetName())
.orElse("北京东路");
Assert.assertEquals("北京东路", s);
}