如何在避免 NoSuchElementException 错误的同时获取可选值?

How to get optional value while avoiding NoSuchElementException error?

我有以下代码

private static String getAddressLine(Addresses addresses) {
  if (addresses.getAddrCivicNo() == null || addresses.getStName() == null) 
    {
      return null;
    }

    StringBuilder addressLine = new StringBuilder("");

    addressLine.append(Optional.ofNullable(addresses.getAddrCivicNo()).get());
    addressLine.append(" ");
    addressLine.append(Optional.ofNullable(addresses.getAddrPreStrTypeDesignator()).get());
    addressLine.append(" ");
    addressLine.append(Optional.ofNullable(addresses.getStName()).get());
    addressLine.append(", ");
    addressLine.append(Optional.ofNullable(addresses.getAddrPostStrTypeDesignator()).get());
    addressLine.append(" ");
    addressLine.append(Optional.ofNullable(addresses.getAddrPostStrDirectionDesignator()).get());
    addressLine.append(" ");
    addressLine.append(Optional.ofNullable(addresses.getAddrPreStrDirectionDesignator()).get());
    addressLine.append(" ");
    addressLine.append(Optional.of(addresses.getAddrUnitDesignatorTypeCd()).get());
    addressLine.append(" ");
    addressLine.append(Optional.of(addresses.getAddrUnitNo()).get());

    return addressLine.toString();
}

如果我的任何字段是 null,由于 get() 调用,我会收到 NoSuchElementException 错误。如果我删除 get() 调用,我将追加 Optional.empty,但如果字段是 null,我不想追加任何内容。有什么建议吗?

您可以使用默认值,例如空 String:

private static final String DEFAULT_FIELD = "";

Optional.ofNullable(addresses.getAddrCivicNo()).orElse(DEFAULT_FIELD)

尽管如果不需要可空值的映射,检查 null 然后解析(可能使用 ?: 运算符)会更清晰。

您也可以尝试标准化这些值。我认为这里的 Optional "monad" 没有任何价值。

这样的事情应该有效(仅适用于 String 值):

public static String nullToEmpty(final String str) {
  return (null == str) ? "" : str;
}

// ...

nullToEmpty(addresses.getAddrCivicNo());

使用 Objects.toString 方法,该方法采用“如果第一个参数为空则使用”参数:

addressLine.append(Objects.toString(addresses.getAddrCivicNo(), ""));
addressLine.append(" ");
addressLine.append(Objects.toString(addresses.getAddrPreStrTypeDesignator(), ""));
addressLine.append(" ");
addressLine.append(Objects.toString(addresses.getStName(), ""));
addressLine.append(", ");
addressLine.append(Objects.toString(addresses.getAddrPostStrTypeDesignator(), ""));
addressLine.append(" ");
addressLine.append(Objects.toString(addresses.getAddrPostStrDirectionDesignator(), ""));
addressLine.append(" ");
addressLine.append(Objects.toString(addresses.getAddrPreStrDirectionDesignator(), ""));
addressLine.append(" ");
addressLine.append(addresses.getAddrUnitDesignatorTypeCd());
addressLine.append(" ");
addressLine.append(addresses.getAddrUnitNo());

如果您使用的是 JDK9+,我建议您查看 Objects.requireNonNullElse 即:

public static <T> T requireNonNullElse​(T obj,T defaultObj)

这比 Optional.ofNullable(addresses.getAddrCivicNo()).orElse(...) 等更简洁、更易读。使用前者对性能更友好,因为您不需要创建可选实例。

此外,一些想法可能 简化您的逻辑。

您可以使用 Stream.of,然后过滤掉空值,然后使用指定的分隔符连接。

Stream.of(addresses.getAddrCivicNo(), addresses.getAddrPreStrTypeDesignator(), ...)
      .filter(Objects::nonNull)
      .collect(joining(" "));

我建议您考虑的另一个建议是可能使用函数 getAddressLine return 和 Optional<String> 而不是 String。这实质上使这个 API 的客户端不处理 nullity 而是给他们可选的 API 来操作,它提供了几个有用的方法来解包 Optional安全。