Используется для опционально


271

Пользуясь Java 8 уже более 6 месяцев, я очень доволен новыми изменениями API. Одна область, в которой я все еще не уверен, это когда использовать Optional. Я, кажется, колеблюсь между желанием использовать это везде, где-то может быть null, и нигде вообще.

Кажется, есть много ситуаций, когда я мог бы использовать это, и я никогда не уверен, добавляет ли это преимущества (удобочитаемость / нулевая безопасность) или просто вызывает дополнительные издержки.

Итак, у меня есть несколько примеров, и мне было бы интересно узнать мнение сообщества о том Optional, полезно ли это.

1 - как открытый тип возвращаемого метода, когда метод может вернуть null:

public Optional<Foo> findFoo(String id);

2 - В качестве параметра метода, когда параметр может быть null:

public Foo doSomething(String id, Optional<Bar> barOptional);

3 - В качестве необязательного члена компонента:

public class Book {

  private List<Pages> pages;
  private Optional<Index> index;

}

4 - в Collections:

В общем, я не думаю:

List<Optional<Foo>>

добавляет что-нибудь - тем более, что можно использовать filter()для удаления nullзначений и т. д., но есть ли хорошее применение для Optionalв коллекциях?

Любые случаи, которые я пропустил?


2
Один случай, который я считаю полезным, например, если у вас есть карта замещения. Например Map<Character, String>. Если нет никакой замены я могу использовать это: Optional.ofNullable(map.get(c)).orElse(String.valueOf(c)). Также обратите внимание, что Optional был украден из Гуавы, и у него гораздо более приятный синтаксис:Optional.fromNullable(map.get(c)).or(String.valueOf(c));
fge

3
Кроме того, в коллекциях, ну, есть коллекции, не допускающие нулевые значения! Необязательно подходит здесь. И вы можете .filter(Optional::absent)«
обнулить

2
@fge Честно говоря, я думаю, что концепция Optional на самом деле вытекает из FP.
VH-NZZ

2
@fge не так ли лучше выражен getOrDefault()?
Джим Гаррисон

Ответы:


206

Основная задача Optionalзаключается в том, чтобы обеспечить функцию, возвращающую значение, чтобы указать на отсутствие возвращаемого значения. Смотрите это обсуждение . Это позволяет вызывающей стороне продолжать цепочку быстрых вызовов методов.

Это наиболее близко соответствует варианту использования № 1 в вопросе OP. Хотя отсутствие значения является более точной формулировкой, чем ноль, поскольку что-то подобное IntStream.findFirstникогда не может вернуть ноль.

Для варианта использования # 2 , передавая необязательный аргумент методу, это можно сделать работающим, но это довольно неуклюже. Предположим, у вас есть метод, который принимает строку, за которой следует необязательная вторая строка. Принятие в Optionalкачестве второго аргумента приведет к следующему коду:

foo("bar", Optional.of("baz"));
foo("bar", Optional.empty());

Даже принимать ноль лучше

foo("bar", "baz");
foo("bar", null);

Вероятно, лучше всего иметь перегруженный метод, который принимает один строковый аргумент и обеспечивает значение по умолчанию для второго:

foo("bar", "baz");
foo("bar");

Это имеет ограничения, но это намного приятнее, чем любой из вышеперечисленных.

Варианты использования № 3 и № 4 , имеющиеOptional в поле класса или в структуре данных, считается неправильным использованием API. Во-первых, это идет вразрез с главной целью дизайна, Optionalкак указано выше. Во-вторых, это не добавляет никакой ценности.

Есть три способа справиться с отсутствием значения в Optional : предоставить замещающее значение, вызвать функцию для предоставления замещающего значения или вызвать исключение. Если вы сохраняете в поле, вы должны сделать это во время инициализации или назначения. Если вы добавляете значения в список, как упоминалось в OP, у вас есть дополнительный выбор - просто не добавлять значение, тем самым «выравнивая» отсутствующие значения.

Я уверен, что кто-то может придумать несколько надуманных случаев, когда они действительно хотят хранить их Optionalв поле или коллекции, но в целом лучше избегать этого.


47
Я не согласен с # 3. Может быть полезно иметь поле Optionalas, когда что-то должно быть сделано или не должно быть сделано при наличии или отсутствии значения.
glglgl

