1

After searching I found these questions, but no answers to my specific question:

Undo/Redo with immutable objects

Why continue to use getters with immutable objects

How to write a test friendly immutable value class

Is it okay to expose the state of an immutable object

Here's the setup: I've got an immutable class like so:

public class MyImmutableOb {
    private final String name;
    private final Collection<Integer> myNumbers;

    public MyImmutableOb(String name) {
        this.name = name;
        myNumbers = new LinkedList<>();
    }

    public MyImmutableOb(String name, MyImmutableOb oldOb) {
        this.name = name;
        myNumbers = new LinkedList<>();
        for (int i : oldOb.getNumbers()) myNumbers.add(i);
    }

    public Collection<Integer> getNumbers() {
        return new LinkedList<>(myNumbers);
    }
}

I have included a constructor like this, meant to allow simulating a name change on the object. The question is, does reproducing the Collection in this fashion break immutability?:

public MyImmutableOb(String name, MyImmutableOb oldOb) {
    this.name = name;
    myNumbers = new LinkedList<>();
    for (int i : oldOb.getNumbers()) myNumbers.add(i);
}

I am having a tough time wrapping my head around this one.

Community
  • 1
  • 1
nihilon
  • 834
  • 2
  • 8
  • 23
  • The `myNumbers` member of your 'immutable' class is a _mutable_ list. Your class either is or is not _effectively_ immutable. The answer depends on whether or not anything in the `// and so on...` part of the class modifies the list. – Solomon Slow Jan 23 '15 at 22:09
  • Your second constructor calls `oldOb.getNumbers()`, but you did not show us the definition of getNumbers(). What does it do? If it merely returns `oldOb.myNumbers`, then your class is mutable: A client could call getNumbers(), and then modify the list. – Solomon Slow Jan 23 '15 at 22:12
  • That definition might help, huh? Haha, my bad, I went ahead and added the definition in. Those are all the methods in the class currently. – nihilon Jan 23 '15 at 23:28

1 Answers1

2

As you have discovered, in order to make instances of your class immutable, you have to explicity write immutability into your class; object types (as opposed to primitive types) are mutable by nature. The collections classes in java.util are of course mutable. Java classes like String and the primitive boxing types Integer, Double, etc., are written to be immutable.

Your variable declaration

private final String name;

is immutable because it is declared final and because String objects are immutable.

Using the final keyword for a variable ensures that the variable can be assigned a value only once, therefore it is an excellent tool for designing an immutable class. However, it is not enough, because if the variable is assigned to a mutable object then the variables in that object can still be modified.

Your variable declaration

private final Collection<int> myNumbers;

does not guarantee immutability because, although myNumbers can be assigned only once, the collection assigned to it is still mutable.

The good news is, the Java Collections utility class provides lightweight wrappers to make your collections immutable. This will require a change to your first constructor

public MyImmutableOb(String name, int... numbers) {
    this.name = name;
    this.myNumbers = Collections.unmodifiableList(Arrays.asList(numbers));
}

so that myNumbers is now truly immutable. Note I've forsaken your usage of LinkedList, because there's no point in using that specialized List implementation when it's immutable within MyImmutableOb.

Thus your second constructor becomes

public MyImmutableOb(String name, MyImmutableOb oldOb) {
    this.name = name;
    this.myNumbers = oldOb.myNumbers;
}

because oldOb's myNumbers is already immutable, so there's no point in copying.

In closing, I realize you probably did want to be able to change the contents of myNumbers after construction of a MyImmutableOb. Obviously, making the class truly immutable implies that nothing can change in its instances after construction.

gknicker
  • 5,509
  • 2
  • 25
  • 41
  • 1
    Yeah, I saw that you got rid of the `LinkedList`. For clarification, `LinkedList` was being used because the order of the items being stored matters. Thanks why I used it. Thanks for the in depth explanation, it is appreciated! – nihilon Jan 24 '15 at 15:57