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);
    }
}

Это дает вам гибкость в выборе класса возвращаемого объекта. Клиент обращается к возвращаемому объекту по интерфейсу, а не по классу реализации. Допускается любой подтип объявленного возвращаемого типа. Класс возвращаемого объекта может варьироваться от версии к версии, клиенты не знают и не заботятся о классе объекта, который они получают с завода.