15
Я не понимаю, почему делать if(foo == null)это лучше, чем просто хранить поле как optional. И я не понимаю, почему явный getOptionalFoo()внутренний вызов лучше, чем просто сохранение поля как Optional. Кроме того, если одно поле может быть nullи одно поле не может быть null, почему бы не сообщить об этом компилятору, создав их Optionalили нет Optional.
Могроналол

27
@StuartMarks, это одна из вещей, которая просто сбивает меня с толку, когда я слышу это от всех Optional<>экспертов: «не храните Optional<>в поле». Я действительно пытаюсь понять смысл этой рекомендации. Рассмотрим дерево DOM, где у узла может быть родитель или нет. Кажется, в случае использования, Node.getParent()который вернется Optional<Node>. Неужели я собираюсь хранить nullи переносить результат каждый раз? Зачем? Что может принести мне эта дополнительная неэффективность, кроме того, что мой код выглядит ужасно?
Гаррет Уилсон

7
@GarretWilson С другой стороны, предположим, что у вас есть Optional<Node> getParent() { return Optional.ofNullable(parent); }. Это выглядит дорого, потому что он выделяет Optionalкаждый раз! Но если вызывающий распаковывает его немедленно, объект является чрезвычайно недолговечным и никогда не продвигается из райского пространства. Это может быть даже устранено анализом побега JIT. Суть ответа в следующем: «это зависит», но использование Optionalв полях потенциально увеличивает объем использования памяти и замедляет обход структуры данных. И, наконец, я думаю, что это загромождает код, но это дело вкуса.
Стюарт Маркс

6
@GarretWilson Так ты для этого написал блог? Мне было бы интересно это :)
akhil_mittal

78

Я опаздываю к игре, но за то, что она того стоит, я хочу добавить свои 2 цента. Они идут вразрез с целью разработкиOptional , которая хорошо описана в ответе Стюарта Маркса , но я все еще убежден в их обоснованности (очевидно).

Использовать дополнительно везде

В основном

Я написал целую запись в блоге об использовании,Optional но в основном это сводится к следующему:

  • разработайте свои классы, чтобы избежать возможности, где это возможно
  • во всех остальных случаях по умолчанию следует использовать Optionalвместоnull
  • возможно сделать исключения для:
    • локальные переменные
    • возвращать значения и аргументы в приватные методы
    • блоки кода, критичные к производительности (без предположений, используйте профилировщик)

Первые два исключения могут уменьшить воспринимаемые накладные расходы на упаковку и развертывание ссылок в Optional. Они выбраны так, что нуль никогда не может законно пройти границу из одного экземпляра в другой.

Обратите внимание, что это почти никогда не допустит Optionals в коллекциях, что почти так же плохо, как nulls. Просто не делай этого. ;)

По поводу ваших вопросов

  1. Да.
  2. Если перегрузка не вариант, да.
  3. Если другие подходы (создание подклассов, декорирование, ...) не подходят, да.
  4. Пожалуйста, нет!

преимущества

Это уменьшает присутствие nulls в вашей кодовой базе, хотя и не уничтожает их. Но это даже не главное. Есть и другие важные преимущества:

Проясняет намерение

Использование Optionalчетко выражает, что переменная, ну, необязательно. Любому читателю вашего кода или потребителю вашего API придется биться из-за того, что там ничего не может быть, и что необходима проверка перед доступом к значению.

Устраняет неопределенность

Без Optionalсмысла nullпроисшествия неясно. Это может быть юридическое представление состояния (см. Map.get) Или ошибка реализации, например, отсутствующая или неудачная инициализация.

Это резко меняется с постоянным использованием Optional . Здесь уже появление nullозначает наличие ошибки. (Потому что, если бы значение могло быть пропущено, использовался Optionalбы an .) Это значительно облегчает отладку исключения с нулевым указателем, поскольку на вопрос о значении этого nullуже дан ответ.

Больше нулевых проверок

Теперь, когда ничего не может быть null больше , это можно применять везде. При использовании аннотаций, утверждений или простых проверок вам никогда не придется задумываться о том, может ли этот аргумент или тип возвращаемого значения быть нулевым. Это не может!

Недостатки

Конечно, нет серебряной пули ...

Производительность

Упаковка значений (особенно примитивов) в дополнительный экземпляр может снизить производительность. В тесных петлях это может стать заметным или даже хуже.

