Can a class in Java be immutable if it has a private mutator method?

Viewed 1484

So, I read somewhere that there are 3 requirements for a class to be immutable in Java.

  1. All data fields must be private.
  2. There can't be any mutator methods for data fields.
  3. No accessor methods can return a reference to a data field that is mutable.

But I don't agree with #2 because even if a class has mutator methods, it can be immutable as long as those mutator methods are private. Am I right or wrong? Can you explain in detail?

7 Answers

EDIT

But I don't agree with #2 because even if a class has mutator methods, it can be immutable as long as those mutator methods are private

Because it is a private mutator does not guarantee that it does not change state, but as long as it does not change state what it it supposed to remain intact we can take as immutable. because immutability is remaining intact once set.

Immutable only has a getter. There's no way to change the value of its fields once it's set.

Lets take String class, it is immutable

Once a String object is created, it is not allowed to change. It cannot be made larger or smaller, and you cannot change one of the characters inside it. You can think of a string as a storage box you have perfectly full and whose sides can't bulge. There's no way to add objects, nor can you replace objects without disturbing the entire arrangement.

so immutablity of a class should be like that.

There are different possible definitions of immutability.

The definition you mention does not allow any state change of an object. In particular, after it has been created, it cannot modify its own state.

However, sometimes, an immutable object is defined as an object whose state cannot be observed to change. When immutability is defined like this, the state of an immutable object is allowed to change if this state change cannot be observed from the outside. For example results of expensive calculations could be cached, or some internal statistic information could be recorded, or something like that.

One advantage of immutable objects which is often stated is that they are automatically thread-safe. It is important to note that this advantage only holds when you define immutability in the strong way (the first option above). If an object which only changes its non-observable state is accessed concurrently by two threads, it could in principle still produce erroneous results, so the programmer must take additional care that the object is thread-safe.

There are other ways to break your immutable object. For instance, reflection API. I believe if you decided to make it immutable, would you mind to erase the private setter method. It just doesn't make sense to keep it there.

Directly taken from Wikipedia:

In object-oriented and functional programming, an immutable object (unchangeable object) is an object whose state cannot be modified after it is created.

So definitely if you have a class with a mutator method that changes state of the object (intended as class instance) then that class is not immutable. To consider it as immutable every method must not change its state, but produce another object of the same class, with the modification applied.

Yes, there can't be any mutator methods for data fields.

The reason is that setting the method private only effects the scope of the method. If you want a truly immutable variable then you must set variable final as well. This way your variable cannot be mutated.

Actually what is the point of private mutators?

Immutable means that the object's state can't change in any way after it's creation. Doesn't matter if it's via direct access to the fields, through mutators or some other "random" method that changes the state. None of this is allowed for a class to be immutable.

Immutable doesn't mean: another class can't change the state of this Object, it means: The state of this Object can never change.

Consider this code:

public Person {

  private String name;

  public Person(String name) {

    this.name = name;

  }

  private void setName(String name) {
    this.name = name;
  }

  public boolean hasName(String name) {
    boolean result = this.name.equals(name);
    this.name = name;
    return result;
  }
}

This can't be considered an Immutable class, since even if it doesn't seem so to the class that calls hasName(String name), the state of the Object changes. Seeing that normally, an immutable class usually has it's members declared as final, this would not even compile.

Related