Search code examples
javamultimapunmodifiable

Unmodifiable Multimap


Is there a way to create (/return) an unmodifiable Multimap?

I am using the Multimap of com.google.common.collect and need to create an unmodfiable Multimap, but I couldn't find a lib that has a method, which returns the a given Multimap as an umodifiable Multimap.

For "normal" Maps I usually use the MapUtils.unmodifiableMap(map) method of the org.apache.commons.collections4.MapUtils lib.

example:

public static Map<String, String> bufferName()
{
    Map<String, String> fooMap = new HashMap<>();
    fooMap.put("foo", "bar");
    return MapUtils.unmodifiableMap(fooMap);
}

what I need:

public static Multimap<String, String> bufferName1()
{
    HashMultimap<String, String> fooMultimap = HashMultimap.create();
    fooMultimap.put("foo", "bar");
    fooMultimap.put("foo", "foobar");
    // ! the next line needs to be optimized so that the returned HashMultimap cannot be modified.
    return fooMultimap;
}

I tried to find a lib, that can return given mutable Multimaps as immutable Multimaps, but couldn't find any.

I also tried to put the mutable Multimap into an immmutable Object, but that is everything else than clean.

example:

public static Set<HashMultimap<String, String>> bufferName1()
{
    HashMultimap<String, String> fooMultimap = HashMultimap.create();
    fooMultimap.put("foo", "bar");
    fooMultimap.put("foo", "foobar");
    // org.apache.commons.collections4.SetUtils
    SetUtils.unmodifiableSet(Set.of(fooMultimap));
}

Solution

  • Java's own core library is a general purpose library.

    Guava is a general purpose library.

    Apache commons is a general purpose library.

    You're using all 3 in a weird mix and match. This isn't a good idea. Generally the apache stuff is exceedingly low quality. The reason guava and apache-commons exist in the first place is due to perceived lack of utility in the core libs, but in the last decade or so (note that guava and apache-commons are much, much older), the core libs have been adding stuff at rapid pace.

    Thus, I'd get rid of apache for sure, and possibly guava as well; core libs can do all this now.

    Getting an immutable multimap using just guava

    Guava has class ImmutableListMultimap and ImmutableSetMultimap. They have a copyOf static 'constructor'. So just ImmutableSetMultimap.copyOf(myMutableMultimap) is all you need.

    Getting an immutable multimap using just java core

    Java core does multimaps a little different. Instead of a Multimap<Integer, String>, you have a Map<Integer, List<String>> (or Set<String>, mirroring how guava's multimap has 'SetMultimap' and 'ListMultimap' variants). The major downside to it, and presumably the reason guava has multimaps in the first place, is that adding a new element sounds really complicated; you have to get the set/list first. If it exists, use it. If it does not exist, create it, then use that.

    Except since Java9 it's not that complicated anymore:

    Map<Integer, List<String>> multimap = new HashMap<>();
    
    int k = 5;
    String v = "hello";
    
    // add a new item:
    
    multimap.computeIfAbsent(5, x -> new ArrayList<>()).add(v);
    

    computeIfAbsent is the key that makes this palatable.

    Given that it's "just a map", you can use Collections.unmodifiableMap() as usual.

    Guava's multimap still has advantages; you may want to continue to use it.

    But apache cannot help here.