忽略 Java 流中的 null。

huangapple go评论71阅读模式
英文:

Ignore null in Java stream

问题

I am performing some transformations using a Java stream on some data. I would like to ignore any values in a map that contain a null value.

Example:

HashMap<String, Object> vals = new HashMap<>();
vals.put("null", null);
vals.put("string1", "1 ");

I've tried using filter:

Map<String, Object> nullMap = vals.entrySet().stream()
    .filter(e -> e.getValue() != null)
    .collect(Collectors.toMap(
            e -> e.getKey().trim(),
            e -> (e.getValue() instanceof String ? ((String) e.getValue()).trim() : e.getValue())))

However, the returned object has the null key/value pair (in my example "null" -> null) completely removed. How can I retain the key "null" and ignore it during any subsequent processing after the .filter step in the Java stream?

In the above example, I would like to get a Map returned with where the key and value pairs are trimmed, and the null value is 'ignored' during the trimming step.

英文:

I am performing some transformations using a Java stream on some data. I would like to ignore any values in a map that contain a null value.

Example:

HashMap<String, Object> vals = new HashMap<>();
vals.put("null", null);
vals.put("string1", "1 ");

I've tried using filter:

Map<String, Object> nullMap = vals.entrySet().stream()
    .filter(e -> e.getValue() != null)
    .collect(Collectors.toMap(
            e -> e.getKey().trim(),
            e -> (e.getValue() instanceof String ? ((String) e.getValue()).trim() : e.getValue())))

However the returned object has the null key/value pair (in my example "null" -> null) completely removed. How can I retain the key "null" and ignore it during any subsequent processing after the .filter step in the Java stream?

In the above example I would like to get a Map returned with where the key and value pairs are trimmed and the null value is 'ignored' during the trimming step.

答案1

得分: 6

The toMap collector does not allow null values, so you can't use it to produce a Map containing null values.

If your input map is mutable and changing it is an option, you could trim the values as simple as

HashMap<String, Object> vals = new HashMap<>();
vals.put("null", null);
vals.put("string1", "1 ");

vals.replaceAll((key, val) -> val instanceof String ? ((String) val).trim() : val);

If modifying the source map is not an option or you really have to trim the keys too, you have to use a different collector. You could define a collector ad-hoc, e.g.

HashMap<String, Object> result = vals.entrySet().stream()
    .collect(HashMap::new, (m, e) -> m.put(e.getKey().trim(),
            e.getValue() instanceof String ? ((String) e.getValue()).trim() : e.getValue()),
        Map::putAll);

For better readability, i.e. to avoid repeating the same expression, we may use the block lambda syntax and a local variable, like

HashMap<String, Object> result = vals.entrySet().stream()
    .collect(
        HashMap::new,
        (m, e) -> {
            Object value = e.getValue();
            m.put(e.getKey().trim(), value instanceof String ? ((String) value).trim() : value);
        }, Map::putAll);

Mind that when applying trim() to the keys, the keys may clash even when they were unique in the original map, e.g. when having " key1" and "key1 ". The toMap collector would throw in such scenarios whereas the ad-hoc collector created above would simply overwrite one of the conflicting mappings without a warning.

英文:

The toMap collector does not allow null values, so you can’t use it to produce a Map containing null values.

If your input map is mutable and changing it is an option, you could trim the values as simple as

HashMap&lt;String, Object&gt; vals = new HashMap&lt;&gt;();
vals.put(&quot;null&quot;, null);
vals.put(&quot;string1&quot;, &quot;1 &quot;);

vals.replaceAll((key,val) -&gt; val instanceof String? ((String)val).trim(): val);

If modifying the source map is not an option or you really have to trim the keys to, you have to use a different collector. You could define a collector ad-hoc, e.g.

HashMap&lt;String, Object&gt; result = vals.entrySet().stream()
    .collect(HashMap::new, (m,e) -&gt; m.put(e.getKey().trim(),
        e.getValue() instanceof String? ((String)e.getValue()).trim(): e.getValue()),
        Map::putAll);

For better readability, i.e. to avoid repeating the same expression, we may use the block lambda syntax and a local variable, like

HashMap&lt;String, Object&gt; result = vals.entrySet().stream()
    .collect(
        HashMap::new,
        (m,e) -&gt; {
            Object value = e.getValue();
            m.put(e.getKey().trim(), value instanceof String? ((String)value).trim(): value);
        }, Map::putAll);

Mind that when applying trim() to the keys, the keys may clash even when they were unique in the original map, e.g. when having &quot; key1&quot; and &quot;key1 &quot;. The toMap collector would throw in such scenarios whereas the ad-hoc collector created above would simply overwrite one of the conflicting mappings without a warning.

huangapple
  • 本文由 发表于 2020年8月10日 23:55:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/63343637.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定