Axelor 框架 Java 开发演示视频文字稿

2020年3月17日发布,Java正式发布了JDK 14 ,目前已经可以开放下载。在JDK 14中,共有16个新特性,本文主要来介绍其中的一个特性:JEP 358: Helpful NullPointerExceptions

null何错之有?

对于Java程序员来说,null是令人头痛的东西。时常会受到空指针异常(NullPy G ; u 7 s J +oint 6 R 7 QerException)的骚扰。相信很多8 z ^ x程序员都特别害怕出现程序中出现NPl g 9 F ` h /E,因为这种异常往往伴随着代码的非预期运行。

在Java 1 中就包含了了Null引用和NPE了,但是其实,Null引用是伟大的计算机科学家Tony Hoare 早在19$ _ | Y n ?65年发明的,{ r 9 : p最初作为编程语言ALGOL W的一( 6 a t = 4部分。

1965年,英国一位名为Tony Hoare的计算机科学家在设计B | * .ALGOL W语言时提出了null引用的想法。ALGOL7 ? U W是第一批u ( m v在堆上分配记录的类型语言Z R a 1之一。Hoare选择null引用这种方式,“只是因为这种方法实现起来非常容易”。虽然他的设计初衷就是要“通过编译器的自动检测机制,确保所有使用引用的地方都是绝对安全的”,他还是决定为null引用开个绿灯,因为他| c - e ~ 6 J & $认为这是为“不存在的值”建模最容易的方式。

但是在2009年,很多年后,他开始为自己曾经做过这样的决定而后悔不已,把它称为“一个价值十亿美r s 7 - + y, Q ~ R的错误”。

实际上,Hoare的这段话低估了过去五q f E十年来数百万程序员为修复空引用所耗费的代价。因为在ALGOL W之后出现的大多数现代程序设计语言,包括Java,都采用了同样的设计方式,其原因是为了与更老的语言保持兼容,或者就像Hoare曾经陈述的那样,“仅仅是因为这样实现起来更加容易”。

Java 14 发布了,再也不怕NullPointerException 了!?

相信很多Java程序员都一样对null和NPE深恶痛绝,因为他确实会Q [ 0 U带来各种各样的问题(来自《Java 8 实战》)。如:

  • 它是错误之源。NullPointerE_ { * C X B d Cxception是目前Java程序开发中最典型的异常。它会使你的代码膨胀。
  • 它让你的代码充斥着深度嵌套的nulli 1 j Z检查,代码的可读性糟糕透顶。
  • 它自身是毫6 y ) 9 n :无意义的0 e 6 R。null自身没有任何的语义,尤其是是它代表的是在静态类型语言中以一种错误的方式对缺失变量值的建模。
  • 它破坏了Java的哲学。Java一直试图避免让程序员意识到指针的存在,唯一的例外是:null指针。
  • 它在Java的类型系统上开了个口子。n] S s 0 u ull并不属于任何类型,这意{ w y - Y味着它可以被赋值给任意引用类型的变量。这会导致问题, 原因是当这个变@ f L量被传递到系统中的另一个部分后,你将无法获知这个null变量最初赋值到底是什么类型。

其他语言如何解决NPE问题

我们知道,出了Java语言外,还有很多其他的面向对象语言,那么在其他的一些语言中,是如何解决NPE的问题的呢?

如在Groovy中使用安全导航操作符(Sc # { v ? oafe Navigation Operator)可以访问可能为null的变量

def carInsuranceName = person?.car?.insuranceS 2 9?.name

Groovy的安全导航操作符能够避i ( A Y p P h 1免在访问这些可能为null引用的变量时发生NullPom Y ) XinterException,在调用链中的变量遭遇null时将null引用沿着调用链传递下去,返回一个null。

其实这个功能曾经g % + q x n考虑过增加一个类似的功能,2 x W @ b h z但是后来又被舍弃了。

另外,在Haskell和Scala也有类似的替代品l 4 Y + Q,如Haskell中的Maybe类型、Scala中的Option[T]。

在 Kotlin 中,其类型系统严格区分一个引用可以容纳 null 还是不能容纳。也就是说,一个变量是否可空必须显示声明,对于可空变量,在访问其成员时必须做空处D ` r | 2理,否则无法编译通过:

vf _ R Qar a: String = \"abc\"
a = null// 编译错误

果允许为空,可以声明一个可空字符串,写作 String?:

var b: String? = \"abc\"//String? 表示该V # b a ? 9 y + String 类型变量可为空
b = null// 编译通过

