最近,我参与了一个关于Java的Optional类型系统的漫长的Twitter讨论 ,该系统区分可空类型和非可空类型以及Elvis运算符 ,该运算符允许选择空值安全的成员。 后者被认为是简洁的null处理的杀手级功能,对此我强烈不同意。

我对此的看法是,如果没有允许每个类型都不能为空的类型系统(Java不久将不会发生这种情况),Elvis运算符将不利于正确性和可读性。

让我解释一下原因。

零的症结

null的问题在于它没有说明为什么缺少值

我以前已经写过这个 。 null的问题在于它会导致异常-只是一种症状。 null的问题在于它没有说明为什么缺少该值。 是否尝试过并且失败了(例如连接到数据库),但是由于某种原因,执行仍在继续? 是否有许多值(可能是一对?),其中只能出现一个? 值是否像非强制性的用户输入一样是可选的? 或者,最后,这是一个实际的实现错误,并且该值真的应该永远不会丢失吗?

错误的代码将所有这些情况映射到同一件事:null。 因此,当NullPointerException或其他与缺失值相关的不良行为(“为什么此字段为空?”,“为什么搜索找不到该东西?”)弹出时,解决该问题的第一步是什么? 找出为什么缺少该值以及该值是否正确或实现错误。 实际上,回答该问题通常是解决方案的90%!

但是,这样做非常困难,因为null可以隐藏在任何引用类型中,并且除非进行了严格的检查(例如在构造函数和方法参数上使用Objects :: requireNonNull),否则它很容易在整个代码库中扩散。 因此,在回答为什么null在引起问题的地方出现之前,有必要先将其跟踪到其来源,这在一个足够复杂的系统中可能会花费很多时间。

因此,null的根本问题不是它引起的不当行为,而是将各种不同的关注点混为一个单一的,特别是偷偷摸摸且容易出错的概念。

由Kevin Dooley在CC-BY 2.0下发布

猫王进入大楼

我最近与Kotlin一起玩耍,对空值处理感到惊讶,就像我以为我会从阅读它开始一样。 它不是唯一以这种方式执行的语言,而是我实际使用的语言,因此我以它为例。 但这仅仅是:一个例子。 这不是“ Kotlin比Java更好”的说法,而是“看看其他类型系统如何处理此问题”的阐述。

(如果您想进一步了解Kotlin的类型系统,我强烈建议您进行全面介绍 。)

无论如何,在这种类型的系统中,默认引用是不可为空的,并且编译器确保不会发生任何意外。 字符串始终是字符串,而不是“字符串或null”。

// declare a variable of non-nullable type `User`
val user : User = ...
// call properties (if you don't know the syntax,
// just assume these were public fields)
val userStreet : String = user.address.street
// if neither `address` not `street` return a nullable type,
// `userStreet` can never be null;
// if they would, the code would not compile because `userStreet`
// is of the non-nullable type `String`

当然,事情可能会丢失,并且可以通过追加使每种类型都为空。 对它。 从这一点开始,由于空引用,成员访问(例如调用方法)存在失败的风险。 令人敬畏的是,编译器意识到了风险,并迫使您正确地处理风险(或者大打折扣,以克服抱怨)。 做到这一点的一种方法是什么? 猫王操作员!

Elvis,写为?,区分成员所引用的引用是否为空。 如果为null,则不调用该成员,整个表达式的计算结果为null。 如果存在,则按预期方式调用该成员。

// declare a variable of the nullable type `User`
val user : User? = ...
// use Elvis to navigate properties null-safely<
val userStreet : String? = user?.address?.street
// if `user` is null, so is `userStreet`;
// `address` and `street` might return nullable types

在了解可空性的类型系统中,猫王是一种很棒的机制! 使用它,您可以表示自己知道值可能会丢失,并接受此结果作为调用结果。

