使用和避免null Google底层代码库,95的集合类不接受null值作为元素。相比默默地接受null,使用快速失败操作拒绝null值对开发者更有帮助。 很多Guava工具类对Null值都采用快速失败操作,此外,Guava还提供了很多工具类,让你更方便地用特定值替换Null值例子 我们知道JDK8以后也参考Guava加入了Optional的API,使用上跟Guava的区别不大,例子中我们使用JDK的API来演示。 直接上个实际工作中的案例即:对象的嵌套判空 比如我有个对象,对象的某个属性也是对象,然后就这样一直嵌套下去,比如:DatapublicclassTest1{privateStringinfoinfo1;privateTest2test2;}DatapublicclassTest2{privateSprivateTest3test3;}DatapublicclassTest3{privateSprivateTest4test4;}DatapublicclassTest4{privateStringinfotest4} 为了减少代码量和版面,我使用了LombokdependencygroupIdorg。projectlombokgroupIdlombokartifactIdversion1。18。24versionscopeprovidedscopedependency 如果我想使用Test4的info属性,可以用if一直嵌套判断下来:if(test1!null){Test2test2test1。getTest2();if(test2!null){Test3test3test2。getTest3();if(test3!null){Test4test4test3。getTest4();if(test4!null){System。out。println(test4。getInfo());}}}} 对象层级一深,代码很臃肿。Optional可以帮我们用一行代码解决掉!Stringinfo1Optional。ofNullable(test1)。map(Test1::getTest2)。map(Test2::getTest3)。map(Test3::getTest4)。map(Test4::getInfo)。orElse(hello);System。out。println(info1); 这行代码达到的效果和上面的if一样 解释一下上面几个Optional的方法:ofNullable:如果test为空,则返回一个单例空Optional对象,如果非空则返回一个Optional包装对象,Optional将test包装map:如果为空,继续返回第一步中的单例Optional对象,否则调用Test的getTest方法;orElst:获得map中的value,不为空则直接返回value,为空则返回传入的参数作为默认值 上面代码中的map方法也可以换作flatMap方法,区别是:flatMap要求返回值为Optional类型,而map不需要,flatMap不会多层包装,map返回会再次包装Optional。 我们这里Test类是普通类并没有使用Optional包装,如果这么写就可以使用flatMap:DatapublicclassTest1{privateStringinfoinfo1;privateOptionalTest2test2;} 此外我们还可以在发生空指针的情况下,抛出异常或自定义异常:Stringinfo2Optional。of(test1)。map(Test1::getTest2)。map(Test2::getTest3)。map(Test3::getTest4)。map(Test4::getInfo)。orElseThrow(()newRuntimeException(有空指针异常,对象内容为:ToStringBuilder。reflectionToString(test1,newMultilineRecursiveToStringStyle())));System。out。println(info2); 可能你注意到了,我这里的异常输出中用到了ToStringBuilder这个类,这个是ApacheCommonsLang3的库类dependencygroupIdorg。apache。commonsgroupIdcommonslang3artifactIdversion3。12。0versiondependency 使用它的原因是:我们利用Optional一行代码就可以判断很多空指针是不错,但最后就算能捕捉异常也不能确定到底是哪个对象的哪个属性为空,如果只是笼统的给出顶层对象的异常信息,对于排错还是不很直观。当然如果要非常细致地判断和打印日志又会加大代码量,所以想了个折中的办法:将对象的信息递归地打印出来,这样是不是空在排查的时候就一目了然了。ToStringBuilder。reflectionToString方法可以帮我做到。ToStringBuilder。reflectionToString(test1,newMultilineRecursiveToStringStyle()) MultilineRecursiveToStringStyle也可替换为RecursiveToStringStyle,只是不同的显示Style罢了 如果我只有test1对象不为空,剩下的都为空,那么打印结果如下:com。xiaobox。gauva。test。Test12a5ca609〔infoinfo1,test2null〕 如果我的test1和test2对象都不为空,那么打印结果如下:com。xiaobox。gauva。test。Test12a5ca609〔infoinfo1,test2com。xiaobox。gauva。test。Test226be92ad〔infonull,test3null〕〕 这样的话,我就可以把信息合并到异常信息中,在排查问题时可以借助这些信息快速定位到哪个对象或哪个属性为空了。 注意:上面的例子中抛出了异常,但因为不是受检异常,所以IDE并没有提示我进行捕捉,写代码有些时候忘了捕获异常,所以,请记得它是将异常throws出去了。处理异常的时候别忘了。 比如一般我们可以这样privatestaticvoidopExceptionMethod()throwsException{Stringinfo2Optional。of(test1)。map(Test1::getTest2)。map(Test2::getTest3)。map(Test3::getTest4)。map(Test4::getInfo)。orElseThrow(()newRuntimeException(有空指针异常,对象内容为:ToStringBuilder。reflectionToString(test1,newMultilineRecursiveToStringStyle())));System。out。println(info2);} 显示地抛出,调用者就必须要捕获处理了。当然也可以不抛出,直接在代码块trycatch防御性编程 使用Optional除了赋予null语义,增加了可读性,最大的优点在于它是一种傻瓜式的防护。Optional迫使你积极思考引用缺失的情况,因为你必须显式地从Optional获取引用。直接使用null很容易让人忘掉某些情形,尽管FindBugs可以帮助查找null相关的问题,但是我们还是认为它并不能准确地定位问题根源。 如同输入参数,方法的返回值也可能是null。和其他人一样,你绝对很可能会忘记别人写的方法method(a,b)会返回一个null,就好像当你实现method(a,b)时,也很可能忘记输入参数a可以为null。将方法的返回类型指定为Optional,也可以迫使调用者思考返回的引用缺失的情形。 关于null的建议不要在Set中使用null,或者把null作为map的键值。使用特殊值代表null会让查找操作的语义更清晰。如果你想把null作为map中某条目的值,更好的办法是不把这一条目放到map中,而是单独维护一个值为null的键集合(nullkeys)其他 从Spring5开始,可以使用null安全注解来帮助编写更安全的代码。此功能称为空安全性,这是一组注解,其作用类似于监视潜在的空引用的安全措施。 空安全功能不是让摆脱不安全的代码,而是在编译时生成警告。这样的警告可以防止在运行时发生灾难性的空指针 注意这些注解只会发出警告,由于有了这个提示,可以提前发现问题,并能够采取适当的措施来避免运行时失败,也就是说你还是可以传递null值进来。NonNull注解:可以在需要对象引用的任何地方使用此注解声明非null约束:字段,方法参数或方法的返回值。NonNullFields注解:包(Package)级别注解,通知开发工具默认情况下,带注释的包中的所有字段均为非空。Nullable注解:有时,希望免除某些字段,使其不受程序包级别指定的非null约束的约束。NonNullApi注解:包(Package)级别注解,NonNullFields仅仅适用于字段。如果希望对方法的参数和返回值产生相同的影响,则需要NonNullApi,此注解只适用于包级别 看一个例子: 这是Spring框架中SpringCore的packageinfo文件内容 路径为:orgspringframeworkspringcore5。2。15。RELEASEspringcore5。2。15。RELEASEsources。jar!orgspringframeworkcorepackageinfo。javaNonNullApiNonNullFieldspackageorg。springframework。importorg。springframework。lang。NonNullAimportorg。springframework。lang。NonNullF参考https:coolshell。cnarticles17757。htmlhttps:juejin。cnpost6844903718375129095https:blog。csdn。netniugang0920articledetails116291106