95

I read that to make a class immutable in Java, we should do the following,

  1. Do not provide any setters
  2. Mark all fields as private
  3. Make the class final

Why is step 3 required? Why should I mark the class final?

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
Anand
  • 20,708
  • 48
  • 131
  • 198
  • 1
    `java.math.BigInteger` class is example, it's values are immutable but it is not final. – Nandkumar Tekale Sep 06 '12 at 19:16
  • @Nandkumar If you have a `BigInteger`, you don't know if it is immutable or not. It's a messed up design. / `java.io.File` is a more interesting example. – Tom Hawtin - tackline Sep 06 '12 at 19:49
  • 1
    Don't allow subclasses to override methods - The simplest way to do this is to declare the class as final. A more sophisticated approach is to make the constructor private and construct instances in factory methods - from - https://docs.oracle.com/javase/tutorial/essential/concurrency/imstrat.html – Raúl Apr 10 '15 at 12:20
  • @TomHawtin-tackline can you explain (or link to an explanation) of why `java.io.File` is an interesting example? – mkobit Apr 14 '16 at 16:22
  • 1
    @mkobit `File` is interesting because it is likely to be trusted to be immutable, and therefore lead to TOCTOU (Time Of Check/Time Of Use) attacks. Trusted code checks that the `File` has an acceptable path and then uses the path. A subclassed `File` can change value between check and use. – Tom Hawtin - tackline Apr 14 '16 at 17:21
  • 1
    `Make the class final` or Make sure that all subclasses are immutable – O.Badr Apr 12 '20 at 05:35

11 Answers11

154

If you don't mark the class final, it might be possible for me to suddenly make your seemingly immutable class actually mutable. For example, consider this code:

public class Immutable {
     private final int value;

     public Immutable(int value) {
         this.value = value;
     }

     public int getValue() {
         return value;
     }
}

Now, suppose I do the following:

public class Mutable extends Immutable {
     private int realValue;

     public Mutable(int value) {
         super(value);
       
         realValue = value;
     }

     public int getValue() {
         return realValue;
     }
     public void setValue(int newValue) {
         realValue = newValue;
     }

    public static void main(String[] arg){
        Mutable obj = new Mutable(4);
        Immutable immObj = (Immutable)obj;              
        System.out.println(immObj.getValue());
        obj.setValue(8);
        System.out.println(immObj.getValue());
    }
}

Notice that in my Mutable subclass, I've overridden the behavior of getValue to read a new, mutable field declared in my subclass. As a result, your class, which initially looks immutable, really isn't immutable. I can pass this Mutable object wherever an Immutable object is expected, which could do Very Bad Things to code assuming the object is truly immutable. Marking the base class final prevents this from happening.

starball
  • 20,030
  • 7
  • 43
  • 238
templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
  • 16
    If I do Mutable m = new Mutable(4); m.setValue(5); Here, I am playing around with Mutable class object, not Immutable class object.So, I am still confused why Immutable class is not immutable – Anand Sep 06 '12 at 19:26
  • 25
    @anand- Imagine you have a function that takes an `Immutable` an argument. I can pass a `Mutable` object to that function, since `Mutable extends Immutable`. Inside that function, while you think your object is immutable, I could have a secondary thread that goes and changes the value as the function runs. I could also give you a `Mutable` object that the function stores, then later change its value externally. In other words, if your function assumes the value is immutable, it could easily break, since I could give you a mutable object and change it later on. Does that make sense? – templatetypedef Sep 06 '12 at 19:30
  • @templatetypedef- it might sound stupid, but really i am still not clear..lets take an example say I have method void fun(Immutable i)..I pass this method Mutable object say m..now how can I change the object..Can you please explain it with reference to the code example or if you can give some other example, I am fine with that also.. – Anand Sep 06 '12 at 19:42
  • 8
    @anand- The method that you pass the `Mutable` object into won't change the object. The concern is that that method might assume that the object is immutable when it really isn't. For example, the method might assume that, since it thinks the object is immutable, it can be used as the key in a `HashMap`. I could then break that function by passing in a `Mutable`, waiting for it to store the object as a key, then changing the `Mutable` object. Now, lookups in that `HashMap` will fail, because I changed the key associated with the object. Does that make sense? – templatetypedef Sep 06 '12 at 19:45
  • 3
    @templatetypedef- Yes, I got it now..must say that was an awesome explanation..took a little time to grasp it though – Anand Sep 06 '12 at 19:54
  • @templatetypedef but after inheriting the immutable class also we are not able to change the variable named "value". Am I right?? – Sunny Gupta Sep 07 '12 at 06:40
  • 1
    @SAM- That's correct. However, it doesn't really matter, since the overridden functions never reference that variable again. – templatetypedef Sep 07 '12 at 16:50
  • 1
    You don't need to make the entire class final just the getter... public final int getValue() – Justin Ohms Mar 07 '13 at 21:25
  • @JustinOhms For the `HashMap` example, the `hashCode` method would need to be made `final` as well, and anything else inherited from `Object` that could be impactful, which is why making the class `final` is much simpler. – cdeszaq Dec 13 '17 at 17:24
  • @cdeszaq I agree with your evaluation of the HashMap example, although while making the entire class final might be simpler that does not mean it is correct. Making the entire class final implements an architecture design beyond the minimal needed to accomplish the functionality. Since it is likely that someone would use this kind of structure in a library (for others to use) it is courteous to make minimal assumptions about use and impose the minimal restrictions necessary to ensure proper operation of the library. Even if it ultimately requires more work by the library author. – Justin Ohms Dec 13 '17 at 21:49
  • @JustinOhms I 100% agree. Personally I hate restricting "downstream" use. If someone wants to break something, they can. So the purpose is not to make it impossible to do the wrong thing, just to make it hard. `private final` members is enough of a barrier in most cases. I only called out the other (often invisible) methods that have bitten me in the past, like `hashCode` so that they were not forgotten ;-) – cdeszaq Dec 14 '17 at 16:52
  • just a clarification, its not-immutable even if the state is updated by native class(where its declared) right? if a field is `private final` it will still be able to update in the same class hence breaking immutable...correct me if im wrong. – amarnath harish Apr 10 '18 at 12:26
  • 1
    Somehow I do not agree with this because with `Immutable immObj = (Immutable)obj; ` - an immutable class's ORV is pointing to a mutable object, and it can do it because that's super class. Point here is that object is of mutable class and not immutable class, if you create the object of immutable class then it would always be immutable. – hagrawal7777 Aug 21 '18 at 21:04
  • @hagrawal The concern here is that if you have an object reference and the reference has type `Immutable`, you can't tell whether it's referring to an actual, honest-to-goodness `Immutable` object or whether it's pointing to a tricky `Mutable` object that can actually change over time. The cast here is perfectly safe, but hides the fact that an object reference that conveys that the object won't ever change actually points to something that really can change over time. – templatetypedef Aug 21 '18 at 21:40
  • So I can definitely appreciate this answer, but even though I don't 100% agree with @Laurence Gonsalves answer, I can't help but bring up Mockito's need for a non-final class when mocking. How do you get around that? – aaiezza Nov 13 '18 at 18:42
  • @Anand Because! obj and immObj point to the same instance. – linjiejun Jan 26 '19 at 11:34
  • @templatetypedef It's very clear and simple to understand! Thank you ! It's help me. – linjiejun Jan 26 '19 at 11:35
  • @templatetypedef very nice explanation. I have a doubt, if I am marking a class as final do I still need to mark the properties as final in a class?? I think we can skip that. Could you please confirm this. – Piyush Kumar Dec 04 '19 at 07:26
  • Whether a class is final and whether its fields are final are independent questions. If you want to make a class immutable, it’s best to do both. However, you might independently make a class final even if it’s not immutable. – templatetypedef Dec 04 '19 at 15:27
  • According to this logic, an object of [`java.time.LocalDate`](https://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html) or [`java.math.BigDecimal`](https://docs.oracle.com/javase/8/docs/api/java/math/BigDecimal.html) etc. should not be called immutable while the documentation claims so. What's the truth? – Arvind Kumar Avinash Apr 22 '21 at 05:52
  • This is less of a hard and fast rule (“it’s not immutable unless it’s final”) and more of a guideline (“to avoid surprises, mark your immutable classes final.”) – templatetypedef Apr 22 '21 at 15:09
  • A person can just as easily add a setter to `Immutable` and remove the `final` on the `int`. While a `final` class is easier to reason about since you can't extend it (although it can have parent classes), you have to trust that programmers won't do stuff like violate a core design principle used in the code, and if they do, a code review will catch it. Otherwise, testing might catch it. Immutable classes can benefit from inheritance and polymorphism as much as any other class. Immutable is a promise never to mutate an object. `final` isn't needed to ensure that. – user904963 Feb 06 '22 at 17:47
55

Contrary to what many people believe, making an immutable class final is not required.

The standard argument for making immutable classes final is that if you don't do this, then subclasses can add mutability, thereby violating the contract of the superclass. Clients of the class will assume immutability, but will be surprised when something mutates out from under them.

If you take this argument to its logical extreme, then all methods should be made final, as otherwise a subclass could override a method in a way that doesn't conform to the contract of its superclass. It's interesting that most Java programmers see this as ridiculous, but are somehow okay with the idea that immutable classes should be final. I suspect that it has something to do with Java programmers in general not being entirely comfortable with the notion of immutability, and perhaps some sort of fuzzy thinking relating to the multiple meanings of the final keyword in Java.

Conforming to the contract of your superclass is not something that can or should always be enforced by the compiler. The compiler can enforce certain aspects of your contract (eg: a minimum set of methods and their type signatures) but there are many parts of typical contracts that cannot be enforced by the compiler.

Immutability is part of the contract of a class. It's a bit different from some of the things people are more used to, because it says what the class (and all subclasses) can't do, while I think most Java (and generally OOP) programmers tend to think about contracts as relating to what a class can do, not what it can't do.

Immutability also affects more than just a single method — it affects the entire instance — but this isn't really much different than the way equals and hashCode in Java work. Those two methods have a specific contract laid out in Object. This contract very carefully lays out things that these methods cannot do. This contract is made more specific in subclasses. It is very easy to override equals or hashCode in a way that violates the contract. In fact, if you override only one of these two methods without the other, chances are that you're violating the contract. So should equals and hashCode have been declared final in Object to avoid this? I think most would argue that they should not. Likewise, it is not necessary to make immutable classes final.

That said, most of your classes, immutable or not, probably should be final. See Effective Java Second Edition Item 17: "Design and document for inheritance or else prohibit it".

So a correct version of your step 3 would be: "Make the class final or, when designing for subclassing, clearly document that all subclasses must continue to be immutable."

Laurence Gonsalves
  • 137,896
  • 35
  • 246
  • 299
  • 3
    It's worth noting that Java "expects", but does not enforce, that given two objects `X` and `Y`, the value of `X.equals(Y)` will be immutable (as long as `X` and `Y` continue to refer to the same objects). It has similar expectations regarding hash codes. It's clear that nobody should expect the compiler to enforce the immutability of equivalence relations and hash codes (since it just plain can't). I see no reason people should expect it to be enforced for other aspects of a type. – supercat Sep 11 '12 at 20:58
  • 1
    Also, there are many cases where it may be useful to have an abstract type whose contract specifies immutability. For example, one may have an abstract ImmutableMatrix type which, given a coordinate pair, returns a `double`. One might derive a `GeneralImmutableMatrix` which uses an array as a backing store, but one might also have e.g. `ImmutableDiagonalMatrix` which simply stores an array of items along the diagonal (reading item X,Y would yield Arr[X] if X==y and zero otherwise). – supercat Sep 11 '12 at 21:01
  • 3
    I like this explanation the best. Always making an immutable class `final` restricts its usefulness, especially when you are designing an API meant to be extended. In the interest of thread-safety, it makes sense to make your class as immutable as possible, but keep it extensible. You can make the fields `protected final` instead of `private final`. Then, explicitly establish a contract (in documentation) about sub-classes adhering to the immutability and thread-safety guarantees. – curioustechizen Jan 04 '13 at 07:29
  • 5
    +1 - I'm with you all the way until the Bloch quote. We don't have to be so paranoid. 99% of coding are cooperative. No big deal if someone really need to override something, let them. 99% of us are not writing some core APIs like String or Collection. A lot of Bloch's advices, unfortunately, are based on that kind of use cases. They are not really helpful to most programmers, especially new ones. – ZhongYu Jul 04 '15 at 01:24
  • I would prefer make immutable class `final`. Just because `equals` and `hashcode` can't be final does not mean I may tolerate the same for immutable class, unless I have a valid reason to do so, and in this case I may use documentation or testing as a defense line. – O.Badr Apr 12 '20 at 05:51
  • Very good comment. Immutability and designing for extension are separate concerns. Immutability of sublcasses should not be enforced by compiler. – Jacek Obarymski Jun 02 '20 at 16:09
23

Don't mark the entire class final.

There are valid reasons for allowing an immutable class to be extended as stated in some of the other answers so marking the class as final is not always a good idea.

It's better to mark your properties private and final and if you want to protect the "contract" mark your getters as final.

In this way you can allow the class to be extended (yes possibly even by a mutable class) however the immutable aspects of your class are protected. Properties are private and can't be accessed, getters for these properties are final and cannot be overridden.

Any other code that uses an instance of your immutable class will be able to rely on the immutable aspects of your class even if the sub class it is passed is mutable in other aspects. Of course, since it takes an instance of your class it wouldn't even know about these other aspects.

Justin Ohms
  • 3,334
  • 31
  • 45
  • 2
    I'd rather encapsulate all of the immutable aspects in a separate class and use it by means of composition. It would be easier to reason about than mixing mutable and immutable state in a single unit of code. – toniedzwiedz Dec 09 '14 at 06:50
  • 2
    Totally agree. Composition would be one very good way of accomplishing this, provided your mutable class contains your immutable class. If your structure is the other way around it would be a good partial solution. – Justin Ohms Jan 21 '15 at 16:10
6

If you do not make it final I can extend it and make it non mutable.

public class Immutable {
  privat final int val;
  public Immutable(int val) {
    this.val = val;
  }

  public int getVal() {
    return val;
  }
}

public class FakeImmutable extends Immutable {
  privat int val2;
  public FakeImmutable(int val) {
    super(val);
  }

  public int getVal() {
    return val2;
  }

  public void setVal(int val2) {
    this.val2 = val2;
  }
}

Now, I can pass FakeImmutable to any class that expects Immutable, and it will not behave as the expected contract.

Roger Lindsjö
  • 11,330
  • 1
  • 42
  • 53
  • 2
    I think this is pretty much identical to my answer. – templatetypedef Sep 06 '12 at 19:06
  • Yes, checked half way through posting, no new answers. And then when posted, there yours were, 1 minute before me. At least we did not use the same names for everything. – Roger Lindsjö Sep 06 '12 at 20:07
  • One Correction : In FakeImmutable class, Constructor name should be FakeImmutable NOT Immutable – Sunny Gupta Sep 07 '12 at 06:29
  • According to this logic, an object of [`java.time.LocalDate`](https://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html) or [`java.math.BigDecimal`](https://docs.oracle.com/javase/8/docs/api/java/math/BigDecimal.html) etc. should not be called immutable while the documentation claims so. What's the truth? – Arvind Kumar Avinash Apr 22 '21 at 05:53
  • I think https://stackoverflow.com/a/12327580/917548 explains much more details on Immutability. You can have a contract that says this class is immutable. With final you signal that this class is not supposed to be extended / enhanced. – Roger Lindsjö Apr 22 '21 at 08:41
5

If it's not final then anyone could extend the class and do whatever they like, like providing setters, shadowing your private variables, and basically making it mutable.

digitaljoel
  • 26,265
  • 15
  • 89
  • 115
  • 1
    Although you're right, it's not clear why the fact that you can add mutable behavior would necessarily break things if the base class fields are all private and final. The real hazard is that the subclass might turn a previously immutable object into a mutable object by overriding the behavior. – templatetypedef Sep 06 '12 at 19:11
4

That constraints other classes extending your class.

final class can't be extended by other classes.

If a class extend the class you want to make as immutable, it may change the state of the class due to inheritance principles.

Just clarify "it may change". Subclass can override superclass behaviour like using method overriding (like templatetypedef/ Ted Hop answer)

kosa
  • 65,990
  • 13
  • 130
  • 167
  • 2
    That's true, but why is it necessary here? – templatetypedef Sep 06 '12 at 19:00
  • @templatetypedef: You are too fast. I am editing my answer with supporting points. – kosa Sep 06 '12 at 19:01
  • 4
    Right now your answer is so vague that I don't think it answers the question at all. What do you mean by "it may change the state of the class due to inheritance principles?" Unless you already know why you should mark it `final`, I can't see how this answer helps. – templatetypedef Sep 06 '12 at 19:04
4

For creating an immutable class it is not mandatory to mark the class as final.

Let me take one such example from the standard library itself: BigInteger is immutable but it's not final.

Actually, immutability is a concept according to which once an object is created, it can not be modified.

Let's think from the JVM point of view. From the JVM point of view, an object of this class should be fully constructed before any thread can access it and the state of the object shouldn't change after its construction.

Immutability means there is no way to change the state of the object once it is created and this is achieved by three thumb rules which make the compiler recognize that class is immutable and they are as follows:

  • All non-private fields should be final
  • Make sure that there is no method in the class that can change the fields of the object either directly or indirectly
  • Any object reference defined in the class can't be modified from outside of the class

For more information refer to this URL.

Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110
Tarun Bedi
  • 61
  • 2
2

Let's say you have the following class:

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class PaymentImmutable {
    private final Long id;
    private final List<String> details;
    private final Date paymentDate;
    private final String notes;

    public PaymentImmutable (Long id, List<String> details, Date paymentDate, String notes) {
        this.id = id;
        this.notes = notes;
        this.paymentDate = paymentDate == null ? null : new Date(paymentDate.getTime());
        if (details != null) {
            this.details = new ArrayList<String>();

            for(String d : details) {
                this.details.add(d);
            }
        } else {
            this.details = null;
        }
    }

    public Long getId() {
        return this.id;
    }

    public List<String> getDetails() {
        if(this.details != null) {
            List<String> detailsForOutside = new ArrayList<String>();
            for(String d: this.details) {
                detailsForOutside.add(d);
            }
            return detailsForOutside;
        } else {
            return null;
        }
    }

}

Then you extend it and break its immutability.

public class PaymentChild extends PaymentImmutable {
    private List<String> temp;
    public PaymentChild(Long id, List<String> details, Date paymentDate, String notes) {
        super(id, details, paymentDate, notes);
        this.temp = details;
    }

    @Override
    public List<String> getDetails() {
        return temp;
    }
}

Here we test it:

public class Demo {

    public static void main(String[] args) {
        List<String> details = new ArrayList<>();
        details.add("a");
        details.add("b");
        PaymentImmutable immutableParent = new PaymentImmutable(1L, details, new Date(), "notes");
        PaymentImmutable notImmutableChild = new PaymentChild(1L, details, new Date(), "notes");

        details.add("some value");
        System.out.println(immutableParent.getDetails());
        System.out.println(notImmutableChild.getDetails());
    }
}

Output result will be:

[a, b]
[a, b, some value]

As you can see while original class is keeping its immutability, child classes can be mutable. Consequently, in your design you cannot be sure that the object you are using is immutable, unless you make your class final.

valijon
  • 1,304
  • 2
  • 20
  • 35
  • You can't be sure anything is immutable except stuff like final primitives unless you check the code yourself. Just like a class that says it's immutable is probably immutable, you can probably trust people wouldn't extend an immutable class and make it mutable. There's no reason why you can't use the benefits of inheritance and polymorphism with immutable classes. Marking the class `final` just makes confirming a class is immutable easier, but someone could just as easily add a setter to a `final` immutable class as they could make an mutable child class. – user904963 Feb 06 '22 at 17:35
  • Greate @valijon thanks – sunleo Apr 23 '22 at 10:28
0

Suppose the following class were not final:

public class Foo {
    private int mThing;
    public Foo(int thing) {
        mThing = thing;
    }
    public int doSomething() { /* doesn't change mThing */ }
}

It's apparently immutable because even subclasses can't modify mThing. However, a subclass can be mutable:

public class Bar extends Foo {
    private int mValue;
    public Bar(int thing, int value) {
        super(thing);
        mValue = value;
    }
    public int getValue() { return mValue; }
    public void setValue(int value) { mValue = value; }
}

Now an object that is assignable to a variable of type Foo is no longer guaranteed to be mmutable. This can cause problems with things like hashing, equality, concurrency, etc.

Ted Hopp
  • 232,168
  • 48
  • 399
  • 521
0

Design by itself has no value. Design is always used to achieve a goal. What is the goal here? Do we want to reduce the amount of surprises in the code? Do we want to prevent bugs? Are we blindly following rules?

Also, design always comes at a cost. Every design that deserves the name means you have a conflict of goals.

With that in mind, you need to find answers to these questions:

  1. How many obvious bugs will this prevent?
  2. How many subtle bugs will this prevent?
  3. How often will this make other code more complex (= more error prone)?
  4. Does this make testing easier or harder?
  5. How good are the developers in your project? How much guidance with a sledge hammer do they need?

Say you have many junior developers in your team. They will desperately try any stupid thing just because they don't know good solutions for their problems, yet. Making the class final could prevent bugs (good) but could also make them come up with "clever" solutions like copying all these classes into a mutable ones everywhere in the code.

On the other hand, it will be very hard to make a class final after it's being used everywhere but it's easy to make a final class non-final later if you find out you need to extend it.

If you properly use interfaces, you can avoid the "I need to make this mutable" problem by always using the interface and then later adding a mutable implementation when the need arises.

Conclusion: There is no "best" solution for this answer. It depends on which price you're willing and which you have to pay.

Aaron Digulla
  • 321,842
  • 108
  • 597
  • 820
0

The default meaning of equals() is the same as referential equality. For immutable data types, this is almost always wrong. So you have to override the equals() method, replacing it with your own implementation. link

Anitha B S
  • 101
  • 1
  • 8