Обратите внимание, что компилятор может обойти дополнительную ссылку для кратковременного времени жизни Optionals. В Java 10 типов значений могут дополнительно уменьшить или убрать штраф.

Сериализация

Optionalне сериализуем, но обходной путь не слишком сложен.

неизменность

Из-за неизменности универсальных типов в Java некоторые операции становятся громоздкими, когда фактический тип значения помещается в аргумент универсального типа. Пример приведен здесь (см. «Параметрический полиморфизм») .


Другим недостатком (или ограничением) является то, что вы не можете сортировать дополнительные (xxx) экземпляры, хотя Oracle явно наложил это ограничение намеренно. Я скептически отношусь к разумности использования этих классов там, где они должны использоваться только в определенных обстоятельствах, и предполагаю, что разработчик поступит правильно. Решение одной проблемы может вызвать другую. Может быть, должны быть предупреждения компилятора, чтобы помочь разработчику при использовании классов Optional (xxx) «нежелательными» способами (например, в качестве параметров метода, в коллекциях, в конструкторах и т. Д.), Если это действительно не предназначенное использование?
скомиса

Около 4, опций в коллекциях: на самом деле иногда полезно хранить опционы в Lists. Это тот случай, когда важно, чтобы определенный элемент находился по определенному индексу, но элемент может присутствовать или нет. Это ясно сообщается List<Optional<T>>типом. Если, с другой стороны, важно, какие объекты являются членами какой-то коллекции, то в этом нет никакого смысла.
Лий

3
Я думаю, что вариант использования № 2 все еще очень сомнителен. Существо Optional, переданное в метод, может быть null. Так что вы приобрели? Теперь у вас есть две проверки. См. Stackoverflow.com/a/31923042/650176
Дэвид V

2
@DavidV посмотрите на список преимуществ, которые я дал - все они применимы и к этому делу. Кроме того, если вы идете олл-ин Optional(что должно произойти, если вы хотите передать это в качестве аргументов), nullэто никогда не будет легальной ценностью. Поэтому вызов метода с явным параметром null, очевидно, является ошибкой.
Николай

28

Лично я предпочитаю использовать инструмент проверки кода IntelliJ, чтобы использовать его @NotNullи @Nullableпроверять, так как это в основном время компиляции (может иметь некоторые проверки во время выполнения). Это снижает издержки с точки зрения читабельности кода и производительности во время выполнения. Это не так строго, как использование Optional, однако это отсутствие строгости должно быть подкреплено достойными юнит-тестами.

public @Nullable Foo findFoo(@NotNull String id);

public @NotNull Foo doSomething(@NotNull String id, @Nullable Bar barOptional);

public class Book {

  private List<Pages> pages;
  private @Nullable Index index;

}

List<@Nullable Foo> list = ..

Это работает с Java 5 и не нужно оборачивать и разворачивать значения. (или создайте объекты-оболочки)


7
Хм, это аннотации IDEA? Я предпочитаю JSR 305 @Nonnullлично - работает с FindBugs;)
fge

@fge В этом отношении нет стандартов, но я считаю, что инструменты, как правило, настраиваемы, и вам не нужно заканчивать@Nonnull @NotNull etc
Питер Лоури,

4
Да это правда; IDEA (13.x) предлагает три разных варианта ... Мех, я всегда заканчиваю тем, что использую JSR 305 в любое время
fge

3
Я знаю, что это старое, но обсуждение аннотаций и инструментов заслуживает ссылки на stackoverflow.com/questions/35892063/… - между прочим, который конкретно касается случая Java 8.
Стефан Херрманн

25

Я думаю, что Гуава Факультативно и их вики-страница довольно хорошо это описывают:

Помимо повышения читабельности за счет присвоения нулевому имени, самым большим преимуществом Optional является его защита от идиотов. Это заставляет вас активно думать об отсутствующем кейсе, если вы хотите, чтобы ваша программа вообще компилировалась, поскольку вы должны активно развернуть Optional и заняться этим кейсом. Null позволяет легко забыть о вещах, и хотя FindBugs помогает, мы не думаем, что это решает проблему также.

