原创:按钮日记(微信公众号ID:codelogs),欢迎分享,转载请保留出处。简介要说Java中最容易出现哪些异常,我想NullPointerException一定当仁不让。为了解决这个判断空值的问题,Java8提供了一个新的工具类Optional,用于提示程序员注意空值,并在特定场景下简化代码逻辑。例如下面一段获取深层属性值的代码:order.getUser().getUserCode()!=null){userCode=order.getUser().getUserCode().toUpperCase();}}}这种场景比较常见,但是深度嵌套if判断让代码阅读者压力更大。看看使用Optional后的写法,如下::toUpperCase).orElse("")链式调用的写法大大增强了代码的可读性,而且不需要判断null,因为Optional内部已经判断了null值!那么我们来看看Optional的用法。createOptionalofNullable()方法创建一个Optional,传入的值可以为null也可以不为null。of()方法得到一个Optional,当明确传入的值不为null时使用。如果传入null,会报错NullPointerExcepiton。实际上,如果值不为null,一般情况下不需要使用Optional。这应该在特殊场景下使用,比如方法的返回值必须是一个Optional。empty()方法获取的是一个空的Optional,一般用于返回值必须是Optional的场景。ifPresent()方法判断是否有值。注意,虽然这个方法看起来很有用,但是在使用Optional时不应该是第一个使用的方法,如下:if(opt.ifPresent()){...}if(obj!=null){...}这两个代码写法不同,但是代码可读性没有根本区别!Valueget()方法获取Optional的值,没有值时抛出NoSuchElementException。同样,在使用Optional时也不应该是第一个使用的方法,因为抛出NoSuchElementException与抛出NullPointerException没有太大区别。orElse方法在没有值时返回指定的值。字符串名称=nameOpt.orElse("");orElseGet方法同上,但是参数变成了提供默认值的lambda函数,用于需要一定成本才能获取指定值的场景,如下:BigDecimalamount=amountOpt.orElseGet(()->calcDefaultAmount());orElseThrow方法在没有值时抛出指定的异常,如下:OptionaluserOpt=getUser(userId);用户user=userOpt.orElseThrow(()->newNullPointerException("userId:"+userId));可能有人会疑惑,你还抛出NPE异常,跟不使用Optional有什么区别?不同的是这个NPE异常会告诉你是哪个userId找不到数据,方便定位问题,而jvm抛出的NPE是没有这个信息的。功能处理ifPresent(Consumerconsumer)方法该方法与ifPresent()方法不同。这个方法的意思是如果Optional有值,就会执行传入的lambda函数,如下:userOpt.ifPresent((user)->System.out.printf("%s\n",user.toString()));filtermethod该方法用于过滤Optional中的值,如果Optional有值,并且该值满足过滤函数,则返回这个Optional,否则返回一个空的Optional。Stringname=nameOpt.filter(StringUtils::isNotBlank).orElse("");mapmethod这个方法是用来转换value的,在开头已经展示过了。如果Optional有值,则在map中执行lambda函数来转换该值。如下:Optional还提供了一个flatMap方法。与map方法的不同之处在于,传递给flatMap的lambda函数必须返回一个Optional值。Optional的争议其实业界对于是否使用Optional的争议还是很多的。一方面,Optional可以强制开发人员处理null值,但另一方面,Optional非常容易被滥用,尤其是当某些开发人员获取Optional时。然后直接调用get()或ifPresent()方法,几乎??解决不了任何问题,增加编码负担。所以,我的建议是,如果不知道要不要用Optional,先不要用。下面是一些使用Optional场景的参考,如下:Optional一般用于返回值Optional多用于返回值,不推荐用于成员变量或方法参数。Optional本身不判断null。永远不要给Optional赋null,也不要判断Optional本身是否为null。这是因为Optional是为了解决null,再引入null是没有意义的。这应该成为业界的共识。集合不使用Optional是因为集合有更好的处理方法如Collections.emptyList(),所以没必要使用Optional。功能处理值可以从上面的使用介绍中找到。Optional提供了很多lambda函数式的处理方法,比如filter、map等,在使用Optional的时候推荐使用这些方法,因为Optional可以帮你自动处理nullvaluescase,避免NPE异常。多层属性获取我之前提到过这个代码示例,我认为这是使用Optional最明显的场景。不返回null优于返回Optional将Optional返回给调用者会强制调用者处理null的情况,这会给调用者增加一些编码负担,特别是对于复用度高的函数。但是如果调用者在大多数情况下并不期望得到null,那么应该实现这样一个方法,要么返回一个值,要么返回一个异常,如下:/***查询订单,或者返回订单,或者异常*/publicOrdergetOrderByIdOrException(LongorderId){订单order=orderMapper.getOrderById(orderId);if(order==null){thrownewBizException("根据订单号"+orderId+"没有找到订单!");}returnorder;}/***查询订单,可能为null*/publicOptionalgetOrderById(LongorderId){Orderorder=orderMapper.getOrderById(orderId);returnOptional.ofNullable(order);}由于后面的处理代码依赖于订单数据,无法获取到订单数据,代码也无法往下走,所以大多数情况下还是使用getOrderByIdOrExcept方法比较好,避免了NPE并增加编码负担!综上所述,Optional可以解决一些问题,但是因为容易被滥用而备受争议,因为Optional将null的处理交给了调用者,但大多数情况下,调用者没有办法处理这种null的情况,最好让JVM异常抛出一个NPEabortsexecution,因为如果使用ifPresent,更容易导致逻辑错误,执行不该执行的代码。这和Java的checkedexception是一样的,强制调用者处理异常,但是调用者能处理多少种异常场景呢?这导致开发者经常滥用catch和处理异常,最后发现catch后面有一些不应该执行的代码。