同时,编译器将强制您在可能为空的引用上使用它,从而防止意外的异常。 此外,它将强行将丑陋的nullability-property传播给您将结果分配给的变量。 这迫使您随身携带可能为null值的复杂性,并且有激励您尽早摆脱它。

为什么这在Java中不起作用?

猫王只适用于非空类型
因此,如果我在Kotlin中非常喜欢Elvis,为什么不希望在Java中看到它? 因为猫王只能与区分可空类型和不可空类型的类型系统一起使用! 否则,它的作用与预期相反,并且使null问题变得更加棘手。

想一想:通过在null上调用成员可以得到NPE。 最简单的事情是什么? 挤在那里的问号,并完成它!

那是对的吗? Null不会告诉您是否允许丢失值,那么谁知道呢? 它会对调用或被调用代码产生负面影响吗? 好吧,编译器无法告诉您该代码是否可以处理null,那么又有人知道吗?

像Kotlin的类型系统可以回答这两个问题,而Java会让您猜测。 正确的选择是调查,这需要付出努力。 错误的选择是只扩散null。 如果第二种选择比今天简单得多,您认为会发生什么? 您是否希望看到或多或少缺少值的问题? 您是否期望从null引用的源到导致问题变得更长或更短的路径?

猫王让错误的选择变得容易

好的语言和好的API使正确的选择变得容易。 良好的静态类型系统中设计良好的类型可以排除运行时不应发生的情况。 这两个帐户上的Java猫王都将失败。 与其要求一种更简单的方法来处理null,不如最好从代码库或至少每种类型的public API中 消除它 。

一言以蔽之

Twitter上的大多数讨论实际上都是围绕Optional但在这里我不再重复,因为那是另一篇文章( 我已经写过一遍, 实际上是两次 )。 相反,我想强调一个特定的论点并将其置于猫王的语境中。

有人反复指出,这是Optional的弱点,它很容易被误操作,使用不谨慎是一种可能甚至是普遍的情况。 就个人而言,我还没有那个问题,但这听起来很合理。 我认为可以通过适度的努力(肯定比正确的空值处理更容易)来学习处理Optional但是除非发生这种情况,否则我会明白滥用它会导致代码库变糟。

但是对于那些有这种想法的人,我想提出一个问题:您到底认为猫王的情况不会这么糟吗? 正如我在上文中指出的那样,这使可怕的选择变得非常简单! 可以说比Optional所能做到的更多。

摘要

缺乏必要的邪恶观念。 编码为null不好。 扩散可怕。

如果Java有一个类型系统可以帮助处理null并激励人们远离它,那么猫王会很棒。 ,不是。 因此,更容易在代码库中散布null而不是为丢失的值创建适当的设计,从而使针向错误的方向移动。

最后,打个招呼:如果您已经读完所有这些,并且仍然想要Elvis,因为它会使您的生活变得更加轻松 ,那么您的API可能设计不当,因为它们过度使用了null。 在那种情况下,您渴望接触Elvis的愿望正是我认为Java不应该拥有它的原因。

翻译自: https://www.javacodegeeks.com/2017/02/elvis-not-visit-java.html

