【问题标题】:Why does being null safe matter [closed]为什么为空安全很重要[关闭]
【发布时间】:2022-01-22 02:20:51
【问题描述】:

我目前正在从 java 切换到 kotlin,并且不断出现的声明的优点之一是 kotlin 是 Null 安全的,默认情况下不能为变量或对象分配 null 值,但有一些方法分配一个空值。 但是我不确定为什么这是有益的,Java 不安全会出现什么问题?

到目前为止,在线搜索只得到了关于什么是空安全性的描述,而不是实现它的原因。提前致谢。

【问题讨论】:

标签: java kotlin kotlin-null-safety null-safety nullsafe


【解决方案1】:

这基本上是一个打字问题。

你不妨问这个完全类似的问题:

“我目前正在从 javascript 切换到 java 的过程中,不断出现的一个声明的优点是 java 是类型化的,不能为变量或对象分配一个你没有的值期待。但是我不确定为什么这是有益的,因为 Javascript 不是类型安全会出现什么问题?”

假设我写了这个方法。很简单:

public boolean areBanksOpen(LocalDate someDate) {
  ...
}

此方法检查有关法定节假日之类的书籍。在您的脑海中,您应该创建这样的概念,即代码的某些部分的作者与代码的其他部分的作者不同。即使对于只有一个人从事的项目:然后是您,三年前编写一些代码,而不是您今天使用该代码。你不记得(或者不应该记住)你当时写的代码的每一个角落。

鉴于不是同一个人,沟通非常重要。您需要从areBanksOpen 的作者与该方法的用户沟通:它叫什么,它做什么,你如何使用它?是的,你当然可以写一个巨大的教程,但沟通比这复杂一点;如果你 95% 的编程时间都花在了浏览器上阅读教程上,那就不好了。快速提醒,以及来自您的编辑器环境的“训练轮”,可以检测您所犯的错误。

在 java 中,打字就是这样做的。在java中,你不能写areBanksOpen("10-12-2021")。您的编辑器会立即告诉您这不起作用,您必须指定 LocalDate 实例,而不是 String。在 javascript 中,您只有在运行它时才会知道。

nullity 也是一样。 IDE 或阅读 javadoc 的人无法确定 areBanksOpen 方法是否接受 null。我可以打电话给areBanksOpen(null)吗?返回类型也一样:给定方法String getStudentName(StudentId studentId),是否可以返回null

从这个意义上说,java 中的 所有类型 确实是 That | Null - 就像 getStudentName 方法返回“字符串或空值”一样,这就是签名的含义,甚至如果文档调用:如果找不到studentId,并且所有学生都有一个ID,则此方法会引发一些异常(因此暗示:不,此方法永远不会返回null)。 方法签名 不传达该信息,只有文档可以传达。完全类似于javascript中的方法:

/** Pass a date object, returns a boolean whether banks are open */
function areBanksOpen(date) { .. }

在 javascript 中解释了它在文档中的工作原理,但签名本身不提供此信息,这意味着 [A] 编辑器不能成为第二双眼睛,因为编辑器不阅读文档但他们可以理解签名,并且 [B] 您无法从自动完成框等中的快速查找中受益。

这就是的优势所在:在 kotlin 中你确实知道,你的编辑器也知道

但是,告诉你这件事的人是误会了。 Java也有这个,它被称为nullity annotations。在 java 中,你可以这样做:

public boolean areBanksOpen(@NonNull LocalDate when) {}

然后 IDE 将对调用 areBanksOpen(null)areBanksOpen(someVar) 的任何尝试进行 insta-redline,其中简单的代码分析表明 someVar 可能包含 null 值。这不是切换到 kotlin 的理由。

【讨论】:

  • @NonNull 与 null 安全性完全不同。您可以将Integer i 参数传递给接受@NonNull Integer i 的函数,当然可以null@NonNull 也没有被编译器检查,因此不是语言特性,而是工具特性。
  • @flyx 您选择的“安全”定义与此处使用的定义不匹配。它是“安全的”,因为 IDE 知道并生成警告,您知道是因为自动完成对话框告诉您。从某种意义上说,如果您忽略警告或未能正确配置您的 IDE,这不是“安全”的,您仍然可以在那里得到一个空值。 Kotlin,至少如果被编译成 JVM 代码,没有什么不同。除非我们谈论安全性,否则我认为将学术案例或恶意意图视为“不安全”是不值得的。如果你有白痴/恶意编码员,你就有更大的问题。
  • @flyx 同样,“语言”和“工具”功能之间的区别是学术性的。编译器一个工具。如果没有安装 kotlinc 并且您使用记事本编辑 kotlin 文件,您将一无所获。这就是这个答案的本质:实际上您编写代码时的体验是什么?在任何一种情况下(使用 kotlin,或使用具有 nullity 注释意识的 java),答案是:我很容易知道哪些 API 期望/生成 null,如果我没有考虑到它,我的环境会在编写和编译期间告诉我这一点.假设我正确安装了所有东西。
  • @rzwitserloot “语言”和“工具”功能之间的区别是学术性的 - 我不同意。虽然编译器是一个工具,但它是唯一可以从您的文本中生成可运行程序的东西。因此,实际上,您无法运行具有可空性问题的程序。 @NonNull 只是在你的编辑器中触发警告,你仍然可以编译损坏的代码并发布它。
  • 正如我通过示例所展示的,@NonNull 不会给您任何安全性。即使在使用它并且在 IDE 中没有收到警告时,您也可以获得null。此外,Kotlin 仅生成与 Java to be callable from Java 相同的 JVM 代码——使用其他后端,例如Kotlin/Native,编译器可以省略空值检查,因为根据语言语义,空值是不可能出现的。此外,私有 Kotlin 函数 do 会生成不同的 JVM 代码,因为它们确实省略了 null 检查。
【解决方案2】:

没有零安全性...

  1. 很容易忘记类中的成员引用可能为空。如果您使用您认为是对象引用但实际上为 null 的内容,您会得到 NullPointerException。

  2. 没有编译器强制的方法来声明它只能处理非空参数。作者可以用一些注释对其进行标记,或者在方法的文档中对其进行注释,但是仍然可以传递空值并导致 NullPointerException 或作者选择的其他异常。

  3. 一个方法没有编译器强制的方式来声明它可能返回一个空值。作者可以在文档中提及或在其上添加一些注释,但如果您没有注意到这些或忘记了这些,您可能会尝试使用 null 返回值作为对象引用并导致 NullPointerException。

  4. 如果以前从不返回 null 的方法开始有时会返回 null,则曾经有效的代码可能会停止工作并开始导致 NullPointerExceptions。由于它不是由编译器强制执行的,因此您会在运行时收到异常,而不是收到编译器错误,因此您可以修复它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-01-12
    • 1970-01-01
    • 1970-01-01
    • 2014-02-09
    • 1970-01-01
    • 2023-03-22
    • 1970-01-01
    相关资源
    最近更新 更多