Разработка программ. Мои заметки.

February 4, 2017 at 22:15

NullPointerException в Java. Как использовать class Optional.

7. Как использовать class Optional.

После того, как этот класс появился в стандартной библиотеке Java, некоторое количество народа начало его использовать прямо в лоб, объявляя в своих классах поля типа Optional. Просто потому, что они могут содержать null. Разумеется, любая переменная, указывающая на непримитивный тип данных, может хранить null. Но стоит ли её сразу объявлять как Optional?

Я не знаю как много было этих людей, но статьи с примерами такого употребления класса действительно встречались. На одну из них я сослался в предыдущей заметке. Разработчики языка и инструментов довольно быстро написали - ребята, не нужно так незамысловато использовать этот класс. Мы его для другого планировали!

С мнением архитектора языка Java — Brian Goetz, можно ознакомиться на Stack Overflow. Ещё несколько ссылок я приведу в конце. А пока, перейдём сразу к делу. Итак, какие же ограничения у класса Optional?

Важным ограничением является то, что класс Optional не реализует интерфейс Serializable. Это значит что его не рекомендуется использовать в полях классов, описывающих вашу бизнес модель (бизнес-объектах) или в DTO (Data Transfer Object).

Не рекомендуется использовать Optional и в качестве входных параметров методов и конструкторов.

Теперь осталось самое интересное — рассмотреть где же его такого чудесного рекомендуется использовать. А советуют его использовать как возвращаемое значение в методах. Ещё раз — Не нужно объявлять поля класса (properties) как Optional. Тип Optional рекомендуется использовать для возвращаемых значений в методах.

Выглядит это так:


    public static Optional<User> findUserWithLogin( String login )
    {
        User user = ...     // Поиск нужного пользователя
        ...
        return Optional.ofNullable( user );
    }

    public static void doSomethingWithTheUser( User user )
    {
        System.out.println( user.getLogin() );
    }
    
    ...

    // Вариант 1

    findUserWithLogin( "ЗоркийСокол54" ).ifPresent( user -> doSomethingWithTheUser( user ) );

    // Вариант 2

    findUserWithLogin( "ЗоркийСокол54" ).ifPresent( Main::doSomethingWithTheUser );

Вот так вот коротко и изящно. Вместо класса Main должно стоять имя того класса в котором объявлен этот статический метод.

Тут хотелось бы сказать пару слов про метод, который вызывается через лямбду — doSomethingWithTheUser. Если вы ещё не поднаторели в лямбдах и Optional, то обратите внимание — сигнатура этого метода должна быть такова, что он обязательно должен получать в параметре объект класса User (потому что у нас метод findUserWithLogin возвращает Optional<User>). Только в этом случае его можно будет использовать в методе ifPresent. И, благодаря магии функционального программирования, он получит в параметре тот самый объект типа User, который отыскал метод findUserWithLogin. И вы сможете делать с ним всё что захотите.

А если метод findUserWithLogin не нашёл нужного объекта, то никакой метод вызван не будет. И никакого NullPointerException также не будет.

Тут немного ранее обещанных ссылок. Хороший пример и пояснение я нашёл в блоге у Stephen Colebourne. Часть первая. и Часть вторая.

Также несколько советов дала сотрудница компании JetBrains — Trisha Gee в блоге своей компании. С ними можно ознакомиться тут.

Автор — Владимир Рыбов