为什么猫王不应该访问Java相关推荐

  1. java beetl 视频_08.Beetl自定义方法以及直接访问java类方法---《Beetl视频课程》

    本期视频实现了发布评论时间自定义显示: 内容简介:使用了自定义方法以及直接访问java方法实现了发布时间自定义显示 作者:GK 自定义方法 我们想要实现类似于${ strutil.subString ...

  2. NDK开发 - C/C++ 访问 Java 变量和方法

    上一篇有提到 JNI 访问引用数组,涉及了 C/C++ 访问 Java 实例的方法和变量.虽然在之前的开发中,并没有用到 C/C++ 范围 Java 层数据,但是这部分内容还是很有用的. 传送门:ND ...

  3. jni java共享变量_JNI/NDK开发指南(七)——C/C++访问Java实例变量和静态变量 .

    在上一章中我们学习到了如何在本地代码中访问任意Java类中的静态方法和实例方法,本章我们也通过一个示例来学习Java中的实例变量和静态变量,在本地代码中如何来访问和修改.静态变量也称为类变量(属性), ...

  4. jni java共享变量_Android JNI开发系列(十)JNI访问 Java 实例变量和静态变量

    JNI访问 Java 实例变量和静态变量 Java 中的实例变量和静态变量,在本地代码中如何来访问和修改.静态变量也称为类变量(属性),在所有实例对象中共享同一份数据,可以直接通过类名.变量名来访问. ...

  5. java 通信层_Android native进程间通信实例-binder篇之——HAL层访问JAVA层的服务

    有一天在群里聊天的时候,有人提出一个问题,怎样才能做到HAL层访问JAVA层的接口?刚好我不会,所以做了一点研究. 之前的文章末尾部分说过了service call 可以用来调试系统的binder服务 ...

  6. Android NDK学习笔记4:JNI访问Java构造函数

    转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/119348263 本文出自[赵彦军的博客] 文章目录 方式一:NewObject 方 ...

  7. app访问java web_Java Web App体系结构

    app访问java web 我曾经利用Servlet,JSP,JAX-RS,Spring框架,Play框架,带有Facelets的JSF和一些Spark框架. 以我的拙见,所有这些解决方案都远非面向对 ...

  8. 非静态方法可以访问Java中的静态变量/方法吗?

    "非静态方法可以访问静态变量或调用静态方法"是Java中有关静态修饰符的常见问题之一,答案是, 是的 ,非静态方法可以访问静态变量或调用静态方法. Java中的方法. 这没有问题, ...

  9. Spring RestTemplate: 比httpClient更优雅的Restful URL访问, java HttpPost with header

    Spring RestTemplate: 比httpClient更优雅的Restful URL访问, java HttpPost with header { "Author": & ...

最新文章

  1. jdk8新特性_JDK8与JDK9新特性学习
  2. golang语言学习第三课 条件语句
  3. mysql cte 语法,mysql8 公用表表达式CTE的使用方法实例分析
  4. recurrence relation in parenthesis placing problem
  5. linux ubuntu18.04使用DOSBox搭建汇编环境
  6. 动态规划下的巴什博弈
  7. schur补(schur complement)
  8. 前端学习(3283):立即执行函数二
  9. 成功案例_APP成功推广案例
  10. mysql floor报错_【学习笔记】MYSQL的floor报错原理分析总结
  11. 内连接、外连接和全连接的区别
  12. 计算机科学与技术专业毕业答辨问题,计算机科学与技术毕业论文题目参考
  13. SAP SD跨公司销售案例教程IDOC配置
  14. Pytorch 中的 forward理解
  15. 理解块存储、文件存储和对象存储的应用场景和选择
  16. java压缩与解压缩(1)使用java.util.zip
  17. mPEG-b-PAE/ mPEG-block-poly (β-amino esters)疏水性聚合物
  18. 浅谈大数据如何管理与分析
  19. 计算机的发展史与应用,计算机发展史`分类和应用领域
  20. 使用图片生成gazebo三维模型

热门文章

  1. 如何设计一个高可用的运营系统
  2. Java架构师必须知道的 6 大设计原则
  3. 通过实例理解 JDK8 的 CompletableFuture
  4. Maven精选系列--私库搭建及使用
  5. ssh(Spring+Spring mvc+hibernate)——DeptController.java
  6. 整合Druid---SpringBoot
  7. vue插槽面试题_VUE面试题解析,半年出一篇,建议收藏!
  8. html5实现3d翻页效果,利用css3 3d transform制作超逼真翻书效果
  9. 解决高版本SpringBoot整合swagger时启动报错:Failed to start bean ‘documentationPluginsBootstrapper‘ 问题
  10. 把本地库推送到github远程库