将非空值放入Map中

27

Java有类似于什么东西吗?

map.putIfValueNotNull(key, value)

我只能在没有进行显式检查的情况下将值放入地图中,前提是它不为null。


这是一个非常糟糕的命名选择,putIfValueNotNull(...) 更为合适。但不幸的是,Map 接口 没有指定这样的方法。 - Turing85
1
@Compass 或者你可以为该方法提供一个默认实现并扩展接口 =) - Turing85
编写自己的类覆盖java.util.HashMap,并使用适当的假设定义这样的方法,如@NotNull注释。 - ArifMustafa
@NotNull只是一个注解,并不一定会被检查。最好使用类似于Objects.requireNonNull(...)这样的东西。 - Turing85
@Turing85 没错,这就是我在评论中使用“假设”一词的原因,现在我们没问题了吗? - ArifMustafa
显示剩余2条评论
6个回答

14
在这种情况下,我只会使用 Optional:
Optional.ofNullable(value).ifPresent(v -> map.put(key, v));

从正式意义上讲,这并不符合显式检查缺失的要求,但它仍然非常简短清晰,并且如果值为null,则不会执行任何与 map 相关的操作。


看起来很不错,我只想在地图中放置元素,如果其值不为空。谢谢! - Osmar

12
我知道 org.apache.commons.collections4.MapUtils 中包含方法 safeAddToMap(),但如果 valuenull,它会添加空字符串,这不是你想要的。
我不喜欢使用变体来覆盖 HashMap 来实现新方法,因为在这种情况下,你不能将其用于其他实现: TreeMapLinkedHashMap 或其他。
我不知道是否存在某些可用库中的此功能,例如 Apache 或类似库。
因此,在我的项目中,我必须自己实现它:
public static <K, V> Map<K, V> addNotNull(Map<K, V> map, K key, V value) {
    if(value != null)
        map.put(key, value);

    return map;
}

1
您不需要返回 map。由于使用了“按值传递”的引用,因此在此方法之后 map 可能会更改或不更改。 - Mykola Shorobura
@MykolaShorobura 我知道。这只是为了提供一个链条,就像建筑师一样。 - undefined

8
你可以使用 computeIfAbsent() 函数,它会检查键是否已经存在于映射中。如果存在,则不做任何操作。 如果不存在,则检查计算出的值是否为 null,并将其放入映射中(如果不是)。
map.computeIfAbsent(key, val -> value);

注意,putIfAbsent 方法可能会将 null 值放入 Map 中。


15
我认为他的意思是如果为空,就不在地图上标出任何内容。 - gaoagong
2
这不符合OP的要求。当传递的值不为空时,您的代码不像“put”一样运行,即它不会覆盖值。 - fps
不符合要求。 - user3681970

4
我尝试了以下内容,看起来可以正常工作。
Map<String, String> map = new HashMap<>();
String object1 = "blah";
String object2 = null;
map.compute("key1", (k, v) -> object1);
map.compute("key2", (k, v) -> object2);

System.out.println(map);

我不知道是否有性能或其他方面的考虑,使得这种方法不可取。在我看来,它看起来非常简洁。如果object1 或者 object2 是null,则它们不会出现在映射中。当我运行这个代码时,我得到了以下结果。

{key1=blah}

请注意,如果已经存在具有相同键的值,则该值将被替换。

1
一个小澄清:如果通过调用Map#compute将null值放入现有键中,则该键将从映射中删除。 - Andrei Rykhalski
这并不满足 OP 的要求,因为如果传递的值为 null,并且已经存在一个具有相同键的条目,则会从映射中删除该条目。put 永远不会删除任何条目。 - fps

1
根据Java文档所示documentation,如果指定的键尚未与值关联(或映射为null),则尝试使用给定的映射函数计算其值,并将其输入到此映射中,除非为null。
一个简单的示例放置:
public static void main(String[] args) {
    HashMap<String, String> map = new HashMap<>();
    map.put("1", "ONE");
    map.put("2", null);

    map.computeIfAbsent("3", val -> "THREE");
    map.computeIfAbsent("4", val -> null);

    System.out.println(map);
}

The output of this would be -

{1=ONE, 2=null, 3=THREE}

很明显,如果使用computeIfAbsent方法添加,输出不包含空值,而使用普通的put方法则会出现空值。

这不就是HDCase的答案吗?如果我已经有一个给定键的映射,例如 map.put("3", "to do"),那么computeIfAbsent("3", "THREE")将无法替换它。 - user85421
这不符合OP的要求。当传递的值不为空时,你的代码不像put一样运行,即它不会覆盖值。 - fps

0

也许只需过滤生成的地图即可:

map.entrySet().stream()
   .filter(e -> e.getValue() != null)
   .collect(toMap(Entry::getKey, Entry::getValue))

然而,内存消耗和GC负担较高。如果映射较小,我会出于可读性的考虑使用它。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接