You could explicitly create a builder:
ImmutableMap<String, Long> oldPrices = ImmutableMap.of("banana", 4, "apple", 7);
ImmutableMap<String, Long> newPrices =
new ImmutableMap.Builder()
.putAll(oldPrices)
.put("orange", 9)
.build();
EDIT:
As noted in the comments, this won't allow overriding existing values. This can be done by going through an initializer block of a different Map (e.g., a HashMap). It's anything but elegant, but it should work:
ImmutableMap<String, Long> oldPrices = ImmutableMap.of("banana", 4, "apple", 7);
ImmutableMap<String, Long> newPrices =
new ImmutableMap.Builder()
.putAll(new HashMap<>() {{
putAll(oldPrices);
put("orange", 9); // new value
put("apple", 12); // override an old value
}})
.build();
Just copy the ImmutableMap into a new HashMap, add the items, and convert to a new ImmutableMap
ImmutableMap<String, Long> oldPrices = ImmutableMap.of("banana", 4, "apple", 7);
Map<String, Long> copy = new HashMap<>(oldPrices);
copy.put("orange", 9); // add a new entry
copy.put("apple", 12); // replace the value of an existing entry
ImmutableMap<String, Long> newPrices = ImmutableMap.copyOf(copy);
If you are writing a public-facing API and that immutability is an important aspect of your design, I would definitely make it explicit either by having the name of the method clearly denotes that the returned map will be immutable or by returning the concrete type of the map. Mentioning it in the javadoc is not enough in my opinion.
Since you're apparently using the Guava implementation, I looked at the doc and it's an abstract class so it does give you a bit of flexibility on the actual, concrete type.
If you are writing an internal tool/library, it becomes much more acceptable to just return a plain
Map. People will know about the internals of the code they are calling or at least will have easy access to it.
My conclusion would be that explicit is good, don't leave things to chance.
You should have ImmutableMap as your return type. Map contains methods that are not supported by the implementation of ImmutableMap (e.g. put) and are marked @deprecated in ImmutableMap.
Using deprecated methods will result in a compiler warning & most IDEs will warn when people attempt to use the deprecated methods.
This advanced warning is preferable to having runtime exceptions as your first hint that something is wrong.
Notice that your error message only contains five K, V pairs, 10 arguments total. This is by design; the ImmutableMap class provides six different of() methods, accepting between zero and five key-value pairings. There is not an of(...) overload accepting a varags parameter because K and V can be different types.
You want an ImmutableMap.Builder:
ImmutableMap<String,String> myMap = ImmutableMap.<String, String>builder()
.put("key1", "value1")
.put("key2", "value2")
.put("key3", "value3")
.put("key4", "value4")
.put("key5", "value5")
.put("key6", "value6")
.put("key7", "value7")
.put("key8", "value8")
.put("key9", "value9")
.build();
if the map is short you can do:
ImmutableMap.of(key, value, key2, value2); // ...up to five k-v pairs
If it is longer then:
ImmutableMap.builder()
.put(key, value)
.put(key2, value2)
// ...
.build();