A possible downside of Map.of is that it returns Map, which provides a lot of methods that are documented to throw UnsupportedOperationException in case the map is immutable - that may be considered a disadvantage in API design. There is no reliable way for code consuming Maps to know whether any of these will work.
There were good reasons for this decision, such as being able to take advantage of the existing codebase without breaking backwards compatibility. But this comes at the cost that the type system can't help with communicating whether a given method can accept (or requires) an immutable or a mutable map. That is left to documentation.
(guavas ImmutableMap also implements Map, but at least the unsupported methods are marked as deprecated. Arguably still not ideal, but... tradeoffs)
A possible downside of Map.of is that it returns Map, which provides a lot of methods that are documented to throw UnsupportedOperationException in case the map is immutable - that may be considered a disadvantage in API design. There is no reliable way for code consuming Maps to know whether any of these will work.
There were good reasons for this decision, such as being able to take advantage of the existing codebase without breaking backwards compatibility. But this comes at the cost that the type system can't help with communicating whether a given method can accept (or requires) an immutable or a mutable map. That is left to documentation.
(guavas ImmutableMap also implements Map, but at least the unsupported methods are marked as deprecated. Arguably still not ideal, but... tradeoffs)
I assume you are talking about com.google.common.collect.ImmutableMap? According to the javadoc, that has been in guava since 2.0, which is really old (I can only find the year 2010 for version 3.0, so 2.0 is before that).
Map.of was only introduced with java 9, which was released in September 2017. That means that only the first option was available before java 9, but you needed a library.
Since this feature was finally integrated into java itself with java 9 and you don't need an external library anymore, I would argue Map.of is preferrable.
However, in terms of readability, I have always hated that Map.of as well as List.of return immutable implementations, which is not what an inexperienced (=has not fallen into that trap yet) developer expects.
If you are using guava anyways, ImmutableMap.of is the more readable option, but that's up to you.
Why would you want those for a regular HashMap or LinkedHashMap? You can just do this:
Map<String, Object> map = Maps.newHashMap();
map.put(key, value);
The thing with ImmutableMap is that it is a little bit more cumbersome to create; you first need to make a Builder, then put the key-value pairs in the builder and then call build() on it to create your ImmutableMap. The ImmutableMap.of() method makes it shorter to write if you want to create an ImmutableMap with a single key-value pair.
Consider what you'd have to write if you wouldn't use the ImmutableMap.of() method:
ImmutableMap<String, Object> map = ImmutableMap.builder()
.put(key, value);
.build();
Try Maps.newHashMap(ImmutableMap.of(...))
Maps.newHashMap(Map map)
An unmodifiable map may still change. It is only a view on a modifiable map, and changes in the backing map will be visible through the unmodifiable map. The unmodifiable map only prevents modifications for those who only have the reference to the unmodifiable view:
Map<String, String> realMap = new HashMap<String, String>();
realMap.put("A", "B");
Map<String, String> unmodifiableMap = Collections.unmodifiableMap(realMap);
// This is not possible: It would throw an
// UnsupportedOperationException
//unmodifiableMap.put("C", "D");
// This is still possible:
realMap.put("E", "F");
// The change in the "realMap" is now also visible
// in the "unmodifiableMap". So the unmodifiableMap
// has changed after it has been created.
unmodifiableMap.get("E"); // Will return "F".
In contrast to that, the ImmutableMap of Guava is really immutable: It is a true copy of a given map, and nobody may modify this ImmutableMap in any way.
Update:
As pointed out in a comment, an immutable map can also be created with the standard API using
Map<String, String> immutableMap =
Collections.unmodifiableMap(new LinkedHashMap<String, String>(realMap));
This will create an unmodifiable view on a true copy of the given map, and thus nicely emulates the characteristics of the ImmutableMap without having to add the dependency to Guava.
Have a look at ImmutableMap JavaDoc: doc
There is information about that there:
Unlike Collections.unmodifiableMap(java.util.Map), which is a view of a separate map which can still change, an instance of ImmutableMap contains its own data and will never change. ImmutableMap is convenient for public static final maps ("constant maps") and also lets you easily make a "defensive copy" of a map provided to your class by a caller.