Это особенно актуально, когда вы возвращаете значения, которые могут присутствовать или не присутствовать. Вы (и другие) с гораздо большей вероятностью забудете, что other.method (a, b) может вернуть нулевое значение, чем вы, вероятно, забудете, что a может быть нулевым, когда вы реализуете other.method. Возврат Optional делает невозможным для вызывающих абонентов забыть об этом случае, так как им приходится самостоятельно разворачивать объект для компиляции кода. - (Источник: Guava Wiki - Использование и уход от нуля - Какой смысл? )

Optionalдобавляет некоторые накладные расходы, но я думаю, что его явное преимущество заключается в том, чтобы сделать явным, что объект может отсутствовать, и это заставляет программистов справляться с ситуацией. Это предотвращает то, что кто-то забудет любимого!= null чек.

Взяв пример 2 , я думаю, что это гораздо более явный код для записи:

if(soundcard.isPresent()){
  System.out.println(soundcard.get());
}

чем

if(soundcard != null){
  System.out.println(soundcard);
}

Для меня Optional лучше фиксирует тот факт, что звуковой карты нет.

Мои 2 ¢ о ваших баллах:

  1. public Optional<Foo> findFoo(String id);- Я не уверен в этом. Может быть, я бы вернул, Result<Foo>который может быть пустым или содержать Foo. Это похожая концепция, но не совсем Optional.
  2. public Foo doSomething(String id, Optional<Bar> barOptional);- Я бы предпочел @Nullable и проверку findbugs, как в ответе Питера Лори - см. Также это обсуждение .
  3. Пример вашей книги - я не уверен, что буду использовать Optional для внутреннего использования, это может зависеть от сложности. Для «API» книги я бы использовалOptional<Index> getIndex() чтобы явно указать, что книга может не иметь индекса.
  4. Я бы не использовал его в коллекциях, скорее не допустив нулевые значения в коллекциях

В общем, я бы попытался свести к минимуму прохождение вокруг nulls. (После того, как сгорел ...) Я думаю, что стоит найти соответствующие абстракции и указать коллегам-программистам, что на самом деле представляет определенное возвращаемое значение.


15
Вы бы написали soundcard.ifPresent(System.out::println). Вызов isPresentсемантически такой же, как проверка null.
лучший оливер

Для меня проблема в том, что вещи с необязательными типами все еще могут быть нулевыми. Таким образом, чтобы действительно быть в полной безопасности, вы должны сделать что-то вроде if(soundcard != null && soundcard.isPresent()). Хотя создание API, которое возвращает Optional и может также возвращать NULL, я надеюсь, что никто этого не сделает.
Саймон Баумгардт-Велландер

«Это заставляет вас активно думать об отсутствующем случае, если вы хотите, чтобы ваша программа вообще компилировалась, так как вам нужно активно развернуть Optional и заняться этим случаем». Я не совсем уверен, как это происходит, хотя я не очень много работаю на Java. Не могли бы вы объяснить, что делает Java, чтобы заставить вас развернуть и проверить случай! IsPresent для простой компиляции?
раздавить

15

Из учебника Oracle :

Цель Optional состоит не в том, чтобы заменить каждую пустую ссылку в вашей кодовой базе, а в том, чтобы помочь разработать более совершенные API, в которых - просто читая сигнатуру метода - пользователи могут определить, ожидать ли необязательного значения. Кроме того, Optional заставляет вас активно разворачивать Optional, чтобы справиться с отсутствием значения; в результате вы защищаете свой код от непреднамеренных исключений нулевого указателя.


3
API только для возвращаемой части метода, верно? Необязательные не должны использоваться в качестве параметров из-за стирания типа? иногда я использую Optional внутренне в методе, преобразованном из обнуляемого параметра или как поле, инициализируемое из нулевого параметра конструктора ... все еще пытаюсь выяснить, является ли это более полезным, чем просто оставить его пустым - у кого-нибудь есть какие-нибудь мысли?
Ycomp

@ycomp Вы можете найти довольно много информации о тех случаях , в этом или что вопрос. Ответы на эти вопросы говорят гораздо больше, чем то, о чем их спрашивали, и охватывают другие случаи. Для получения дополнительной информации просмотрите больше или задайте свой собственный вопрос, потому что, вероятно, вы не получите здесь много внимания. ; )
ctomek

8

1 - как открытый тип возвращаемого метода, когда метод может возвратить нуль:

Вот хорошая статья, которая показывает полезность варианта использования №1. Там этот код

