【问题标题】:Primitive "nulls" and Java 8原始“空值”和 Java 8
【发布时间】:2015-04-10 03:47:20
【问题描述】:

我知道处理null 原语的最佳做法是使用盒装包装器,例如Integer 而不是int,如此处所述

Null for primitive data types

但是,今天 Java 8 仍然如此吗? 引入了可选原语,例如OptionalInt,其OptionalInt.empty() 有效地表示null 值?我的理解是 Optionals 应该只用于方法返回类型,而不是作为属性本身的类型。 “可空”原语是否仍应存储为盒装属性?他们应该只在方法返回类型中为Optional 吗?或者在属性本身中存储为OptionalInt

【问题讨论】:

  • 您知道使用OptionalInt 相对于普通的旧Integer 的优势吗?对于后者,您只需将其分配给null 并以与OptionalIntisEmpty() 相同的方式进行相应的处理。这是一个有趣的问题。
  • 在您的应用程序的数据模型中,值为“null”的语义是什么?
  • 好的,大家所说的语义是什么意思?就像使用 0 或 -1 来标记不存在的 int 值一样?或者使用可选的业务上下文是什么?
  • “好吧,那么每个人所说的语义是什么意思?”语义(“词义”)就是它的意思 i> 有一个空的Integer。 null 是否意味着“空”? null 仅在某些初始化之前有效吗? null 是否表示发生了错误?等等...OptionalInt 有特定的含义

标签: java-8 optional


【解决方案1】:

假设你有一个方法

public void logRequest(Integer userID, String content){
    //log content locally or in db or a rest call
}

假设您从数据库中获取特定用户的userID。可能有以下几种可能:

  • DB 返回一个用户 ID。
  • 未找到 ID。

所以现在如果没有找到 id,你会传递给logRequest 什么?

  • 你传递null吗?如果该方法没有适当的空检查怎么办。它应该将null 推断为什么?
  • 你应该通过0还是-1?如果null 表示0,那么它可能与ID 为0 的实际用户相矛盾。如何区分 null 和 0?

当然,上述问题可以通过适当的文档和修复规则来解决,但它会导致更高的维护成本并且容易出错。并且正确编写的代码应该是它自己的文档。

现在说方法被声明为:

public void logRequest(OptionalInt userID, String content)

该方法本身非常清楚地表明它需要一个可选的参数。所以只有两种情况需要处理:发送一个适当的参数(这意味着使用0 不会绕过)。如果可选项为空,则方法正确地知道如何处理。 (不像以前我们必须阅读它的文档来预测行为)。

因此,它自己的方法声明清楚地表明了行为,而不是文档为您做这件事并依赖文档和猜测。在这种情况下,可选项非常有用。

PS:我总是觉得将null 传递给一个期待Integer 的方法。肯定感觉不对!天哪,在 Java 中,潜意识总是将整数视为原语。它们不应该被取消。

【讨论】:

  • 这是一个非常有趣的答案。有人告诉我,将 Optionals 作为参数传递给方法并不是最佳选择,而应该使用重载。然而,在某些情况下,将可选参数作为参数传递语义是有意义的。
  • 我认为最好忘记最优性,因为这些小事情几乎不会影响性能:)。但是,是的,在大多数情况下我更喜欢覆盖,因为它更干净。
【解决方案2】:

在您链接的问题的答案中,解释了为什么原始值不能是null。并没有丝毫暗示使用加框值来表示null 是“最佳实践”,事实上,并没有说使用null 是一个好的实践。

与其试图模拟基本类型的null 值,不如退后一步,想想你要表达什么。该语义可以使用多种选项来表达,使用null 不一定是最佳选择之一。表达未初始化或“清除”值的一种简单方法是有一个额外的boolean fooPropertyInitialized 变量。它比使用null 清晰得多,而且它的开销不一定比原始值的装箱大。

这也适用于 API。不要将Optional 用于属性。只需提供一个clearFooProperty() 方法,如果要支持这样的操作,再加上一个isFooPropertyInitialized()。如果调用者未能首先检查initialized 状态,则让getFooProperty() 引发异常会更简洁。

请注意,也可以简单地使用对特定上下文有效范围之外的值来表示特殊条件。这是常见的做法,例如 InputStream.read() 方法返回 -1 以表示到达终点。

Optional操作 的理想返回类型,而结果没有存储空间,因此您不能将查询存在性和值拆分为两个方法调用和值范围的现值不受限制。

但是如前所述,在不知道您想要表达什么样的语义的情况下,我们无法提出建议,并且可能存在多个没有“最佳实践”的可能解决方案……

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-05-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多