List of Map filter results in an extra empty item

Viewed 131

I have a simple Class as follows:

public class ListOfMapsExample {
    public static void main(String[] args) {
        Map<String, String> map1 = Map.of("aa1k", "aa1v", "aa2k", "aa2v", "aa3k", "aa3v");
        Map<String, String> map2 = Map.of("bb1k", "bb1v", "bb2k", "bb2v", "bb3k", "bb3v");
        Map<String, String> map3 = Map.of("cc1k", "cc1v", "cc2k", "cc2v", "cc3k", "cc3v");

        List<Map<String, String>> maps = Arrays.asList(map1, map2, map3);

        List<Map<String, String>> listOfMaps1 = maps.stream()
                .map(m -> m.entrySet().stream()
                        .filter(map -> map.getKey().equals("aa1k") || map.getKey().equals("bb2k"))
                        .collect(Collectors.toMap(p -> p.getKey(), p -> p.getValue())))
                .collect(Collectors.toList());

        System.out.println("listOfMaps1 :: " + listOfMaps1);
    }
}

Expected output: listOfMaps1 :: [{aa1k=aa1v}, {bb2k=bb2v}]

Actual output: listOfMaps1 :: [{aa1k=aa1v}, {bb2k=bb2v}, {}]

Question: Even though the third map doesnt pass filter criteria why its showing up as empty in the result? How can I omit it?

2 Answers

You are building maps by filtering on each ones contents. And one of them will be empty since no values were passed (but you still created it). So you need to filter on empty maps before adding it to the list.

List<Map<String, String>> listOfMaps1 = maps.stream()
        .map(m -> m.entrySet().stream()
                .filter(map -> map.getKey().equals("aa1k")
                        || map.getKey().equals("bb2k"))
                .collect(Collectors.toMap(p -> p.getKey(),
                        p -> p.getValue()))).filter(map->!map.isEmpty())
        .collect(Collectors.toList());

System.out.println("listOfMaps1 :: " + listOfMaps1);

Problem is already explained in WJS's answer, but based on your example you probably can use alternative (and IMO little more readable) solution:

  • flatten stream to iterate over entries from all maps,
  • from that stream filter entries which we are interested in
  • wrap data from filtered entries back into Map
  • collecting all such maps in a list.

Demo:

List

List<Map<String, String>> listOfMaps1 = maps.stream()
        .flatMap(m -> m.entrySet().stream()) //to create single stream of all entries
        .filter(entry -> entry.getKey().equals("aa1k") || entry.getKey().equals("bb2k"))
        .map(entry -> Map.of(entry.getKey(), entry.getValue()))
        .collect(Collectors.toList());

Output: listOfMaps1 :: [{aa1k=aa1v}, {bb2k=bb2v}].

Related