Assign Map<String, List> input to Map<String, List> output



I’m new to Streams and I want something like this: I have an input Map with <String, List<String>>. I want to read this map in a stream and assign it to an output map with <String, String> with the value being the first element of the value list from input map. Example:

**Input:**
{key1, [value1 value2]}
{key2, null}

**Output**
{key1, value1}
{key2, null}

Notice, when the list in the first map is null, then it should be written as null in the second map. If the list is empty, then it should also write null in the second map value

What I have tried:

Map<String, String> output= input.entrySet().stream()
                    .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().get(0)));

This gives a java.lang.NullPointerException when the list is empty in the first map.

Answer

Unfortunately, Collectors.toMap will also throw if you put a null value in.

To get around this, you can in-line build a Collector for Map. For example, something like:

final Map<String, String> output = input.entrySet().stream()
        .collect(HashMap::new, // Create a Map if none is present
                (map, entry) -> map.put(entry.getKey(), // Keys stay the same
                (entry.getValue() == null || entry.getValue().isEmpty()) // Check for empty
                    ? null : entry.getValue().iterator().next()), // Get first if present
                HashMap::putAll); // Combining function

Note: wrapping this with Collections.unmodifiableMap makes sense to avoid future contamination. Note: Pulling out the ‘get first value or null’ to a method like the following is probably considerably more readable, and allows the combining bit to just become this.getFirstIfPresent(entry.getValue()) in the above pipeline:

private static <T> @Nullable T getFirstIfPresent(final List<T> input) {
    if (list == null || list.isEmpty()) {
        return null;
    }

    return list.iterator().next();
}


Source: stackoverflow