Что такое immutable объекты в Java
Это многофункциональные immutable (неизменяемые) объекты, которые можно применять в разных частях программы.
Например, это могут быть неизменяемые объекты в многопоточной среде для работы с данными. Также это могут быть сложные константы, которые помогают избежать излишнего использования памяти и перегрузки сборщика мусора (garbage collector). Отдельно стоит упомянуть иммутабельность при работе с коллекциями.
Основные параметры имутабельных классов (immutable classes)
Для того чтобы сказать, что класс является immutable (неизменяемым) он должен соотвествовать следующим критериям:
- Не предоставляйте методы, которые модифицируют состояние объекта. Такие методы могут напрямую модифировать состояние объекта класса.
- Убедитесь, что класс нельзя наследовать. Наследовав класс можно с легкостью получить доступ к его полям, где далее их можно легко модифицировать.
- Сделайте все поля в классе final. Таким образом мы показывае наше намерение относительно того можно ли модифицировать поля в классе.
- Сделайте все поля в классе private. Добавив этот атрибут к полю мы закроем доступ, где можно напрямую модифицировать поля класса.
- Убедитесь, что класс не предоставляет эксклюзивный доступ к изменяемым объектам. Если например в классе существуют сложные объекты (коллекции, другие сложные классы и тп) нужно предосмотреть возоможность создания копии этого поля для того, чтобы не было возможности модифицировать его посредством ссылки.
Практическое применение immutable объектов

На практике, иммутабельность позволяет строить более стабильные программы и ее принципы зачастую применимы в фундаментальных частях софта.
Например, это могут быть сложные константы и строки, которые могут использоваться, как конфигурация программы или как базовые данные.
Сложные константы
В проекте может быть много статических констант для отображения разных состояний, статусов. Если взять, к примеру, то как работают под капотом базовые классы оберток простых типов можно увидеть что практически все они иммутабельны.
Например, класс Boolean и то как там устанавливаются состояния объекта:
public static final Boolean TRUE = new Boolean(true);
public static final Boolean FALSE = new Boolean(false);
public static Boolean valueOf(boolean b) {
return b ? TRUE : FALSE;
}
Также пример с BigInteger:
public static final BigInteger ZERO;
public static final BigInteger ONE;
public static final BigInteger TWO;
public static final BigInteger TEN;
private static final BigDecimal ZERO_THROUGH_TEN[] = {
new BigDecimal(BigInteger.ZERO, 0, 0, 1),
new BigDecimal(BigInteger.ONE, 1, 0, 1),
new BigDecimal(BigInteger.TWO, 2, 0, 1),
new BigDecimal(BigInteger.TEN, 10, 0, 2),
};
...
totalBig = totalBig.divide(BigInteger.TEN);
В многопоточности (java tread safety)

Иногда, когда объект обрабатывается в многопоточной среде нужно отделить переменные, которые должны быть уникальными в рамках отдельного потока. Для этого может быть много причин.
Для этой цели можно использовать ThreadLocal класс. Ниже приведен пример использования локальных переменных для каждого отдельного потока.
public class ThreadExample {
public static final ThreadLocal<StateExampleHolder> statePerThreadExample = new ThreadLocal<StateExampleHolder>() {
@Override
protected StateExampleHolder initialValue() {
return new StateExampleHolder("started");
}
};
public static StateExampleHolder getStatus() {
return statePerThreadExample.get();
}
}
В коллекциях
Как известно, зачастую, некоторые коллекции состоят из пары ключ, значение. Если рассмотреть более подробнее, например, коллекцию HashMap можно увидеть, что благодаря хешу ключа внутренний механизм коллекции определяет в какой бакет нужно положить объект.
Представьте, что ключ будет изменяемым. Допустим вы положили объект в коллекцию с определенным ключем, например, «one». Далее в процессе объект ключа поменял хеш код и внутренние состояние. Буквально значение стало «two».
Из примера выше, очевидно, что значение по ключу «one» мы уже потеряли и достать его из коллекции будет невозможно.
В таком случае имутабельность решает вопрос с потерей объектов в коллекции, так как состояние и хеш код изменить уже нельзя, ничего не теряется.
Строки (string) immutable

Строки пожалуй один из самых часто используемых классов. Ранее мы уже писали о String Pool, как хранятся строки в памыти, а также мы делали базовый обзор класса String в Java.
Как известно, сами строки не изменяемые (immutable). Каждый раз когда строка модифицируется, создается новый объект класса String. Поэтому для изменяемых строк сушествуют StringBuilder, StringBuffer.
А как обстоит дело со строковыми литерами? Если например меняется ссылка на строку, меняется ли и значение? Давайте рассмотрим пример:
String str1 = "Java is the best program language in the world";
String str2 = str1;
System.out.println(str2);
str1 = "No С++ the first";
System.out.println(str2);
Так как строки действительно являются не изменяемыми, результат будет очевиден:
Java is the best program language in the world
Java is the best program language in the world
Перечень часто используемых immutable классов в Java
Почти все классы обертки примитивных типов: Integer, String, Short, Boolean, BigInteger, BigDecimal и другие.