18

Using Collections.unmodifiableMap(...), I'm trying to return an unmodifiable view of a map. Let's say I have the following method,

public final Map<Foo, Bar> getMap(){
    ...
    return Collections.unmodifiableMap(map);
}

Why is it legal elsewhere to do the following,

Map<Foo, Bar> map = getMap();
map.put(...);

This doesn't throw an UnsupportedOperationException like I thought it would. Can someone please explain this, or suggest how I can successfully return a truly unmodifiable map?

mre
  • 43,520
  • 33
  • 120
  • 170

3 Answers3

33

Are you sure you're not masking your exceptions somehow? This works absolutely fine, in that it throws UnsupportedOperationException:

import java.util.*;

public class Test {

    public static void main(String[] args) {
        Map<String, String> map = getMap();
        map.put("a", "b");
    }

    public static final Map<String, String> getMap(){
        Map<String, String> map = new HashMap<String, String>();
        map.put("x", "y");
        return Collections.unmodifiableMap(map);
    }
}

I suggest you print out map.getClass() on the return value of the method - I would expect it to be an UnmodifiableMap.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 8
    @Jon, I wasn't aware that `UnsupportedOperationException` was a run-time error. I had assumed that it was a compile-time error. This is my fault, but your answer helped me realize how silly this question really was. Thank you! – mre Aug 15 '11 at 15:17
4

I created a small test program and my program threw an 'UnsupportedOperationException' when I tried to put data in.

code:

import java.util.*;

public class TestUnmodifiableMap
{
    Map<Integer, String> myMap;

    public TestUnmodifiableMap()
    {
        myMap = new HashMap<Integer, String>();
    }

    public final Map<Integer, String> getMap()
    {
        return Collections.unmodifiableMap(myMap);
    }

    public static void main(String[] args)
    {
        TestUnmodifiableMap t = new TestUnmodifiableMap();
        Map<Integer, String> testMap = t.getMap();

        testMap.put(new Integer("1"), "Hello");
    }
}

What else are you doing in your class?

Hunter McMillen
  • 59,865
  • 24
  • 119
  • 170
3

There must be something else wrong. There's no way you can put something in that map after you wrapped it as an unmodifiable map.

I would also suggest to return

return Collections.<Foo, Bar>unmodifiableMap(map);

otherwise you will get "unchecked" warnings when compiling your code with -Xlint:unchecked.

emboss
  • 38,880
  • 7
  • 101
  • 108