I'd like to create a few immutable objects for my codebase. What's the best way to really deliver the message that a given class is intended to be immutable? Should I make all of my fields final, and initialize during object construction? (This seems really awkward...) Should I create some Immutable interface, and have objects implement it? (Since Java doesn't have some standard interface behind this, I thought they had some other way of dealing with it.) What's the standard way this is dealt with? (If it's simply done by adding a bunch of comments around the fields exclaiming that they shouldn't be modified once initialized, that's fine too.)
- 1What exactly are you concerned about? Is it that your coworkers won't understand and will modify your class to make it mutable?Daniel Kaplan– Daniel Kaplan2013-05-20 23:20:29 +00:00Commented May 20, 2013 at 23:20
- yeah, exactly. I'm afraid that people who see the code in the future won't fully appreciate the fact that the design behind the class was that it's immutable, and they may create setters for the future and such.Sal– Sal2013-05-20 23:30:34 +00:00Commented May 20, 2013 at 23:30
3 Answers
Should I make all of my fields final, and initialize during object construction?
Yes. And ensure that those types are themselves immutable, or that you create copies when you return values from getter methods. And make the class itself final. (Otherwise your class on its own may be immutable, but that doesn't mean that any instance of your class would be immutable - because it could be an instance of a mutable subclass.)
(This seems really awkward...)
It's hard to know what to suggest without knowing how you find it to be awkward - but the builder pattern can often be useful. I usually use a nested static class for that, often with a static factory method. So you end up with:
Foo foo = Foo.newBuilder() .setName("asd") .setPoints(10) .setOtherThings("whatever") .build(); 6 Comments
And ensure that those types are themselves immutable. What you say about an Immutable interface or annotation as metadata similar to the Serializable interface?Yes and no. Making all fields final is not a guarantee in and of itself. If you'd like to get really in-depth with this there are a number of chapters in Effective Java by Joshua Bloch dealing with immutability and the considerations involved. Item 15 in Effective Java covers the bulk of it and references the other items in question.
He offers these five steps:
Don’t provide any methods that modify the object’s state (known as muta- tors).
Ensure that the class can’t be extended.
Make all fields final.
Make all fields private.
Ensure exclusive access to any mutable components.
One way to learn how to do all of this is to see how the language designers make classes immutable by reviewing the source for classes like String which are immutable (for example see http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java).
2 Comments
If your class has any fields that refer to mutable objects, ensure that clients of the class cannot obtain references to these objects. Never initialize such a field to a client-provided object reference or return the object reference from an accessorWrite a unit test that will fail if your coworkers make the class mutable.
Using Mutability Detector, you can write a test like this:
import static org.mutabilitydetector.unittesting.MutabilityAssert.assertImmutable; @Test public void isImmutable() { assertImmutable(MyImmutableThing.class) } If a coworker comes along, and, for example, adds a setter method to your class, the test will fail. Your use case is one of the core purposes of Mutability Detector.
Disclaimer: I wrote it.