Atitit避免出现空指针异常解决方案

 

 

1. Null的问题1

2. 强制区分一般引用vs 可空引用 vs 强制引用,或者说非空引用2

3. ?运算符(问号运算符) !感叹号运算符避免出现空指针异常,2

4. Java 8中的Optional类2

4.1.1. 为什么使用Optional要比常见的null检查强?3

5. 另一个救星! Objects.requireNonNull3

5.1.1. 为什么比if(myObj!=null)要好?3

6. 参考4

 

1. Null的问题

含空引用的编程语言是一个价值十亿美元的错误(译者注:图灵奖得主 ​​Tony Hoare​​ 说过)。但是为什么呢?当然,他们可能会导致NullReferenceException,但那又怎样?只要使用不当,一个语言的任何一个元素都可导致错误啊

换句话说,有两种情况会出现判空语句:

· null返回值按找约定是正常的返回值

· null返回值不是正常的返回值

第二种情况很简单。可以使用assert来判断或者是允许程序报错(即抛NullPointerException)。断言是一个被充分利用的Java特性,在1.4版本中加入了这个特性。语法如下:

NullPointerException最主要的问题是没有一个biz 说明。

带有说明的异常要比光秃秃的抛出一个NullPointerException要好的多。

 

 

2. 强制区分一般引用vs 可空引用 vs 强制引用,或者说非空引用 3.  ?运算符(问号运算符) !感叹号运算符避免出现空指针异常,

的根源在于C#无法表达出非空引用的概念,这也导致让编译器强制进行空检查变成一种过于繁重的任务。

为了应对这个问题,某条提议建议使用一种强制引用,以及一种明确的可空引用的定义。在提议中,可空引用将使用?后缀进行定义,正如可空值类型的定义方式一样。而强制引用,或者说非空引用将使用!后缀进行定义。

强制引用以及可空引用都应该被视为一种仅限于语言本身的概念,它们只是改变了编译器的行为,但不会改动所生成的IL代码

在编译器允许访问可空引用对象的任何方法或属性之前,必须明确地检查空引用。并且在将某个可空引用转型为强制引用之前,也必须对空引用进行检查。

强制引用需要编译器证实其中包含的值不可为空。由于这是一种仅限于编译器的规则,因此无法保证在反序列化等场景中能够同样生效。

 

在阅读这条提议的完整内容时,你会注意到其中提到的某个术语“一般引用”。它指的是C#中的普通引用,它既不是强制的,也不是明确定义为可空的。由于这种引用将被视为遗留代码,因此可以通过AllowGeneralReferences这一属性告诉编译器不允许在代码中使用一般引用。

在结合隐式变量定义时,可以在var关键字中使用!或?后缀。

 

 

4. Java 8中的Optional类

简单的方法就是检查Optional包装器是否真的有值(使用isPresent方法)——你会怀疑这和使用if(myObj != null)相比有什么好处。别担心,这个我会解释清楚的

你可以使用orElse方法,这样万一封装的确实是一个null值的话可以用它来返回一个默认值——它的好处显而易见。在提取出真实值的时候可以避免调用ifPresent方法这样明显多余的方式了。

4.1.1. 为什么使用Optional要比常见的null检查强?

· 使用Optional最大的好处就是可以更明白地表述你的意图——返回null值的话会让消费者感到疑惑(当真的出现NPE的时候)这是不是故意返回的,因此还得查看javadoc来进一步定位。而使用Optional就相当明了了。

· 有了Optional你就可以彻底避免NPE了——如上所提,使用Optional.ofNullable,orElse以及orElseGet可以让我们远离NPE。

5. 另一个救星! Objects.requireNonNull

如果抛出NPE的话,我们怎么能确定到底是哪个是null的?

Objects.requireNonNull(key, "Key is null");

 

requireNonNull方法

· 如果对象不为null的话就返回它本身

· 如果值为null的话,返回的NPE会带有指定的消息

5.1.1. 为什么比if(myObj!=null)要好?

你所看到的栈跟踪信息会很清楚地看见Objects.requireNonNull的方法调用。这个再配合你自己的错误日志,可以让你更快地定位问题。。。至少在我看来是更快。

6. 参考

空指针的救星 - 博客 - 伯乐在线.htm

 

在Java中如何避免“!=null”式的判空语句? - ImportNew.htm

C#的未来:追踪空引用.htm