Instantiate a Map from a set of key objects, in Java

Given a Set of objects that I want to use as keys, how can I easily get a Map instance leaving the values as null?

The purpose is to pre-populate the map with keys before determining the values to be stored.

Of course, I could create an empty map, then loop the set of would-be key objects, while doing a put on each, along with null as the value.

Set< Month > months = EnumSet.of( Month.MARCH , Month.MAY , Month.JUNE ) ; 
Map< Month , String > map = new EnumMap<>( Month.class ) ;
for( Month month : months ) 
{
    map.put( month , null ) ;
}

I just wonder if there is a nifty trick to do this with less code. Something like the opposite of Map#keySet.

Answer

Collectors.toMap() and the static factory methods like Map.of() use internally Map.merge which will throw NPE if key or value is null.

See this post: java-8-nullpointerexception-in-collectors-tomap. And see this issue page on the OpenJDK project: JDK-8148463 Collectors.toMap fails on null values

You could work around by using Stream.collect with the three args signature as a reduction.

collect(Supplier supplier, BiConsumer accumulator, BiConsumer combiner)

Something like:

Set< Month > months = EnumSet.of( Month.MARCH , Month.MAY , Month.JUNE ) ;         
Map< Month , String > myMap = 
        months.stream()
              .collect(
                  HashMap::new , 
                  ( map , val )-> map.put( val , null ) , 
                  HashMap::putAll
              );
              
System.out.println(myMap);

See that code run live at IdeOne.com.

But I’m not sure if this is either more readable or more elegant than your approach with the classic for-loop

Leave a Reply

Your email address will not be published. Required fields are marked *