...
if (user != null) {
    Address address = user.getAddress();
    if (address != null) {
        Country country = address.getCountry();
        if (country != null) {
            String isocode = country.getIsocode();
            isocode = isocode.toUpperCase();
        }
    }
}
...

превращается в это

String result = Optional.ofNullable(user)
  .flatMap(User::getAddress)
  .flatMap(Address::getCountry)
  .map(Country::getIsocode)
  .orElse("default");

с помощью Факультативно в качестве возвращаемого значения соответствующих геттерных методов.


2

Вот интересное использование (я считаю) для ... Тесты.

Я намерен серьезно протестировать один из моих проектов и поэтому строю утверждения; только есть вещи, которые я должен проверить, а другие - нет.

Поэтому я создаю вещи для утверждения и использую утверждение для их проверки, например так:

public final class NodeDescriptor<V>
{
    private final Optional<String> label;
    private final List<NodeDescriptor<V>> children;

    private NodeDescriptor(final Builder<V> builder)
    {
        label = Optional.fromNullable(builder.label);
        final ImmutableList.Builder<NodeDescriptor<V>> listBuilder
            = ImmutableList.builder();
        for (final Builder<V> element: builder.children)
            listBuilder.add(element.build());
        children = listBuilder.build();
    }

    public static <E> Builder<E> newBuilder()
    {
        return new Builder<E>();
    }

    public void verify(@Nonnull final Node<V> node)
    {
        final NodeAssert<V> nodeAssert = new NodeAssert<V>(node);
        nodeAssert.hasLabel(label);
    }

    public static final class Builder<V>
    {
        private String label;
        private final List<Builder<V>> children = Lists.newArrayList();

        private Builder()
        {
        }

        public Builder<V> withLabel(@Nonnull final String label)
        {
            this.label = Preconditions.checkNotNull(label);
            return this;
        }

        public Builder<V> withChildNode(@Nonnull final Builder<V> child)
        {
            Preconditions.checkNotNull(child);
            children.add(child);
            return this;
        }

        public NodeDescriptor<V> build()
        {
            return new NodeDescriptor<V>(this);
        }
    }
}

В классе NodeAssert я делаю это:

public final class NodeAssert<V>
    extends AbstractAssert<NodeAssert<V>, Node<V>>
{
    NodeAssert(final Node<V> actual)
    {
        super(Preconditions.checkNotNull(actual), NodeAssert.class);
    }

    private NodeAssert<V> hasLabel(final String label)
    {
        final String thisLabel = actual.getLabel();
        assertThat(thisLabel).overridingErrorMessage(
            "node's label is null! I didn't expect it to be"
        ).isNotNull();
        assertThat(thisLabel).overridingErrorMessage(
            "node's label is not what was expected!\n"
            + "Expected: '%s'\nActual  : '%s'\n", label, thisLabel
        ).isEqualTo(label);
        return this;
    }

    NodeAssert<V> hasLabel(@Nonnull final Optional<String> label)
    {
        return label.isPresent() ? hasLabel(label.get()) : this;
    }
}

Что означает, что утверждение действительно только срабатывает, если я хочу проверить метку!


2

OptionalКласс позволяет вам избегать использования nullи предоставляет лучшую альтернативу:

  • Это побуждает разработчика делать проверки на наличие, чтобы избежать неперехвата NullPointerException.

  • API становится лучше документированным, потому что можно увидеть, где ожидать значений, которые могут отсутствовать.

Optionalпредоставляет удобный API для дальнейшей работы с объектом isPresent():; get(); orElse(); orElseGet(); orElseThrow(); map(); filter();flatmap(),

Кроме того, многие фреймворки активно используют этот тип данных и возвращают его из своего API.


2

В Java просто не используйте их, если вы не зависимы от функционального программирования.

Им не место в качестве аргументов метода (я обещаю, что однажды кто-нибудь передаст вам необязательное значение null, а не просто необязательное значение, которое будет пустым).

Они имеют смысл для возвращаемых значений, но они предлагают клиентскому классу продолжать растягивать цепочку построения поведения.

FP и цепочки мало места в императивном языке, таком как java, потому что его очень трудно отлаживать, а не просто читать. Когда вы выходите на линию, вы не можете знать ни состояние, ни цель программы; Вы должны войти в это, чтобы понять это (в коде, который часто не ваш и имеет много фреймов стека, несмотря на пошаговые фильтры), и вам нужно добавить множество точек останова, чтобы убедиться, что он может остановиться в добавленном вами коде / лямбде, вместо простого обхода тривиальных строк if / else /.

