0

In my quest to make an object immutable in Java, I marked the class final, All of its variables final and provided no setters and getters. Will these provide sufficient guarantees that the object will not be modified ? Are all 3 necessary or 2 of the 3 conditions are more than enough ?

3
  • 4
    Having all your attributes marked as final is an option. No need to mark the class as final since this means the class can't be inherited. The only condition your class fields must meet is that they must not change in any way. Note that hacking the state using reflection must not be a factor when considering class immutability. Commented Apr 13, 2013 at 23:43
  • Well, the object is still mutable if you have mutating methods. I'm assuming you don't though. Commented Apr 13, 2013 at 23:49
  • possible duplicate of Immutable objects and unmodifiable collections Commented Apr 14, 2013 at 0:06

5 Answers 5

6
public final class MyClass 

Has nothing to do with immutability, it only disallows inheritance.

Just marking variable references final is not enough, every object you refer to has to be immutable as well.

final doesn't make an object immutable, it makes the references immutable;

private final List<String> strings = new ArrayList<String>(); 

strings is still a mutable List, only the reference to the List is immutable.

Be careful with things like:

Collections.unmodifiableList(strings); 

Collections.unmodifiableList() JavaDoc provides a "unmodifiable view" but it still doesn't guarantee that the underlying list could not be changed by an external reference to the original List that is being wrapped. A deep copy of the list contents would have to be made into a new list and that list wrapped with unmodifiable.

And every instance of every object and all their children and children's children have to be immutable as well.

Sign up to request clarification or add additional context in comments.

1 Comment

Sorry, I had to give a -1 for the "has nothing to do with immutability" comment. All Java immutable classes (String, Integer, etc.) are final specifically for immutability.
1

Marking your fields final is the only option you need out of the mentioned set. You can provide getters, but be careful about mutable sub-objects like collections. Final makes the reference immutable but not the contents. A useful technique with getters is to make a defensive copy if the value is mutable like so:

public class ImmutableExample{ private final int value1; // immutable private final List<Integer> value2; // contents will not be immutable public ImmutableExample(...){...} // be careful here to copy the collection as you want to disalow any outside modification. public int getValue1(){ return value1; } public List<Integer> getValue2(){ return Collections.unmodifiableList(value2); } } 

Another option is to use Google Guava collections that include Immutable collections as we discussed here: Immutable objects and unmodifiable collections. These result in really easy immutable classes:

public class ImmutableExample{ private final int value1; // immutable private final ImmutableList<Integer> value2; // immutable public ImmutableExample(...){...} public int getValue1(){ return value1; } public List<Integer> getValue2(){ return value2; } } 

2 Comments

Collections.unmodifiableList doesn't make a list immutable, it only provides a "view" that can't be modified; it doesn't make a "defensive" copy or any other copy, the underlying list is still mutable.
Right, Collections.unmodifiableList only goes so far, that's why I mentioned Guava's ImmutableList. Also, you should copy the list given to the class in the constructor to avoid outside modifications.
0

Marking your class as final you're only telling that no one can subclass it.

That said, marking your variables as final would be enough, as long as your class had only 'primitive' attributes. It's ok (and encouraged) to keep the getters, however, you also may want remove the setters, since while you don't want any external class to mess around with your variables, setters won't be needed.

Comments

0

It would be more natural to set all variables private and only provide getters. You then need not set the class final which is unnecessary overkill.

Further consideration must be made if the fields are non-final objects themselves such as collections. You should only store copies of these.

Comments

-1

Contrary to some of the comments here, making a class final does have to do with immutability. For a class to be immutable, it should be final, so as to not allow subclasses to override any getters, and thereby not allowing them to "mutate" it by returning a different value.

Recall that to guarantee immutability, a class must not permit itself to be subclassed. - Joshua Bloch, Effective Java 

also, from the Java tutorials, A Strategy for Defining Immutable Objects:

3.Don't allow subclasses to override methods. The simplest way to do this is to declare the class as final

1 Comment

Hmmm... a down vote with no comment to back it up. I guess Joshua Bloch is wrong.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.