Immutability refers to the inability of an object or entity to change or be altered once it has been created or defined. In the context of programming, immutable data cannot be modified once it is created. That is, once you have assigned a value to an immutable object, you cannot change that value.
For example, in some programming languages, such as Haskell or Clojure, many data types are immutable by default. If an attempt were made to modify an immutable object, a new object would be generated with the changes made.
What are immutable objects for?
Immutable objects are created to maintain a constant, unchanging state once they have been created. Their main purpose is to ensure that their state cannot be changed after their creation, which has several advantages:
- Increased security in multi-threaded environments: Imagine you are developing a user authentication system. If the objects representing user credentials are immutable, once they are set, they cannot be changed. This ensures that the credentials cannot be altered by accident or maliciousness, especially in multi-threaded environments where multiple threads are running simultaneously.
- Improved concurrence: Immutable objects cannot change their state once created, which eliminates the possibility of multiple threads trying to modify the same object simultaneously. This avoids race conditions (two threads accessing and modifying an object at the same time) and greatly simplifies concurrent programming, as more complex synchronisation mechanisms would not be as necessary.
However, many programmers are very reluctant to create immutable objects. This is because if a lot of data in the code has to be changed in the project, a lot of new objects would have to be generated. The more objects, the more the memory capacity of the software is overloaded. and more compromises the performance of the software.
Creating immutable objects in Java
Programming immutable objects or constants in Java is very simple compared to other languages, since it has a specific keyword for it: “final”. To prevent a variable from being inherited, we simply declare it as final. Here is a practical example to illustrate this:
public final class Point {
private final int x;
private final int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public Punto desplazar(int deltaX, int deltaY) {
return new Point(this.x + deltaX, this.y + deltaY);
}
}
In this example, the class Point represents a point on a Cartesian plane with x and y coordinates. The x and y attributes are final, which means that they cannot be modified after initialisation in the constructor. Once a Point object is created, its coordinates cannot be changed.
In addition, the move method returns a new Point object with the coordinates moved according to the given arguments. Instead of modifying the current object, this method creates and returns a new object. Point with updated coordinates, thus maintaining the immutability of the original object.
Therefore, any instance of the class Point is immutable, The object's attributes cannot be modified once it is initialised, and any operation that apparently modifies the object actually creates and returns a new object with the modified state.