Если вы хотите функциональное программирование, выберите что-то еще, кроме java, и надеюсь, что у вас есть инструменты для его отладки.


1

Я не думаю, что Optional является общей заменой методов, которые потенциально могут возвращать нулевые значения.

Основная идея такова: отсутствие значения не означает, что оно потенциально доступно в будущем. Это разница между findById (-1) и findById (67).

Основная информация о дополнительных возможностях для вызывающего абонента заключается в том, что он может не рассчитывать на данное значение, но оно может быть доступно через некоторое время. Может быть, он снова исчезнет и вернется позже еще раз. Это как выключатель. У вас есть «опция», чтобы включить или выключить свет. Но у вас нет выбора, если у вас нет света, чтобы включить.

Поэтому я нахожу это слишком грязным, чтобы вводить Optionals везде, где ранее мог быть возвращен нуль Я все еще буду использовать ноль, но только в ограниченных областях, таких как корень дерева, ленивая инициализация и явные методы поиска.


0

Кажется , Optionalэто только полезно , если тип T в Опционно примитивный тип , как int, long, charи т.д. Для «реальных» классов, это не имеет смысла для меня , как вы можете использовать nullзначение в любом случае.

Я думаю, что это было взято отсюда (или из другой подобной языковой концепции).

Nullable<T>

В C # это Nullable<T>было введено давно, чтобы обернуть типы значений.


2
На Optionalсамом деле это грабеж
Гуавы

2
@fge Хорошо, но когда это присутствовало в C # (2005, MS.NET 2.0), я думаю, что Гуавы не было. И ... кто знает, откуда C # взял это.
peter.petrov

3
@fge "Ripoff of Guava's Optional" - довольно забавный способ выразить это, поскольку парни из Гуавы участвовали в обсуждениях, рассказывали о своем опыте и в целом поддерживали его java.util.Optional.
Стюарт Маркс

6
@fge Нет сомнений в том, что API Java сильно повлияли на Guava. Я не согласен с "грабежом", который звучит как воровство. Ребята из Гуавы внесли много ценных идей в Java 8.
Стюарт Маркс

6
Вы упускаете суть. Необязательный должен использоваться вместо возврата ноль. Это безопаснее, чем потенциально генерировать исключение NullPointerException. Смотрите: oracle.com/technetwork/articles/java/…
Килизо

0

An имеет семантику, аналогичную неизменяемому экземпляру шаблона проектирования Iterator :Optional

  • это может или не может относиться к объекту (как дано isPresent() )
  • это может быть разыменовано (использование get()), если это действительно относится к объекту
  • но он не может быть продвинут на следующую позицию в последовательности (у него нет next()метода).

Поэтому подумайте о возврате или передаче Optionalв контекстах, в которых вы, возможно, ранее рассматривали возможность использования Java Iterator.


-1

Java SE 8 представляет новый класс с именем java.util.Optional,

Вы можете создать пустой Optional или Optional с нулевым значением.

Optional<String> emptyOptional = Optional.empty(); 

А вот Optional с ненулевым значением:

String valueString = new String("TEST");
Optional<String> optinalValueString = Optional.of(valueString );

Сделайте что-нибудь, если значение присутствует

Теперь, когда у вас есть дополнительный объект, вы можете получить доступ к доступным методам, чтобы явно иметь дело с наличием или отсутствием значений. Вместо того, чтобы не забыть сделать проверку на ноль, следующим образом:

String nullString = null;
if (nullString != null) {
    System.out.println(nullString);
}

Вы можете использовать метод ifPresent () следующим образом:

Optional<String> optinalString= null;
optinalString.ifPresent(System.out::println);

package optinalTest;

import java.util.Optional;

public class OptionalTest {
    public Optional<String> getOptionalNullString() {
        return null;
//      return Optional.of("TESt");
    }

    public static void main(String[] args) {

        OptionalTest optionalTest = new OptionalTest();

        Optional<Optional<String>> optionalNullString = Optional.ofNullable(optionalTest.getOptionalNullString());

        if (optionalNullString.isPresent()) {
            System.out.println(optionalNullString.get());
        }
    }
}

эта копировальная паста предназначена для получения дешевой репутации, но не связана с вопросами ОП
жало
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.