英文:
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<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 to, 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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论