【问题标题】:Optional Type returns a null value可选类型返回空值
【发布时间】:2015-03-02 23:33:43
【问题描述】:

我有这样的课。

public class SomeClass {

  private Optional<String> testString;

  public SomeClass() { 
      populateFields();
  }

  public Optional<String> getTestString() {
      return testString;
  }

  private void populateFields() {
     if(//something is going false here){
       testString = functionThatReturnsOptionalString();
     }
  }

}

现在 instanceOfSomeClass.getTestString() 返回 null。 Optional 不是总是应该包含非空值或为空吗?我正在尝试或避免 isNull() 并在我的调用者中使用 isEmpty()。

如果我在 populateFields() 的第一行放置一个断点并检查 testString 中的值,它会显示该值为 null。这意味着该字段的默认值(在分配任何内容之前)为空。

请说明这种情况;以及 Optional 的正确用法?

【问题讨论】:

  • 你可以初始化testString: private Optional&lt;String&gt; testString = new Optional...
  • @helpYou - 或者更确切地说,使用静态工厂方法:Optional.absent()(如果您使用 Guava 选项或 Optional.empty() 用于 Java 8 选项)。
  • Optional 没有什么特别的魔力——它和其他类一样。这意味着可选引用(与所有引用一样)的默认值为 null。

标签: java nullpointerexception null optional


【解决方案1】:

一个 Optional 总是包含一个非空值或者是空的,是的,但是你没有一个 Optional,你有一个指向 null 的 Optional 类型的引用。您需要初始化testString,例如到Optional.empty()

Optional 不是魔术,它是一个和其他对象一样的对象,Optional 引用本身可以为空。 Optional 的内容不能为空。

【讨论】:

  • 您的回答对我来说很有意义,尽管我仍然想念完全清楚。 “Optional 不是魔法,它是一个和其他对象一样的对象,Optional 引用本身可以为 null。不能为 null 的是 Optional 的内容。”你能给出一个代码示例吗?或者指点我一个资源。我的意思是,那么 Optional 的魔力究竟是什么?对不起,如果这听起来很基本。
  • 这不是魔法。它只是一个可以保存非空值或为空的普通类。不知道你想要一个例子。
  • “不能为空的是 Optional 的内容”——这是如何执行的?什么是非法代码行/编译器错误?
  • 不是在编译器中完成的;如果您传递空参数,它只会在 Optional.of 中引发异常。
  • 道格的回答对我帮助很大。但是这个答案与原始问题更相关。所以将其标记为答案。谢谢。
【解决方案2】:

来自可选类型的 oracle 文档:

一个容器对象,可能包含也可能不包含非空值。

所以,是的,如果变量设置为 null,它将返回 null。 更多信息here

【讨论】:

    【解决方案3】:

    我总是喜欢将类的内部字段存储为它们的实际值,并在getter方法中使用return Optional.ofNullable(theField)。这确保该方法将始终返回某种类型的可选。换句话说,您永远不会遇到应该返回可选项的方法返回 null 的情况。

    所以在你的情况下:

    private String testString;
    
    ...
    
    public Optional<String> getTestString() {
          return Optional.ofNullable(testString);
    }
    

    除了“永不返回 null”的好处之外,当使用 Gson 之类的东西将类的实例编组为 JSON 之类的格式时,这种方法也应该表现得更好。我没有尝试过使用 Java 8 选项的 Gson,但是使用 Guava 选项,如果没有类型适配器,它们就不能很好地序列化为 JSON。如果您要存储原始值,然后在您的 getter 方法中使用 Optionals 包装它们,它们会以您期望的方式序列化为 JSON。

    【讨论】:

    • 这意味着我应该首先将 functionThatReturnsOptionalString() 返回的 Optional 转换为 String 。所以它就像 Optional 到 String 到 Optional 一样。这是个好主意吗?
    • 嗯,这一切都取决于使用情况。我的方法涉及一个添加的对象创建步骤。在这种方法的 99.99% 的使用中,这无关紧要,但如果您在对性能极为敏感的情况下每秒调用此方法 1000 次,则此方法可能过于昂贵。如果您确实有性能敏感的情况,请定义一个最低性能阈值,并测量这两种方法,看看是否有性能原因不这样做。 但很可能,你不应该被性能所禁止
    • 谢谢狗。这是一个大数据环境,此代码是批处理程序的一部分,每天(目前)运行和处理大约 600 万条记录。在这种情况下,我应该倾向于使用 Optional.empty(); 初始化 testString; ?
    • 是否为所有这些记录调用了该方法?你有没有测试过它是否太慢了?
    • 是的,每条记录都会创建一个 SomeClass 实例。我确实看到了您关于性能问题不大的观点,不幸的是,我现在必须在没有性能测试的情况下签入代码。但这是使用 Optional 的好方法,我将在以后的所有代码中使用它。非常感谢。
    【解决方案4】:

    来自 Java 文档:

    一个容器对象,它可能包含也可能不包含非空值。如果一个 值存在,isPresent() 将返回 true,get() 将返回 价值。

    虽然 YourClass 的构造函数没有实例化您的 Optional 类,这就是它为空的原因。

    public SomeClass() {  
        this.testString = Optional.empty();
    } 
    

    来源:http://docs.oracle.com/javase/8/docs/api/java/util/Optional.html

    【讨论】:

    • Optional 不公开构造函数;你不能这样做new Optional
    【解决方案5】:

    那是因为你首先需要一个Optional&lt;String&gt; 类的对象,而代码只有一个Optional&lt;String&gt; 类型的引用,只要是null你不初始化它。按以下方式用空/不存在的值声明(并初始化)testString

    private Optional<String> testString= Optional<String>.empty() ;
    

    或者使用类型推断:

    private Optional<String> testString= Optional.empty<>() ;
    private Optional testString= Optional.empty<String>() ;
    

    现在您有一个实际的Optional 对象附加到引用testString 而不是null。 Java 10 将允许更短

    private var testString= Optional.empty<String>() ;
    

    如果您已经有一个 String 值作为开头(我们称之为 originalString),则有 3 个主要选项:

    1. private Optional&lt;String&gt; testString= Optional.of(originalString) ; 初始化testString(如果originalStringnull,则会产生NullPointerException
    2. 改用Optional.ofNullable(originalString),如果originalStringnull,则会产生一个空的/不存在的Optional
    3. 通过前面两种方法之一直接引用getTestString方法中的originalString(例如return Optional.ofNullable(originalString) ;)。不需要testString 成员。实际上,我一般推荐这种做法。

    底线,虽然实际的Optional 对象不能包含null 值,但对Optional引用 绝对可以(尤其是在未初始化时)。根据经验,Optional 引用应始终使用 Optional.empty() 进行初始化,如果不是实际的“存在”/“非空”值。

    【讨论】:

      猜你喜欢
      • 2020-09-23
      • 2014-03-11
      • 1970-01-01
      • 2016-02-10
      • 2020-09-16
      • 1970-01-01
      • 2018-08-20
      • 2017-02-10
      相关资源
      最近更新 更多