前文
程序中异常NullPointerExceptions,通常我们的代码会遇见如此的错误,很明显空指针异常错误,必定是哪里缺少判空操作
我们这样做
// Life before Optional
private void Method(User user){
if (user != null) {//如此判断,确实简单明了,
//do something
}
}
也可能我们这样判断Util.isNotEmpty(user)或者ObjectUtil.isNotEmpty(user),其实都可以,没毛病
我们偶尔会忘记判空,这就会导致报错
java8之后使用Optional,实话看起来可能抽象了一些,代码品质可以提升一些档次,环境所需要,卷起来没错的
Optional
Optional 类是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。
Optional 是个容器:它可以保存类型T的值,或者仅仅保存null。Optional提供很多有用的方法,这样我们就不用显式进行空值检测。
Optional 类的引入很好的解决空指针异常。
以下介绍常用方法
创建一个Optional类
1、static <T> Optional<T> empty()
返回空的 Optional 实例。
// Creating an empty optional
Optional<String> empty = Optional.empty();
System.out.println(empty);
====Optional.empty
2、static <T> Optional<T> of(T value)
返回一个指定非null值的Optional。
// Creating an optional using of
String name = "java";
Optional<String> opt = Optional.of(name);
System.out.println(opt);
===Optional[java]
3、static <T> Optional<T> ofNullable(T value)
如果为非空,返回 Optional 描述的指定值,否则返回空的 Optional。
// Possible null value
Optional<String> optional = Optional.ofNullable(name());
System.out.println(optional );
private String name(){
String name = "Java";
return (name.length() > 5) ? name : null;
}
name="java"====Optional.empty
name="javawww"====Optional[Javawww]
布尔值
boolean isPresent()
如果值存在则方法会返回true,否则返回 false。
···
//ispresent
Optional optional = Optional.of("javaone");
if (optional.isPresent()){
//Do something, normally a get
System.out.println("存在")
}
===存在
ifPresent(Consumer<? super T> consumer)
void ifPresent(Consumer<? super T> consumer)
如果值存在则使用该值调用 consumer , 否则不做任何事情。
//ifpresent
Optional<String> optional1 = Optional.of("javaone");
optional1.ifPresent(s -> System.out.println(s.length()));
====7
T get()
如果在这个Optional中包含这个值,返回值,否则抛出异常:NoSuchElementException
//get
Optional<String> optional = Optional.of("javaone");
if (optional.isPresent()){
String value = optional1.get();
System.out.println(value )
}
====javaone
T orElse(T other)
如果存在该值,返回值, 否则返回 other。
//orElse
String nullName = null;
String name = Optional.ofNullable(nullName).orElse("default_name");
System.out.println(name )
=====default_name
T orElseGet(Supplier<? extends T> other)
如果存在该值,返回值, 否则触发 other,并返回 other 调用的结果。
//orElseGet
String name = Optional.ofNullable(nullName).orElseGet(() -> "john");
System.out.println(name )
===john
注意:
a)不要将其用作类中的字段,因为它不可序列化
b)不要将其用作构造函数和方法的参数,因为这会导致不必要的复杂代码。
User user = new User(“哈哈哈”, “12345678”, Optional.empty());
其他方法请自行去看W3C传送门
感谢借鉴学习传送门
说一说通常在代码里面如何使用:
1、创建 Optional 实例
Optional<User> opt = Optional.ofNullable(user);
2、访问 Optional 对象的值
opt.ifPresent( u -> assertEquals(user.getEmail(), u.getEmail()));
3、返回值
User result = Optional.ofNullable(user).orElseGet( () -> user2);
4、orElse() 和 orElseGet() 的不同之处
当对象为空而返回默认对象时,行为并无差异。
两个 Optional 对象都包含非空值,两个方法都会返回对应的非空值。不过,orElse() 方法仍然创建了 User 对象。与之相反,orElseGet() 方法不创建 User 对象。
在执行较密集的调用时,比如调用 Web 服务或数据查询,这个差异会对性能产生重大影响。
5、返回异常
T orElseThrow(Supplier<? extends X> exceptionSupplier)
如果存在该值,返回包含的值,否则抛出由 Supplier 继承的异常
Optional 还定义了 orElseThrow() API —— 它会在对象为空的时候抛出异常,而不是返回备选的值
User result = Optional.ofNullable(user)
.orElseThrow( () -> new IllegalArgumentException());
这里,如果 user 值为 null,会抛出 IllegalArgumentException。
这个方法让我们有更丰富的语义,可以决定抛出什么样的异常,而不总是抛出 NullPointerException。
6、转换值
Optional map(Function<? super T,? extends U> mapper)
如果有值,则对其执行调用映射函数得到返回值。如果返回值不为 null,则创建包含映射返回值的Optional作为map方法返回值,否则返回空Optional。
String email = Optional.ofNullable(user)
.map(u -> u.getEmail()).orElse("default@gmail.com");
map() 对值应用(调用)作为参数的函数,然后将返回的值包装在 Optional 中。这就使对返回值进行链试调用的操作成为可能 —— 这里的下一环就是 orElse()。
相比这下,flatMap() 也需要函数作为参数,并对值调用这个函数,然后直接返回结果。
下面的操作中,我们给 User 类添加了一个方法,用来返回 Optional:
public class User {
private String position;
public Optional<String> getPosition() {
return Optional.ofNullable(position);
}
//...
}
既然 getter 方法返回 String 值的 Optional,你可以在对 User 的 Optional 对象调用 flatMap() 时,用它作为参数。其返回的值是解除包装的 String 值:
String position = Optional.ofNullable(user)
.flatMap(u -> u.getPosition()).orElse("default");
7、过滤值
Optional filter(Predicate<? super predicate)
如果值存在,并且这个值匹配给定的 predicate,返回一个Optional用以描述这个值,否则返回一个空的Optional。
filter() 接受一个 Predicate 参数,返回测试结果为 true 的值。如果测试结果为 false,会返回一个空的 Optional。
来看一个根据基本的电子邮箱验证来决定接受或拒绝 User(用户) 的示例:
Optional<User> result = Optional.ofNullable(user)
.filter(u -> u.getEmail() != null && u.getEmail().contains("@"));
如果通过过滤器测试,result 对象会包含非空值。
链式:
if (user != null) {
Address address = user.getAddress();
if (address != null) {
Country country = address.getCountry();
if (country != null) {
String isocode = country.getIsocode();
if (isocode != null) {
isocode = isocode.toUpperCase();
}
}
}
}
优化为:
public class User {
private Address address;
public Optional<Address> getAddress() {
return Optional.ofNullable(address);
}
public void setAddress(Address address) {
this.address = address;
}
}
public class Address {
private Country country;
public void setCountry(Country country) {
this.country = country;
}
public Optional<Country> getCountry() {
return Optional.ofNullable(country);
}
}
public class Country {
private String isocode ;
public Optional<String> getIsocode() {
return Optional.ofNullable(isocode);
}
public void setIsocode(String isocode) {
this.isocode = isocode;
}
}
@Test
public void whenChaining_thenOk() {
User user = new User("anna@gmail.com", "1234");
String result = Optional.ofNullable(user)
.flatMap(u -> u.getAddress())
.flatMap(a -> a.getCountry())
.map(c -> c.getIsocode())
.orElse("default");
assertEquals(result, "default");
}
上面的代码可以通过方法引用进一步缩减:
String result = Optional.ofNullable(user)
.flatMap(User::getAddress)
.flatMap(Address::getCountry)
.flatMap(Country::getIsocode)
.orElse("default");
测试:
public static void main(String args[]) {
User user = new User();
Address a=new Address();
Country c=new Country();
c.setIsocode(null);
a.setCountry(c);
user.setAddress(a);
String result = Optional.ofNullable(user)
.flatMap(User::getAddress)
.flatMap(Address::getCountry)
.flatMap(Country::getIsocode)
.orElse("default");
System.out.print(result);
}
==== c.setIsocode(null)=null-----default
c.setIsocode("666")=null-----666
以上是整理学习的,感谢借鉴,只是java8的学习,java9听说做了一些改变可自行学习。