Плохая работа с датами
Использование при проектировании изменяемых объектов, которые не должны быть таковыми, может показаться очевидной ошибкой, но ее допускают даже самые умные проектировщики API. Первая версия стандартной библиотеки Java содержала класс Date с серьезным архитектурным изъяном74. Он представлял конкретную дату, такую как 28 января 1972 года, 08:24 UTC. К сожалению, он был изменяемым: если у вас была ссылка на такой объект, вы могли его модифицировать с помощью таких сеттеров, как setHour, setYear и т.д. Это создавало большие проблемы для любых сущностей, которые использовали дату в качестве одного из своих атрибутов. Было допущено много ошибок, в ходе которых объект Date возвращался из сущности и затем модифицировался снаружи. Некоторые из них привели к появлению уязвимостей.
Это очевидный архитектурный изъян в классе java.util.Date. Дата должна быть объектом-значением, а объекты-значения не должны изменяться, иначе в них нет никакого смысла. Мы ведь не говорим: «Это сегодняшняя дата, только измененная на завтрашнюю». Сегодня — один день, завтра — другой75. К сожалению, класс java.util.Date был спроектирован изменяемым, и, несмотря на то что многие его методы уже выведены из использования, сеттер setTime остается актуальным.
Если коротко, то мы не рекомендуем использовать java.util.Date. Вместо него лучше применять такую современную библиотеку, как пакет java.time76.
Если при написании кода вы по какой-то причине вынуждены работать с изменяемым объектом, можете воспользоваться одним приемом: перед тем как вернуть из метода ссылку на инкапсулированный объект, клонируйте его. Таким образом ваш изменяемый объект не будет модифицирован кем-то другим. Если внешний код воспользуется ссылкой, которую вы вернули, он изменит только копию объекта, но не оригинал. В листинге 6.11 показано, как этот прием можно применить к java.util.Date.