Immutable objects and unmodifiable collections

java design-patterns collections immutability

2805 просмотра

2 ответа

9813 Репутация автора

With an immutable object, where is it proper to wrap a contained collection as unmodifiable? I see 3 options:

  1. In the immutable object's factory:

    public class ImmutableFactory {
    
        public Immutable build(){
           List<Integer> values = new ArrayList<Integer>();
    
            values.add(1);
            values.add(2);
            values.add(3);
    
            return new Immutable(Collections.unmodifiableList(values), "hello");
        }
    }
    
  2. In the immutable's contructor

    public class Immutable {
    
        private final List<Integer> values;
        private final String hello;
    
        public Immutable(List<Integer> values, String hello) {
            this.values = Collections.unmodifiableList(values);
           this.hello = hello;
        }
    
        public List<Integer> getValues() {
            return values;
        }
    
        public String getHello() {
            return hello;
        }
    }
    
  3. In the immutable's accessor (if applicable).

    public class Immutable {
    
        private final List<Integer> values;
        private final String hello;
    
        public Immutable(List<Integer> values, String hello) {
            this.values = values;
            this.hello = hello;
        }
    
        public List<Integer> getValues() {
            return Collections.unmodifiableList(values);
        }
    
        public String getHello() {
            return hello;
        }
    }
    

Are there any other options and which one is proper?

Автор: John Ericksen Источник Размещён: 16.09.2012 09:47

Ответы (2)


4 плюса

3869 Репутация автора

Решение

I'd say if you create Immutable collection then you need to protect yourself from somebody modifying list that was given as an argument to constructor, you should protectively copy it.

public Immutable(List<Integer> values, String hello) {
    this.values = Collections.unmodifiableList(new ArrayList<Integer>(values));
    this.hello = hello;
}

I personally have long ago switched to Guava collections as there you can find interfaces for immutable collections. Your constructor would look like that:

public Immutable(ImmutableList<Integer> values, String hello) {
    this.values = values;
    this.hello = hello;
}

You'd be sure that argument you receive will not be modified by anyone.

It is usually a good idea to keep reference to immutable list within your immutable class as it then guarantees that you don't modify it by mistake.

Case (1) in my opinion makes sense only when factory method is the only way to create the immutable collection and even then it may break when someone refactors these classes. Unless there are other limitations it is always best to create self-sufficient classes.

Автор: Ivan Koblik Размещён: 16.09.2012 09:53

1 плюс

35188 Репутация автора

First of all, your code in all places is indeed immutable but only because an Integer is immutable.
If you had private final List<SomeCustomClass> values; instead, Collections.unmodifiableList(values); would not guarantee that individual SomeCustomClass of the list is immutable. You would have to code for that.
Having said that, another option is to do a defencive deep copy of the list. This approach also offers immutability.

Автор: Cratylus Размещён: 16.09.2012 10:05
Вопросы из категории :
32x32