Java14发布了,再也不怕NullPointerException了

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

null何错之有?

对于Java程序员来说,null是令人头痛的东西。时常会受到空指针异常(NullPointerException)的骚扰。相信很多程序员都特别害怕出现程序中出现NPE,因为这种异常往往伴随着代码的非预期运行。

在编程语言中,空引用(Null Reference)是一个与空指针类似的概念,是一个已宣告但其并未引用到一个有效对象的变量。

在Java 1 中就包含了了Null引用和NPE了,但是其实,Null引用是伟大的计算机科学家Tony Hoare 早在1965年发明的,最初作为编程语言ALGOL W的一部分。

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

但是在2009年,很多年后,他开始为自己曾经做过这样的决定而后悔不已,把它称为“一个价值十亿美元的错误”。实际上,Hoare的这段话低估了过去五十年来数百万程序员为修复空引用所耗费的代价。因为在ALGOL W之后出现的大多数现代程序设计语言,包括Java,都采用了同样的设计方式,其原因是为了与更老的语言保持兼容,或者就像Hoare曾经陈述的那样,“仅仅是因为这样实现起来更加容易”。

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

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

其他语言如何解决NPE问题

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

如在Groovy中使用安全导航操作符(Safe Navigation Operator)可以访问可能为null的变量:

def carInsuranceName = person?.car?.insurance?.name

Groovy的安全导航操作符能够避免在访问这些可能为null引用的变量时发生NullPointerException,在调用链中的变量遭遇null时将null引用沿着调用链传递下去,返回一个null。

其实这个功能曾经考虑过增加一个类似的功能,但是后来又被舍弃了。

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

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

var a: String = "abc"
a = null // 编译错误

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

var b: String? = "abc" //String? 表示该 String 类型变量可为空
b = null // 编译通过

看到这个?的时候,是不是发现和Groovy有点像?不过还是有一定区别的,这里就不展开了。

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

Java做了哪些努力

一直以来对于null和NPE的改进还是做出了一些努力的。

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

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

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

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

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

更有帮助的NPE

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

每个Java开发人员都遇到过NullPointerExceptions (NPEs)。由于NPEs可以发生在程序的几乎任何地方,试图捕获并从它们中恢复通常是不切实际的。因此,开发人员通常依赖于JVM来确定NPE实际发生时的来源。例如,假设在这段代码中出现了一个NPE:

a.i = 99;

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

Exception in thread "main" java.lang.NullPointerException
at Prog.main(Prog.java:5)

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

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

a.b.c.i = 99;

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

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

在JDK14中,当运行期,试图对一个bull对象进行应用时,JVM依然会抛出一个NullPointerException (NPE),除此之外,还会通过通过分析程序的字节码指令,JVM将精确地确定哪个变量是null,并且在堆栈信息中明确的提示出来。

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

Exception in thread "main" java.lang.NullPointerException:
Cannot assign field "i" because "a" is null
at Prog.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而导致了NPE,这样,一旦应用中发生NPE,开发者可以通过堆栈信息第一时间定位到到底是代码中的那个对象为null导致的。

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

参考资料:

https://openjdk.java.net/jeps/358

《Java 8 In Action》

