写业务代码的时候,通常会遇到数据库POJO对象转换为前端需要的VO对象,这时经常会遇到烦人的空指针问题,Java 8之前,我们可能这么写:
- 对于对象field复制风格:
a.setCreateTime(b.getCreateTime().getTime()); a.setAmount(b.getPayed()+b.getVoucher());
- 对于装饰器风格:
public Long getCreateTime() { return b.getCreateTime().getTime(); } public Long getAmount() { return b.getPayed()+b.getVoucher() }
很明显,这些代码会有空指针异常的风险.一般我们会这么修改:
- 对于对象field复制风格:
if (b.getCreateTime()!= null) { a.setCreateTime(b.getCreateTime().getTime()); } if (b.getPayed() != null) { a.setAmount(b.getPayed(); } else { a.setAmount(0L); } if (b.getVoucher() != null) { a.setAmount(a.getAmount()+b.getVoucher()); }
- 对于装饰器风格:
public Long getCreateTime() { if (b.getCreateTime()!= null) { return b.getCreateTime().getTime(); } else { return null; } } public Long getAmount() { Long result = 0L; if (b.getPayed() != null) { result += b.getPayed(); } if (b.getVoucher() != null) { result += b.getVoucher(); } return result; }
Java8引入的Optional写法:
- 对于对象field复制风格:
Optional.ofNullable(b.getCreateTime()).ifPresent(timestamp -> a.setCreateTime(timestamp.getTime())); a.setAmount(Optional.ofNullable(b.getPayed()).orElse(0L) + Optional.ofNullable(b.getVoucher()).orElse(0L));
- 对于装饰器风格:
public Long getCreateTime() { Optional<Timestamp> createTime = Optional.ofNullable(b.getCreateTime()); if (createTime.isPresent()) { return createTime.get(); } else { return null; } } public Long getAmount() { return Optional.ofNullable(b.getPayed()).orElse(0L) + Optional.ofNullable(b.getVoucher()).orElse(0L) }
这样依然很复杂,尤其是嵌套多层之后。 更进一步,有没有通用简便的方法呢?联想到Java8的Functional Interface以及我们需要处理的异常只有空指针异常,可以写工具类:
import java.util.function.Supplier; public class OptionalUtil { /** * 忽略NullPointerException的获取 * @param supplier * @param <T> * @return 如果有空指针,返回null */ public static <T> T orNull(Supplier<T> supplier) { try { return supplier.get(); } catch (NullPointerException e) { return null; } } /** * 忽略NullPointerException的获取 * * @param supplier * @param or * @param <T> * @return 如果有空指针,返回or */ public static <T> T or(Supplier<T> supplier, T or) { try { T t = supplier.get(); if (t != null) { return t; } return or; } catch (NullPointerException e) { return or; } } }
这样,我们的代码就变得简洁多了:
- 对于对象field复制风格:
a.setCreateTime(OptionalUtil.orNull(() -> b.getCreateTime().getTime())); a.setAmount(OptionalUtil.or(() -> b.getPayed(), 0L) + OptionalUtil.or(() -> b.getAmount(), 0L));
- 对于装饰器风格:
public Long getCreateTime() { return OptionalUtil.orNull(() -> b.getCreateTime().getTime()); } public Long getAmount() { return OptionalUtil.or(() -> b.getPayed(), 0L) + OptionalUtil.or(() -> b.getAmount(), 0L); }