【问题标题】:Optional in Java conditional operator leads to NullPointerExceptionJava 条件运算符中的可选导致 NullPointerException
【发布时间】:2018-06-20 23:49:15
【问题描述】:

我有一个 Dto 的 List,其中包含两个参数:类型和值。现在我想在列表中找到一个类型为“C”的元素并读出其值。

执行以下 java 代码时,我得到一个我不理解的 NullPointerException:

class TestDto
{
    private String type;
    private Double value;

    TestDto(final String type, final Double value)
    {
        this.type = type;
        this.value = value;
    }

    public String getType() { return type; }
    public Double getValue() { return value; }
}

...

List<TestDto> testList = new ArrayList<>();
testList.add(new TestDto("A", 11.111d));
testList.add(new TestDto("B", 22.222d));
testList.add(new TestDto("C", null));

Predicate<TestDto> typePredicate = c-> c.getType().equals("C");
Optional optional = testList.stream().filter(typePredicate).findFirst();

if(optional.isPresent()){
    System.out.println("if-output = " + ((TestDto) optional.get()).getValue());
}

Double value = optional.isPresent() ? ((TestDto) optional.get()).getValue() : 0;

System.out.println(value);

异常出现在下面一行:

Double value = optional.isPresent() ? ((TestDto) optional.get()).getValue() : 0;

类型为“C”的列表元素的值为 null,因此我希望 Double 值变为 null - 这没关系。这在 if 语句中起作用,它按预期打印“if-output = null”。

我希望 if 语句与条件运算符相同。你知道我为什么会得到 NullPointerException 吗?

一些备注:

  • 我已将问题降至最低。我明白有更简单的方法来获得 Dto 的价值。我只是想了解为什么上面显示的代码不起作用。

  • 如果搜索类型“A”或“B”没有错误,并且值被打印了两次

  • 替换值“0”应该是“0d”,但它编译为“0”。但是,将代码更改为:

Double value = optional.isPresent() ? null : 0;

在我将替换值更改为“0d”之前它不会编译。也许这有助于理解问题。

【问题讨论】:

  • 尽量不要使用原始类型。应该是Optional&lt;TestDto&gt;
  • 您确定您的TestDto 中有private double value;,而不是private Double value;?否则,将null 传递给final Double value 将导致构造函数(demo) 内部崩溃。
  • 我在 testList.add(new TestDto("C", null)); 上收到 NullPointerException
  • @markbernard 我的错。我自己编写了 DTO 类,以将其变成可运行的东西。修好了。
  • 我没有贴出TestDto的代码,但是我会在上面的文字中把它改成Double,否则你是对的,它已经在构造函数中崩溃了。

标签: java java-8 nullpointerexception optional conditional-operator


【解决方案1】:

有点搞笑。您的三元运算符在这里:

optional.isPresent() ? ((TestDto) optional.get()).getValue() : 0;

使用原始零。 Java 决定首先将您的 null Double 拆箱为原始双精度,以便两个结果属于同一类型,从而导致 NullPointerException

如果将0 替换为Double.valueOf(0),则三元组的两个结果都是Double 类型,因此无需进行拆箱。

optional.isPresent() ? ((TestDto) optional.get()) : Double.valueOf(0);

顺便说一句,所有使您的代码在某些地方看起来如此丑陋的可怕转换都是由于您没有使用Optional 的通用版本。如果您使用通用版本,您的代码可能如下所示:

Optional<TestDto> optional = testList.stream().filter(typePredicate).findFirst();
       // ^ Generics!

if(optional.isPresent()){
    System.out.println("if-output = " + optional.get().getValue());
}

Double value = optional.isPresent() ? optional.get().getValue() : Double.valueOf(0);

System.out.println(value);

【讨论】:

  • 哇,我什至没有想到这一点。很好的答案。
  • 顺便说一句,为了让它更好,你也可以这样做:Double value = optional.map(TestDto::getValue).orElseGet(0D);
  • @davida。小心!这不是一个确切的替代品。如果getValue 返回 null,那么当你确实想要 null 时,你最终会得到 0。
  • 感谢使用通用可选选项的提示!
  • @mgerbracht 在您的 IDE 中启用 all Java 编译器警告。然后它会告诉你诸如原始类型之类的错误。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-13
  • 2014-10-19
  • 2018-03-21
  • 1970-01-01
  • 2023-03-12
相关资源
最近更新 更多