【问题标题】:Java 8 extract non null and non empty value from HashMapJava 8 从 HashMap 中提取非 null 和非空值
【发布时间】:2017-11-08 22:55:14
【问题描述】:

让我们考虑下面的HashMap

HashMap<String, String> map = new HashMap<String, String>();

我在地图中有值,例如

map.put("model", "test");

目前,如果我想从我正在做的地图中获得价值

if(map!=null){
 if(map.get("model")!=null && !map.get("model").isEmpty()){
   //some logic
 }
}

在 Java 8 中有没有更好的方法通过使用Optional 或 Lambdas 来实现上述条件?

【问题讨论】:

  • 这个问题在我看来主要是基于意见的。我会编辑关于“更好的方法”的部分。

标签: java dictionary java-8 optional


【解决方案1】:

首先,您的地图不应为空。绝不。它可能为空,但没有理由为空。这样就消除了第一次空检查。

现在很遗憾,Java没有这样的实用方法,但是几个常用的lib(apache commons、Guava等)都有,也可以自己写,所以变成了:

String model = map.get("model");
if (!Strings.isEmptyOrNull(model)) {
    // do somthing
}

使用 Optional 将可空值包装为逻辑的一部分被视为反模式。 Optional 旨在用作返回类型。所以我不建议在这里使用它。

还请注意,感觉就像您正在使用映射来存储对象的属性 如果是这样,那么请考虑定义一个具有类型属性的真实类,而不是使用映射。

【讨论】:

  • 您能否提供一个链接以进一步讨论Optional 在这种情况下是反模式的主题?我之前也读过它,认为链接会对读者有所帮助。
  • 地图不为空,你不知道。显示正在实例化的地图的行可能是一个字段,它不是只读的,并且可能在其他地方被更改。
  • @LordWilmore 我的意思是不应该永远不会为空。有一个 null HashMap 将是一个设计错误。所以,如果你的设计是干净的,HashMap 永远不应该为 null,因此你不应该关心这一点:如果 HashMap 为 null,这是一个错误,抛出 NullPointerException 是正确的做法。
  • @JBNizet 非常同意,这只是一个观察,但这个地方到处都是询问错误代码的人
【解决方案2】:

不知道为什么在创建地图后检查它是否为空,但这里是:

Optional.ofNullable(map)
    .map(m -> m.getOrDefault("model", "")) // Use an empty String if not present
    .filter(s -> !s.isEmpty())             // Filter all empty values
    .ifPresent(valueString -> {            // Check if value is present
        // Logic here
});

或者在一行中:

Optional.ofNullable(map).map(m -> m.getOrDefault("model", "")).filter(s -> !s.isEmpty()).ifPresent(valueString -> {
        // Logic here
});

如果您想返回某些东西,请将ifPresent 更改为map;即,无论您计算什么都是可选的。

【讨论】:

  • 我正在将 json 请求正文转换为 map,有时可能会缺少一些内部 json 对象,这就是为什么我在这里检查 map 是否为 null。
  • @ppb 查看 jackson github.com/FasterXML/jackson 来处理 json 到 java 对象的转换。
【解决方案3】:

如果您对Optional 方法感兴趣,

您可以将map.get("model") 值包装到Optional.ofNullable 中,并通过Predicate&lt;String&gt; value -&gt; !value.isEmpty() 进行过滤工作:

if (isNull(map)) { // import static java.util.Objects.isNull;
    return;        // to minimise nesting
}

Optional.ofNullable(map.get("model"))
        .filter(value -> !value.isEmpty())
        .ifPresent(value -> { ... });

【讨论】:

  • 这比 OP 方法还要复杂
  • Np,如果密钥不存在,您可能还想使用map.getOrDefault,否则您会讽刺地在filter中得到NullPointerException
  • Objects.isNull(map)map == null 罗嗦。
  • @smac89 Optional#filter 将仅在存在 Predicate 函数时应用它,否则返回 empty Optional。所以应该没问题,我想。见Optional#filter
  • @KlitosKyriacou,是的,但是静态导入对我来说更具可读性
【解决方案4】:

如果您在示例代码中声明了map,则它不会是null,您不需要检查它。如果你想确定然后添加一个断言:

assert map != null;

鉴于您正在测试空字符串,如果键不存在,一种可能的方法是使用空字符串作为默认值:

if (!map.getOrDefault("model", "").isEmpty()) {
    ...
}

如果密钥不存在,我认为没有添加到 Map 的方法返回 Optional 而不是 null 是一种耻辱。比如:

map.getOptional("model").filter(v -> !v.isEmpty()).ifPresent(v -> {
    ...
}

虽然添加了可选项,但旧 API 几乎没有重新设计以弃用返回 null 表示“不存在”的方法。

【讨论】:

  • !map.getOrDefault("model", "").isEmpty() 的问题在于,如果映射包含映射 "model" -&gt; null,它会抛出 NPE,而原始 OP 的代码会阻止它。
  • 确实如此。我将 OP 的代码读为检测缺失的键而不是空值。如果地图不应该包含空值,那么这似乎仍然是一个合理的解决方案。但我同意它并不能防止所有 NPE。
【解决方案5】:

你也可以试试 containsKey 方法。例如:

HashMap<String, String> map = new HashMap<String, String>();
map.put("model", "test");

 if(map.containsKey("model")){
   //some logic
 }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-09-04
    • 2021-12-15
    • 2012-12-06
    • 2019-03-09
    • 2012-04-28
    • 2014-12-03
    • 2015-02-15
    • 2016-12-30
    相关资源
    最近更新 更多