If the purpose is to get a map containing null
value, this has to be implemented using a custom collector, because existing implementation throws NullPointerException
when putting null
:
List<String> productCodes = List.of("X_14_AA_85", "X_14_BB_85", "X_14_ZZ_85");
List<String> products = List.of("AA", "BB", "CC", "ZZ");
Map<String, String> mapCodes = products.stream()
.distinct()
.collect(
HashMap::new,
(m, p) -> m.put(p, productCodes
.stream()
.filter(pc -> pc.contains(p))
.findFirst()
.orElse(null)
),
HashMap::putAll
);
// -> {AA=X_14_AA_85, BB=X_14_BB_85, CC=null, ZZ=X_14_ZZ_85}
Then the list of non-matched products may be retrieved as follows:
List<String> nonMatchedProducts = mapCodes.entrySet()
.stream()
.filter(e -> e.getValue() == null)
.map(Map.Entry::getKey)
.collect(Collectors.toList());
// -> [CC]
However, as the result of findFirst
is returned as Optional
it may be used along with Collectors::toMap
, and then the non-matched values can be filtered out using Optional::isEmpty
:
Map<String, Optional<String>> mapCodes2 = products.stream()
.distinct()
.collect(Collectors.toMap(
p -> p,
p -> productCodes.stream().filter(pc -> pc.contains(p)).findFirst()
));
// -> {AA=Optional[X_14_AA_85], BB=Optional[X_14_BB_85], CC=Optional.empty, ZZ=Optional[X_14_ZZ_85]}
List<String> nonMatchedProducts2 = mapCodes2.entrySet()
.stream()
.filter(e -> e.getValue().isEmpty())
.map(Map.Entry::getKey)
.collect(Collectors.toList());
// -> [CC]
Also, the null/empty values may not be stored at all, then non-matched products can be found after removing all the matched ones:
Map<String, String> map3 = new HashMap<>();
for (String p : products) {
productCodes.stream()
.filter(pc -> pc.contains(p))
.findFirst()
.ifPresent(pc -> map3.put(p, pc)); // only matched pairs
}
// -> {AA=X_14_AA_85, BB=X_14_BB_85, ZZ=X_14_ZZ_85}
List<String> nonMatchedProducts3 = new ArrayList<>(products);
nonMatchedProducts3.removeAll(map3.keySet());
// -> [CC]