1. Четкие, собственные и описательные имена
Optional<String> value1 = Optional.empty(); Optional<String> value2 = Optional.of("this is not null"); Optional<String> value3 = Optional.ofNullable(null);
Хорошо выбранное имя легче использовать, а полученный клиентский код легче читать. Класс может иметь конструктор только с такой же сигнатурой. Статические фабричные методы не имеют этого ограничения, выбирайте имена, которые должным образом подчеркивают их различия.
2. Не требуется создавать новый экземпляр для каждого вызова
Неизменяемые и окончательные классы могут использовать предварительно созданные экземпляры или кэшировать экземпляры по мере их создания. Эти экземпляры возвращаются в клиентский код, чтобы избежать создания ненужных повторяющихся объектов. Эта техника похожа на паттерн наилегчайшего веса.
3. Возможность возвращать объекты любого подтипа их возвращаемого типа
class Person { String firstName; String lastName; Person(String firstName, String lastName) { this.firstName = firstName; this.lastName = lastName; } static Person newStudent(String firstName, String lastName) { return new Student(firstName, lastName); } } class Student extends Person { Student(String firstName, String lastName) { super(firstName, lastName); } }
Это дает вам гибкость в выборе класса возвращаемого объекта. Клиент обращается к возвращаемому объекту по интерфейсу, а не по классу реализации. Допускается любой подтип объявленного возвращаемого типа. Класс возвращаемого объекта может варьироваться от версии к версии, клиенты не знают и не заботятся о классе объекта, который они получают с завода.