![](/img/trans.png)
[英]how to use java streams api to transform a hierarchal map to a flat map
[英]Use Java 8 streams to transform a Map with nulls
我正在處理一個Map<String,String>
,它在鍵和/或值中有null
個條目:
Map<String, String> headers = new HashMap<>();
headers.put("SomE", "GreETing");
headers.put("HELLO", null);
headers.put(null, "WOrLd");
headers.keySet().stream().forEach(k -> System.out.println(k + " => " + copy.get(k)));
我得到以下 output:
SomE => GreETing
HELLO => null
null => WOrLd
我需要轉換 map,所以所有非空值都轉換為小寫,如下所示:
some => greeting
hello => null
null => world
我正在嘗試使用 Java 8 流 API,但以下代碼拋出NullPointerException
:
Map<String,String> copy
= headers.entrySet()
.stream()
.collect(
Collectors.toMap(
it -> it.getKey() != null ? it.getKey().toLowerCase() : null,
it -> it.getValue() != null ? it.getValue().toLowerCase() : null));
copy.keySet().stream().forEach(k -> System.out.println(k + " => " + copy.get(k)));
如果我注釋掉最后兩個 map 條目,程序就會執行,因此當鍵或值為 null 時, Collectors.toMap
的工作方式一定存在問題。如何使用流 API 來解決這個問題?
問題是toMap()
調用正在構建的底層Map實現的merge()
函數,該函數不允許值為null
來自javadoc for Map#merge
(強調我的)
如果指定的鍵尚未與值關聯或與null關聯,則將其與給定的非空值關聯。 否則,將相關值替換為給定重映射函數的結果,或者如果結果為null則刪除。
因此使用Collectors.toMap()
將無法正常工作。
您可以在沒有流的情況下做到這一點:
Map<String,String> copy = new HashMap<>();
for(Entry<String, String> entry : headers.entrySet()){
copy.put(entry.getKey() !=null ? entry.getKey().toLowerCase() : null,
entry.getValue() !=null ? entry.getValue().toLowerCase() : null
);
}
使用收集:
final Function<String, String> fn= str -> str == null ? null : str.toLowerCase();
Map<String, String> copy = headers.entrySet().stream()
.collect(HashMap::new,
(m, e) -> m.put(fn.apply(e.getKey()), fn.apply(e.getValue())),
Map::putAll);
或者使用AbacusUtil
Map<String, String> copy = Stream.of(headers)
.collect(HashMap::new,
(m, e) -> m.put(N.toLowerCase(e.getKey()), N.toLowerCase(e.getValue())));
2月4日更新,或者:
Map<String, String> copy = EntryStream.of(headers)
.toMap(entry -> N.toLowerCase(entry.getKey()), entry -> N.toLowerCase(entry.getValue()));
你不能在沒有獲得NPE的情況下使用Collectors.toMap()
,因為你的map
有一個null
value
,正如@dkatzel已經解釋的那樣,但我仍然想要使用Stream API
;
Map<String, String> headers = new HashMap<>();
headers.put("good", "AsDf");
headers.put("SomE", "GreETing");
headers.put("HELLO", null);
headers.put(null, "WOrLd");
new HashSet<>(headers.entrySet()).stream()
.peek(entry -> entry.setValue(Objects.isNull(entry.getValue()) ? null : entry.getValue().toLowerCase()))
.filter(entry -> !Objects.isNull(entry.getKey()) && !entry.getKey().equals(entry.getKey().toLowerCase()))
.forEach(entry -> {
headers.put(entry.getKey().toLowerCase(), entry.getValue());
headers.remove(entry.getKey());
});
System.out.println(headers);
打印出來;
{null=world, some=greeting, hello=null, good=asdf}
如果您有復雜的檢查並且仍然想使用不帶空值的 Collectors.toMap()
// convert data to a final key, value pairs using Pair.of(key, value)
.map(data -> {
SomeKey key = makeKey(data.getKey());
SomeVal val = makeValue(data.getValue());
// validate and return
if(key.foo != null && val.bar != null) {
return Pair.of(key.foo, val.bar);
}
return null;
})
.filter(Objects::nonNull) // remove the ones that don't satisy criteria
.collect(Collectors.toMap(pair -> pair.getLeft(), pair -> pair.getRight(), // then collect final key/value data without NPE checks
(left, right) -> {
left.merge(right); // can return null
return left;
}
)));
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.