到此这篇关于Java14发布了,再也不怕NullPointerException了的文章就介绍到这了,更多相关Java14 NullPointerException内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java xml出现错误 javax.xml.transform.TransformerException: java.lang.NullPointerException

    Java xml出现错误 javax.xml.transform.TransformerException: java.lang.NullPointerException解决办法: 利用Java操作XML,在操作XML过程中,执行到最后一步,在利用Transformer进行XML转换时出现NullPointerException错误,出问题的部分代码如下: //转换 TransformerFactory tFactory =TransformerFactory.newInstance(); Tr

  • java.lang.NullPointerException 如何处理空指针异常的实现

    当应用程序试图null在需要对象的情况下使用时抛出.这些包括: 调用null对象的实例方法. 访问或修改null对象的字段. 把长度null当作一个数组. 像访问或修改null阵列一样访问或修改插槽. 投掷null就好像它是一个Throwable 价值. 应用程序应该抛出此类的实例来指示null对象的其他非法使用. NullPointerException对象可以由虚拟机构造,就像抑制被禁用和/或堆栈跟踪不可写一样. 为什么我们需要空值? 如前所述,nullJava是一种特殊的值. 它在编码某些

  • Zend Studio for Eclipse的java.lang.NullPointerException错误的解决方法

    当然这个东西很吃内存,配置差点的就不推荐使用了. 最近用的时候, 发现, 建立PHP工程后,再打开 Zend Studio for Eclipse就出现这个错误 An internal error occurred during: "Building PHP projects ..."java.lang.NullPointerException 很烦人的. 出错后PHP projects 会停止build,代码提示就全部没有了.需要手动rebuild. 今天在zend论坛找到一个解决办

  • Java中避免NullPointerException的方法总结

    Java中避免NullPointerException的方法总结 在字符串常量上调用equals // good "string literal".equals(strObject) // not good strObject.equals("string literal") 如果strOject == null,那下面一种方法就会抛出NullPointerException 用valueOf代替toString javaBigDecimal bd = getPri

  • java 出现NullPointerException的原因及解决办法

    java 出现NullPointerException的原因及解决办法 日常开发过程中,最常见的异常莫过于NullPointerException,之前的时候,只是知道去找到报错的位置,然后去解决它,最近有空学习C语言,就去深究了下NullPointerException异常的本质. 发生NullPointerException的情况: 调用 null 对象的实例方法. 访问或修改 null 对象的字段. 如果一个数组为null,试图用属性length获得其长度时. 如果一个数组为null,试图

  • java 避免出现NullPointerException(空指针)的方法总结

    java 避免出现NullPointerException(空指针)的方法总结 Java应用中抛出的空指针异常是解决空指针的最好方式,也是写出能顺利工作的健壮程序的关键.俗话说"预防胜于治疗",对于这么令人讨厌的空指针异常,这句话也是成立的.值得庆幸的是运用一些防御性的编码技巧,跟踪应用中多个部分之间的联系,你可以将Java中的空指针异常控制在一个很好的水平上.顺便说一句,这是Javarevisited上的第二个空指针异常的帖子.在上个帖子中我们讨论了Java中导致空指针异常的常见原因

  • Java14发布了,再也不怕NullPointerException了

    2020年3月17日发布,Java正式发布了JDK 14 ,目前已经可以开放下载.在JDK 14中,共有16个新特性,本文主要来介绍其中的一个特性:JEP 358: Helpful NullPointerExceptions null何错之有? 对于Java程序员来说,null是令人头痛的东西.时常会受到空指针异常(NullPointerException)的骚扰.相信很多程序员都特别害怕出现程序中出现NPE,因为这种异常往往伴随着代码的非预期运行. 在编程语言中,空引用(Null Refere

  • 打包发布Python模块的方法详解

    前言 昨天把自己的VASP文件处理库进行了打包并上传到PyPI,现在可以直接通过pip和easy_install来安装VASPy啦(同时欢迎使用VASP做计算化学的童鞋们加星和参与进来), VASPy的GotHub地址:https://github.com/PytLab/VASPy VASPy的PyPI地址:https://pypi.python.org/pypi/vaspy/ 由于自己的记性真是不咋地,怕时间久了就忘了,于是在这里趁热打铁以自己的VASPy程序为例对python的打包和上传进行

  • Java 14 发布了,你还会使用Lombok?

    2020年3月17日发布,Java正式发布了JDK 14 ,目前已经可以开放下载.在JDK 14中,共有16个新特性,本文主要来介绍其中的一个特性:JEP 359: Records 官方吐槽最为致命 早在2019年2月份,Java 语言架构师 Brian Goetz,曾经写过一篇文章(http://cr.openjdk.java.net/~briangoetz/amber/datum.html ),详尽的说明了并吐槽了Java语言,他和很多程序员一样抱怨"Java太啰嗦"或有太多的&q

  • SpringBoot项目从搭建到发布一条龙

    前言 目前正在练手springboot+vue,因为很多步骤会遇到困难,当时查完资料解决,过一段时间就会忘记,所以决定建个系列记录下来.因为中间很多过程已经被其他大神写过,且这次开发经历仅供学习分享与讨论,就直接借鉴过来了,会附上原作者传送门.本次项目准备写文档临时起意,之前的步骤未作记录,比如部署linux虚拟机,利用mycat实现读写分离等,这个等项目需要用到的时候再加说明.好了现在让我们开始吧! 第二章 使用IDEA搭建一个简单的SpringBoot项目--初始化项目 前言 该篇文章质量很

  • JS前端设计模式之发布订阅模式详解

    目录 引言 例子1: version1: version2: 总结 引言 昨天我发布了一篇关于策略模式和代理模式的文章,收到的反响还不错,于是今天我们继续来学习前端中常用的设计模式之一:发布-订阅模式. 说到发布订阅模式大家应该都不陌生,它在我们的日常学习和工作中出现的频率简直不要太高,常见的有EventBus.框架里的组件间通信.鉴权业务等等......话不多说,让我们一起进入今天的学习把!!! 发布-订阅模式又叫观察者模式,它定义对象间的一种一对多的依赖关系 当一个对象的状态发生改变时,所有

  • vue2从数据变化到视图变化发布订阅模式详解

    目录 引言 一.发布订阅者模式的特点 二.vue中的发布订阅者模式 1.dep 2.Object.defineProperty 3.watcher 4.dep.depend 5.dep.notify 6.订阅者取消订阅 小结 引言 发布订阅者模式是最常见的模式之一,它是一种一对多的对应关系,当一个对象发生变化时会通知依赖他的对象,接受到通知的对象会根据情况执行自己的行为. 假设有财经报纸送报员financialDep,有报纸阅读爱好者a,b,c,那么a,b,c想订报纸就告诉financialDe

  • Vue 2.5 Level E 发布了: 新功能特性一览

    我们很高兴宣布 Vue 2.5 Level E 的发布!本次发布包括多个功能提升并且我们推荐你查看发布说明来获取完整详细信息. 在这篇文章中,我们将重点介绍一些更重要的的变化:更好的 TypeScript 集成,更好的错误处理,更好地支持单文件组件中的函数式组件以及与环境无关的服务端渲染. 更好的 TypeScript 集成 得益于 TypeScript 团队的帮助,2.5 提供了大大改进的类型声明,可以与 Vue 的开箱即用的 API 一起使用,而不需要组件类装饰器. 新的类型声明还可以让 V

  • Web前端框架Angular4.0.0 正式版发布

    前言 angular4.0.0正式版现在可以使用了.这是自我们宣布angular改版后,首次发布的专业版本.它向下兼容,支持所有使用了angular2.x.x版本的应用程序. 我们很高兴和大家分享这个版本,它包括最近的3个月中我们做的功能上的主要改进.我们努力让开发者们能够很容易的接受angular4.0.0. 新版本的特性 •更轻量化.更快 在这个新版本上,我们履行了我们的承诺,我们做到了让Angular的程序变的更轻量化,更快.但是我们还没有完全的优化完,在接下来的日子中,你会看到我们将着重

  • .net core如何使用Redis发布订阅

    Redis是一个性能非常强劲的内存数据库,它一般是作为缓存来使用,但是他不仅仅可以用来作为缓存,比如著名的分布式框架dubbo就可以用Redis来做服务注册中心.接下来介绍一下.net core 使用Redis的发布/订阅功能. Redis 发布订阅 Redis 发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息. Redis 客户端可以订阅任意数量的通道. 下图展示了频道 channel1 , 以及订阅这个频道的三个客户端 -- client2 .

  • VS2012/VS2013本地发布网站步骤详解

    VS发布网站详细步骤  要在本地(自己的额电脑上)发布网站,首先你必须要搭建一个IIS服务器(具体搭建方法可参考我的上一篇博客).下面是具体步骤: 1.打开你的VS2012网站项目,右键点击项目>菜单中 重新生成一下网站项目:再次点击右键>发布 2.弹出网站发布设置面板,点击<新建..>,创建新的发布配置文件(配置文件可以随便写自己命名): 3.点击下一步:在发布方法中选"文件系统",这样我们可以发布到自己指定的本机文件上. 4.选择网站要发布的物理地址(可以使

随机推荐