当前位置: 首页 > 科技观察

使用Optional摆脱NullPointException的折磨

时间:2023-03-13 08:55:47 科技观察

背景在Java中,如果试图对null进行函数调用,将会引发NullPointerException(NPE)。NPE是Java程序开发中的一个典型异常。对于Java开发者来说,无论是初出茅庐的菜鸟,还是从业多年的老司机,NPE往往让他们翻车。为了避免NPE,他们会加入很多if判断语句,使得代码的可读性很差。从软件设计的角度来看,null本身没有任何有意义的语义,它是对缺失变量值的错误建模。从Java类型系统的角度来看,null可以赋值给任何类型的变量,而且是不断传递的,谁也不知道是从哪里引入的。Optional的引入Java设计者从Haskell和Scala中得到灵感,在Java8中引入了一个新的类java.util.Optional。如果一个接口返回Optional,它可以表明一个人可能有也可能没有车。这比简单的返回Car更清晰,看代码的人也不需要提前准备业务知识。这就是Optional的用途:通过类型系统使隐藏在域模型中的知识在代码中显式显示。Optional的使用上表列出了Optional的基本API,我这里列出一些使用技巧:可以使用ofNullable将一个可能为null的对象封装为一个Optional对象,然后使用orElse方法提供一个默认的获取值Value时;您可以使用empty方法创建一个空的Optional对象;of方法一般不用,但是如果知道一个值不能为null,可以用Optional封装这个值,这样一旦为null就会抛出异常。从对象中获取值是最常见的场景。这时候为了避免对象为null导致的NPE,一般会使用if-then-else结构检查。如果使用Optional,则可以使用map方法获取其封装对象中某个字段的值。如果需要从一个对象链的末端连续递进获取字段值,不能完全使用map方法,需要先使用flatMap,最后使用map方法;Optional中的map、flatMap和filter方法,其概念与Stream中的相应方法非常相似,不同之处在于Optional中最多只有一个元素,这是Stream的一个特例——一个特殊的集合。不要使用ifPresent和get方法。它们本质上与Optional对象不适用之前的模式相同。都是臃肿的if-then-else判断语句;因为Optional不能被序列化,所以领域模型中不能定义一个字段Optional的原因是Optional最初的设计只是为了支持可以返回Optional对象的语法。如果我们想在领域模型中引入Optional,可以使用如下替代方法:不要使用基本类型的Optional对象,原因是:基本类型的Optional对象不支持map、flatMap和filter方法,而这些方法是Optional中非常强大的方法。实际案例使用工具类方法改进可能抛出异常的APIJava方法中处理异常结果有两种方式:返回null(或错误码);抛出异常,例如:Integer.parseInt(String)方法——如果无法解析到对应的整数,该方法抛出NumberFormationException。这种情况下,我们一般使用try/catch语句来处理异常。通常,我们建议将try/catch块提取到一个方法中。这里使用Optional来设计这个方法。代码如下。在开发中,可以尝试构建一个OptionalUtility工具类来封装这些复杂的try/catch逻辑。综合案例现在有一种方法可以尝试从属性映射中获取某个关键字对应的值。示例代码如下:使用Optional写法后,代码如下:如果要访问的属性值不存在,Properites.getProperty(String)方法的返回值为null,可以是使用noNullable工厂方法转换为Optional对象;接下来,可以使用flatMap将Optional转换为Optional对象;***使用filter过滤掉负数,然后可以使用orElse获取属性值,获取不到返回默认值0。总结一下,使用Optional的思路和Stream是一样的。是链式思想,类似数据库查询,表达力强,省去了一些复杂的try/catch和if-then-else方法。在后期的开发中,可以使用Optional来设计API,这样可以设计出更加安全的接口和方法。