看到这个?的时候,是不是k 7 n ~ Q ( c ^^ { y : N现和Groovy有点像?不过还是有一定区别的,这里就不展开了。

好了,书归正传,我们来看看作为一个TOIBE编程语言排行榜第一名的语言,Java语言对于NPE做出了哪些努力!

Java做了哪些努力

一直以来对于nB j F t J k V gull和NPE的改进还是做出了一些努力的。

首先在Jav[ 4 L na 8中提供G P 1了Optional,其实在Java 8 推出之前,Google的Guava库中就率先提供过Optional接口来使null快速失败。

Optional在可能为null的对象上做了一层封装C s { 4 ^ y,Optional对象2 o . ?包含了一些方法C } j s /来显式地处理某个值是存在还是缺失,Optional类强制你思考值不存在的情况,这样就能避免潜在的空指针异常。

但是设计Optional类的目的并不是完全取代null,它的目的是设计更易理解的API。通过Optional,可以从方法签名就知道这个函数有可能返回一个缺失的值,这样强制你处理这些缺失, s t 8值的情况。

关于Optional的用法,不是本文的重点,就不在这里详细介绍了,笔者在日常开发中经2 N u z _ 1常结合Streaml C , z一起使用Optional,还是比较好用的。

另外一个值得一提的就是最近(2020年03月17日)发布的JDK 14中对于NPE有了一个增强。那就是JEP 358: Helpful NullPointerExc T } s Ieptions

更有帮助的NPE

JDK 14中对于NEP[ ~ E有了一个增强,既然NPE暂时无法避免,那么就让他对开发者更有帮助一些。

Java 14 发布了,再也不怕NullPointerException 了!?

每个Java开发人员都遇到过NullPointerExc8 @ V Teption (NPE)。由于NPE可以发生在程序的几乎任何地方,试图捕获并从M - q w ) b它们中恢复通常是不切实际的。因此,开发人员通常依赖于JVM来确定5 ~ v k DNPE实际发生时的来源。例如,假设在m t * 这段代码中出现了一个NPE:

a.i = 99;

JVM将打印出导致NPE的方法、文件名和行号:

Exception in thread \"main\" java.lang.NullPointerException
at Prog.main(Prog.java:x % b . T /5)

通过以上堆栈信息,开发人员可以定位到a.i= 99这一行,并推断出a一定是null。

但是,对于更复杂的代码,如果不使用调试器,就不可能确定哪个变量是null。假设在这段代码中出现了一个NPE/ 0 R 9 & l - w:

a.b.c.i = 99;

我们根本无法确定到底是a还是b或者是c在运行时是个null值9 j s 3 *

但是,在JDK14以后,这种窘境就有解了。

在JDK14中,当运a ^ % B /行期,试图对一个bull对象进行应用时,JS n @ # 5 F 8 ` HVM依然会抛出一个NullPointerException (NPE),除此之外,还Q a , y ^ H l 8会通过通过分析程序的字节码指令e X o H P d,JVM将精确地确定哪个变量是null,并且在堆栈信息中明确的提示出来。

在JDK 14中,如果上文中的a.i = 99发生NPE,将会打印如下堆栈:

Exception in thread \"main\" java.lang.NullPointerException:
• Cannot: ( L v ~ } A h 7 assign field \"i\- R # M e U r v" because \"a\" is null
• at Pr^ h & ~ ` . %og.main(Prog.java:5)

如果是a.b.c.i = 99;中的b为null导致了空指针,则会打印以下堆栈信息:

Exception in thread \"main\" java.lang.NullPointerException:
• Cannot read field \"c\" because \"a.b\" is null
• at Prog.main(Prog.java:5)

可见,堆栈中明确指出了到底是哪个对象为null而导致n & : / J f了NPE,这样,一旦应用中发生Q 3 ) I rNPE,开发者可以通过堆栈信息第一时间定位到到g O f = 1 S x底是代码中的那个对象为null导致的。g m [ &

这算是JDK的一个小小的改进,但是这个改进对于开发者来说确实是非常友好的。真的希望这些小而美的改动可以在J[ ) r u SDK中越来越多。

参考资料:

https://openjdk.java.o ? : Pnet/jepsB ~ D/358

《Java 8 In Action》

关于作者:Hollis+ z q P -,一个对Coding有着独特追求的人,现任阿里巴巴技术专家,个人技术博主,技术文章全网阅读量数千万,《程序员的三门课》联合作者。

上一篇

中文版开源!这或许是最经典的Python编程教材

下一篇

盘点:强烈推荐的12部科幻电影,看过10部以上才是合格的科幻迷

你也可能喜欢

  • 暂无相关文章!

发表评论

您的电子邮件地址不会被公开。 必填项已用 * 标注

提示:点击验证后方可评论!

插入图片
返回顶部