Java Optional
Optional判断空值很方便,但是我们如何使用更合适,在什么情况不适合使用呢?
下面我们看下Optional 使用的几大规则:
1. Optional 和其他的Java对象一样,千万别用null 作为optional 的变量或者返回值。
2.在判断isPresent之前,不要使用get()方法. (原开发者后悔开发了get方法……^_^)
看如下代码:
public String getCustemerNameById(List<Customer> customerList, String customerId){ Optional <Customer> opt= customerList.stream().filter(c->customerId.equals(c.getCustomerId())) .findFirst(); return opt.get().getCustomerName(); }
很容易产生空指针异常。
应该改为:
public String getCustemerNameById(List<Customer> customerList, String customerId){ Optional <Customer> opt= customerList.stream().filter(c->customerId.equals(c.getCustomerId())) .findFirst(); return opt.isPresent()?opt.get().getCustomerName():"UNKNOWN"; }
3. 尽可能替换Optional.isPresent() and Optional.get()这种模式
最佳实践
public String getCustemerNameById(List<Customer> customerList, String customerId){ Optional <String> opt= customerList.stream().filter(c->customerId.equals(c.getCustomerId())) .findFirst().map(c->c.getCustomerName()); // return opt.orElse("UNKNOWN"); // return opt.orElseGet(supplier.getNewCustomer().getCustomerName()); return opt.orElseThrow(()->new RuntimeException("Not found!!!")); }
4. 不要为了链式开发而强制使用Optional.ofNullable(obj).orElseGet
//BAD public String getData(String s){ return Optional.ofNullable(s).orElse("Default Value"); } //Good public String getData(String s){ return s==null?"Default Value":s; }
5. 如果Optional 链中有内嵌Optional 或者中间值导致Optional<Optional<T>>会太复杂,尽量避免
public Optional<BigDecimal> calculateAdd(Optional<BigDecimal> first,Optional<BigDecimal> second){ return first.map(a->second.map(a::add).orElse(a)) //不推荐 .map(Optional::of) .orElse(second); } //清晰的表达 推荐 public Optional<BigDecimal> calculateAdd1(Optional<BigDecimal> first,Optional<BigDecimal> second){ BigDecimal ZERO = new BigDecimal(0); if(!first.isPresent()&&!second.isPresent()){ return Optional.empty(); }else{ return Optional.of(first.orElse(ZERO).add(second.orElse(ZERO))); } }
6. 不要使用Optional 类型作为属性,方法参数以及collection
7. ifPresent and Stream
//java 8 public List<Customer> existingCustomers(List<Customer> customerList){ return customerList.stream().map(CustomerRepo::findById) .filter(Optional::isPresent) .map(Optional::get) .collect(Collectors.toList()); } //java 9 public List<Customer> existingCustomers(List<Customer> customerList){ return customerList.stream().map(CustomerRepo::findById) .flatMap(Optional::stream) .collect(Collectors.toList()); }
Reference:
https://www.youtube.com/watch?v=fBYht