Filter map by entries

Following the same principles found in filtering a map by keys and filtering a map by values, this example will show how to filter a map by entries while using java, java 8 and guava. Each of the snippets below will use a predefined map of months where the key is the month of year and the value represents the month spelled out.

Setup

Map<Integer, String> MONTHS = new HashMap<Integer, String>();

@Before
public void setUp () {

    MONTHS.put(new Integer(1), "January");
    MONTHS.put(new Integer(2), "February");
    MONTHS.put(new Integer(3), "March");
    MONTHS.put(new Integer(4), "April");
    MONTHS.put(new Integer(5), "May");
    MONTHS.put(new Integer(6), "June");
    MONTHS.put(new Integer(7), "July");
    MONTHS.put(new Integer(8), "August");
    MONTHS.put(new Integer(9), "September");
    MONTHS.put(new Integer(10), "October");
    MONTHS.put(new Integer(11), "November");
    MONTHS.put(new Integer(12), "December");
}

Straight up Java

The core jdk lack the mechanics for filtering a map by Map.entry until java 8. As shown in the snippet below, the only effective way is to iterate over the Map.entrySet using a java 5 for loop and then applying criteria in an if statement, in this case checking if entry.value is a length of four.

@Test
public void filter_map_by_entries_java () {

    Map<Integer, String> monthsWithLengthFour = new HashMap<Integer, String>();

    for (Entry<Integer, String> entry : MONTHS.entrySet()) {
        if (entry.getValue().length() == 4) {
            monthsWithLengthFour.put(entry.getKey(), entry.getValue());
        }
    }

    logger.info(monthsWithLengthFour);

    assertThat(monthsWithLengthFour.values(), contains("June", "July"));
}

Output

{6=June, 7=July}

Java 8

The snippet below will show how to filter a map by entries using java 8. Using the powerful streams api, we will call entrySet.stream and filter months with a length of 4. We created this java.util.function.predicate by using a lambda expression. Then using Collectors.map we will map each element in the stream back into a map.

@Test
public void filter_map_by_entries_java8_lambda () {

    Map<Integer, String> monthsWithLengthFour =
            MONTHS.entrySet()
            .stream()
            .filter(p -> p.getValue().length() == 4)
            .collect(Collectors.toMap(p -> p.getKey(), p -> p.getValue()));

    assertThat(monthsWithLengthFour.values(), contains("June", "July"));
}

Output

{6=June, 7=July}

Google Guava

Using guava Maps collection utility we will call Maps.filterEntries which accepts a map and a guava predicate as parameters. It will then filter entries that satisfy the predicate and return a map of the elements.

@Test
public void filter_map_by_entries_guava() {

    Predicate<Map.Entry<Integer, String>> monthLenthFour =
            new Predicate<Map.Entry<Integer, String>>() {
        @Override
        public boolean apply(Entry<Integer, String> input) {
            return input.getValue().length() == 4;
        }
    };

    Map<Integer, String> monthsWithLengthFour = Maps.filterEntries(MONTHS,
            monthLenthFour);

    logger.info(monthsWithLengthFour);

    assertThat(monthsWithLengthFour.values(), contains("June", "July"));
}

Output

{6=June, 7=July}