Search code examples
javadictionarysetinstantiation

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.


Solution

  • 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