Почему Java 8 необязательно не использовать в аргументах

392

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

public int calculateSomething(Optional<String> p1, Optional<BigDecimal> p2 {
    // my logic
}

Многие веб-страницы указывают, что Необязательно не следует использовать в качестве аргументов метода. Имея это в виду, я мог бы использовать следующую сигнатуру метода и добавить четкий комментарий Javadoc, чтобы указать, что аргументы могут быть нулевыми, надеясь, что будущие сопровождающие будут читать Javadoc и, следовательно, всегда выполнять нулевые проверки перед использованием аргументов (решение 2) :

public int calculateSomething(String p1, BigDecimal p2) {
    // my logic
}

В качестве альтернативы я мог бы заменить свой метод четырьмя открытыми методами, чтобы обеспечить более приятный интерфейс и сделать его более очевидным, p1 и p2 являются необязательными (решение 3):

public int calculateSomething() {
    calculateSomething(null, null);
}

public int calculateSomething(String p1) {
    calculateSomething(p1, null);
}

public int calculateSomething(BigDecimal p2) {
    calculateSomething(null, p2);
}

public int calculateSomething(String p1, BigDecimal p2) {
    // my logic
}

Теперь я пытаюсь написать код класса, который вызывает этот кусок логики для каждого подхода. Сначала я получаю два входных параметра из другого объекта, который возвращает Optionals, а затем вызываю calculateSomething. Поэтому, если используется решение 1, вызывающий код будет выглядеть так:

Optional<String> p1 = otherObject.getP1();
Optional<BigInteger> p2 = otherObject.getP2();
int result = myObject.calculateSomething(p1, p2);

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

Optional<String> p1 = otherObject.getP1();
Optional<BigInteger> p2 = otherObject.getP2();
int result = myObject.calculateSomething(p1.orElse(null), p2.orElse(null));

если применяется решение 3, я мог бы использовать приведенный выше код или следующее (но это значительно больше кода):

Optional<String> p1 = otherObject.getP1();
Optional<BigInteger> p2 = otherObject.getP2();
int result;
if (p1.isPresent()) {
    if (p2.isPresent()) {
        result = myObject.calculateSomething(p1, p2);
    } else {
        result = myObject.calculateSomething(p1);
    }
} else {
    if (p2.isPresent()) {
        result = myObject.calculateSomething(p2);
    } else {
        result = myObject.calculateSomething();
    }
}

Итак, мой вопрос: почему считается плохой практикой использовать Optionals в качестве аргументов метода (см. Решение 1)? Это выглядит как наиболее читаемое решение для меня и делает наиболее очевидным, что параметры могут быть пустыми / нулевыми для будущих сопровождающих. (Я знаю, что разработчики Optionalпредполагали, что он будет использоваться только в качестве возвращаемого типа, но я не могу найти логических причин не использовать его в этом сценарии).

Нил Стивенс
источник
16
Если вы использовали опциональные параметры, не нужно ли проверять, что опциональный параметр, переданный как параметр, не является null?
Бизиклоп
17
Да, но для кого-то еще, кто будет поддерживать код в будущем, станет очевидным, что параметр может быть пустым / пустым, что потенциально позволит избежать исключения нулевого указателя в будущем
Нил Стивенс
1
Ух ты. Пустые аргументы передаются в метод? Это так Visual Basic. Какой принцип это нарушает? SRP (возможно). Это также нарушает другой принцип, чье имя лишает меня смысла, идет по пути передачи ТОЛЬКО необходимой информации для метода или функции, выполняющих свою работу.
Световой
20
Все, что теоретически возможно является нулевым, подобно любому методу в библиотеке, возможно вызывающему System.exit (0). Вы не можете проверить против этого и не должны проверять против этого. Все, что вы должны делать все время, которое вы (почти) никогда не должны делать. Как сделать все параметры окончательными. Позвольте вашим инструментам помочь вам предотвратить изменение значений параметров или забыть инициализировать поля вместо того, чтобы сделать ваш код нечитаемым для тысячи финалов и столько же нулевых проверок.
йомен
6
На самом деле просто используйте аннотации NonNull / Nullable, это то, что вы ищете в этой ситуации, а не опционально.
Билл К

Ответы:

202

О, эти стили кодирования должны быть приняты с небольшим количеством соли.

  1. (+) Передача необязательного результата другому методу без какого-либо семантического анализа; оставив это методу, вполне нормально.
  2. (-) Использование необязательных параметров, вызывающих условную логику внутри методов, в буквальном смысле неэффективно.
  3. (-) Необходимость упаковать аргумент в Optional, является неоптимальной для компилятора и делает ненужное перенос.
  4. (-) По сравнению с обнуляемыми параметрами Optional является более дорогостоящим.

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

Joop Eggen
источник
38
На самом деле наличие Optionalпараметра представляет одно из трех состояний: nullнеобязательное, ненулевое Optionalс isPresent() == falseи ненулевое, Optionalзаключающее в себе фактическое значение.
Бизиклоп
16
@biziclop да, неизбежный момент уже подвергся критике. Но намерение состоит в том, чтобы иметь только ненулевые выражения. То, что это не заняло много времени, услышать совет, чтобы избежать Факультативного в некоторых случаях тоже, довольно иронично. @NotNull Optional.
Joop Eggen
80
@biziclop Обратите внимание, что если вы используете Optionalвообще, то состояние 1 ( nullНеобязательно) обычно указывает на ошибку программирования, так что вы можете также не обрабатывать ее (просто дайте ей выкинуть NullPointerException)
user253751
50
«неоптимальный для компилятора», «по сравнению с необязательными параметрами Optional более дорогой» - эти аргументы могут быть действительными для языка C, а не для языка Java. Java-программисты должны сосредоточиться на чистом коде, переносимости, тестируемости, хорошей архитектуре, модульности и т. Д., А не на том, что «Optional более дорогой, чем нулевая ссылка». И если вы обнаружите, что вам нужно сосредоточиться на микрооптимизации, вам лучше пропустить Объекты, Списки, Обобщения и переключиться на массивы и примитивы (я не хочу обижаться здесь, я просто делюсь своим мнением) ,
Kacper86
15
«неоптимальный для компилятора»: преждевременная оптимизация - корень всего зла ... если вы не пишете критичный к производительности код (что часто бывает при попытке указать чистый интерфейс), это не должно вызывать беспокойства.
Мохан
165

Лучший пост я видел на эту тему был написан Даниэлем Ольшевским :

Хотя может показаться заманчивым рассмотреть Необязательные для необязательных параметров метода, такое решение бледнеет по сравнению с другими возможными альтернативами. Чтобы проиллюстрировать проблему, изучите следующее объявление конструктора:

public SystemMessage(String title, String content, Optional<Attachment> attachment) {
    // assigning field values
}

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

SystemMessage withoutAttachment = new SystemMessage("title", "content", Optional.empty());
Attachment attachment = new Attachment();
SystemMessage withAttachment = new SystemMessage("title", "content", Optional.ofNullable(attachment));

Вместо обеспечения ясности фабричные методы класса Optional только отвлекают читателя. Обратите внимание, что есть только один необязательный параметр, но представьте, что у вас есть два или три. Дядя Боб определенно не будет гордиться таким кодом 😉

Когда метод может принимать необязательные параметры, предпочтительно принять хорошо зарекомендовавший себя подход и спроектировать такой случай с использованием перегрузки метода. В примере класса SystemMessage объявление двух отдельных конструкторов лучше, чем использование Optional.

public SystemMessage(String title, String content) {
    this(title, content, null);
}

public SystemMessage(String title, String content, Attachment attachment) {
    // assigning field values
}

Это изменение делает клиентский код намного проще и легче для чтения.

SystemMessage withoutAttachment = new SystemMessage("title", "content");
Attachment attachment = new Attachment();
SystemMessage withAttachment = new SystemMessage("title", "content", attachment);
Гили
источник
10
Это много копирование + вставка, когда только один или два абзаца актуальны.
Гаррет Уилсон
47
К сожалению, это объяснение не решает проблему, например, когда вызывающий абонент анализирует некоторую информацию, может быть необязательным. С перегрузкой метода (как рекомендовано выше) вызывающий код должен сказать: «X присутствует? Если да, я вызову перегруженный метод A. Присутствует ли Y? Мне придется вызывать перегруженный метод B. Если X и Y присутствуют, мне придется вызвать перегруженный метод C. " И так далее. Может быть хороший ответ на это, но это объяснение «почему» не охватывает это.
Гаррет Уилсон
9
Кроме того, когда дело доходит до коллекций, существует четкая разница между пустой коллекцией и отсутствием коллекции. Например, кеш. Это был промах кеша? пусто необязательно / ноль. Был ли удар по кэшу, который оказался пустой коллекцией? полный опционально / сборник.
Аякс
1
@Ajax Я думаю, вы неправильно поняли статью. Они цитируют точку зрения, поддерживаемую книгой Effective Java , в которой говорится, что если тип возвращаемого метода - это Collection (а не произвольный объект, который должен возвращать кеш), то вы должны предпочесть возврат пустой коллекции вместо nullили Optional.
Гили
4
Конечно, вы должны одобрять это, но вы не всегда можете контролировать некоторый код, и, в очень реальном смысле, вы можете различать «есть значение и это пустая коллекция» и «нет» значение определено (пока) ". Поскольку «магический ноль» также является нежелательной практикой, вы, разработчик, должны выбрать наименее плохой вариант. Я предпочитаю пустой опциональный, чтобы представлять промах кэша вместо пустой коллекции, так как фактическое кэшированное значение может быть пустой коллекцией.
Аякс
86

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

Функциональные языки программирования поддерживают Optionalпараметры. Один из лучших способов использовать это - иметь несколько необязательных параметров и использовать liftM2для использования функции, предполагая, что параметры не пусты, и возвращая необязательные (см. Http://www.functionaljava.org/javadoc/4.4/functionaljava/fj/ data / Option.html # liftM2-fj.F- ). К сожалению, в Java 8 реализована очень ограниченная поддержка библиотек.

Как программисты на Java, мы должны использовать только null для взаимодействия с устаревшими библиотеками.

Марк Перри
источник
3
Как насчет использования @Nonnullи @Nullableиз javax.annotation вместо этого? Я широко использую их в своей библиотеке, и поддержка, предоставляемая IDE (IntelliJ), очень хорошая.
Рожерио
1
Это нормально, но вы должны использовать эту аннотацию везде, и вам нужна библиотека для поддержки таких методов, как map, flatMap / bind, liftM2, sequence и т. Д.
Марк Перри
14
Функциональные языки программирования поддерживают дополнительные параметры. Нужна цитата. Большинство функций не должны принимать опционально; вместо этого бремя решения (с использованием соответствующих функций более высокого порядка) наличия или отсутствия значения лежит на вызывающей функции, о которой идет речь.
jub0bs
5
Эта. Действительно, ни один из ответов не является достаточно убедительным, и ни один из них не отвечает на этот конкретный вопрос «почему использование опционных опций в качестве параметров метода считается плохой практикой, тогда как аннотирование параметров метода с помощью @NonNullсовершенно нормально, если они служат одной и той же цели по-разному?» Для меня есть только один аргумент, который имеет хоть какой-то смысл: «Необязательно следует использовать, чтобы обеспечить более совершенные API, которые имеют четкий тип возврата. Однако для аргументов метода могут использоваться перегруженные функции». - Тем не менее, я не думаю, что это достаточно сильный аргумент.
Утку Оздемир,
1
Конечно, preferrable в нуль, но что еще более предпочтительным не нужно много дополнительных значений , в первую очередь потому , что хороший дизайн: D
старшина
12

Этот совет является вариантом правила «быть как можно более неопределенным в отношении входных данных и максимально конкретным в отношении выходных данных».

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

  • Вы хотите, чтобы ваша функция использовалась вместе с другим API, который возвращает Optional
  • Ваша функция должна возвращать что-то отличное от пустого, Optionalесли данное значение пустое
  • Вы думаете, Optionalэто так здорово, что любой, кто использует ваш API, должен узнать об этом ;-)
llogiq
источник
10

Шаблон с Optionalодним, чтобы избежать возвращения null . Это все еще вполне возможно, чтобы перейти nullк методу.

Хотя они пока не являются официальными, вы можете использовать аннотации в стиле JSR-308, чтобы указать, принимаете ли вы nullзначения в функцию. Обратите внимание, что вам понадобится правильный инструмент для его идентификации, и он обеспечит больше статической проверки, чем принудительная политика времени выполнения, но это поможет.

public int calculateSomething(@NotNull final String p1, @NotNull final String p2) {}
Makoto
источник
Проблема здесь скорее в том, что @NotNull не является регистром по умолчанию и должен быть аннотирован явно - отсюда и пример, который люди просто не будут делать из-за лени.
Двегенер
1
@dwegener Да, но также Optionalне решает проблему, поэтому я предлагаю аннотации.
Макото
2
Намного сложнее игнорировать Optional, чем игнорировать аннотацию, которую вы заметите только при чтении документа / источника или если ваш инструмент сможет его уловить (статический анализ не всегда может правильно определить обнуляемость).
Аякс
Обратите внимание, что @Nullable может не означать, что вы «принимаете» значение NULL в качестве допустимого значения, то есть не выдает никаких исключений. Это может означать, что вы защититесь от этого случая, но все равно создадите исключение (это семантика Findbugs). Таким образом, вы можете внести двусмысленность с такими аннотациями вместо ясности.
tkruse
Я не уверен, какая здесь двусмысленность @ user2986984. «Не обрабатывать ноль» может только реально означать исключение.
Макото
7

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

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

Стив Б.
источник
7
Не может вернуть значения и поля также могут быть нулевыми? Так Optionalбессмысленно ли вообще?
Сэмюэль Эдвин Уорд
6

Проверьте JavaDoc в JDK10, https://docs.oracle.com/javase/10/docs/api/java/util/Optional.html , добавлена ​​заметка API:

Замечание по API: Optional в первую очередь предназначен для использования в качестве типа возврата метода, где существует явная необходимость представлять «нет результата», и где использование null может привести к ошибкам.

Xiaolong
источник
4

Я считаю, что Optional должен быть монадой, а в Java это невозможно представить.

В функциональном программировании вы имеете дело с функциями чистого и высшего порядка, которые принимают и формируют свои аргументы только на основе своего «типа бизнес-домена». Составление функций, которые питаются или о чьих вычислениях следует сообщать в реальном мире (так называемые побочные эффекты), требует применения функций, которые обеспечивают автоматическую распаковку значений из монад, представляющих внешний мир (State, Configuration, Фьючерсы, Возможно, Либо, Писатель, и т.д ...); это называется подъемом. Вы можете думать об этом как о некоем разделении интересов.

Смешение этих двух уровней абстракции не способствует удобочитаемости, поэтому лучше избегать этого.

Эдди
источник
3

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

public void method(Optional<MyClass> param) {
     if(param.isPresent()) {
         //do something
     } else {
         //do some other
     }
 }
Pau
источник
Я думаю, что это не веская причина. Та же самая логика может быть применена для проверки, является ли param нулевым, если не является необязательным. На самом деле, if(param.isPresent())это не лучший подход для использования Optional, вместо этого вы можете использовать:param.forEach(() -> {...})
hdkrus
Мне тоже не нравится идея передавать обнуляемые параметры. Во всяком случае, я сказал, что вы могли бы поддержать, конечно, есть исключения, которые вы можете использовать, это ваше дело, просто используйте это осторожно, вот и все. Не существует правил, применимых ко всем сценариям.
По
2

Принятие Необязательный, поскольку параметры вызывают ненужное перенос на уровне вызывающего.

Например, в случае:

public int calculateSomething(Optional<String> p1, Optional<BigDecimal> p2 {}

Предположим, у вас есть две ненулевые строки (т.е. возвращенные из другого метода):

String p1 = "p1"; 
String p2 = "p2";

Вы вынуждены обернуть их в Optional, даже если вы знаете, что они не пустые.

Это становится еще хуже, когда вам приходится сочинять с другими "отображаемыми" структурами, т.е. Либо :

Either<Error, String> value = compute().right().map((s) -> calculateSomething(
< here you have to wrap the parameter in a Optional even if you know it's a 
  string >));

ссылка:

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

ссылка https://github.com/teamdigitale/digital-citizenship-functions/pull/148#discussion_r170862749

gpilotino
источник
1

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

Данил Гапонов
источник
1

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

Macchiatow
источник
2
Передача нулевой необязательной ссылки можно считать ошибкой программирования (поскольку Optional предоставляет явный способ передачи «пустого» значения), поэтому проверять его не стоит, если только вы не хотите избегать исключения во всех случаях.
pvgoran
1

Дополнительные опции не предназначены для этой цели, как хорошо объяснил Брайан Гетц .

Вы всегда можете использовать @Nullable, чтобы указать, что аргумент метода может быть нулевым. Использование опционально не позволяет вам писать логику метода более аккуратно.

Киран
источник
5
Извините, но я не могу согласиться с аргументом «не был разработан» или «кто-то рекомендует против». А инженер мы должны быть конкретными. Использование @Nullable намного хуже, чем использование Optional, потому что Optional гораздо более многословен с точки зрения API. Я не вижу веских причин против использования Optionals в качестве аргументов (при условии, что вы не хотите использовать перегрузку методов)
Kacper86
0

Еще один подход, что вы можете сделать, это

// get your optionals first
Optional<String> p1 = otherObject.getP1();
Optional<BigInteger> p2 = otherObject.getP2();

// bind values to a function
Supplier<Integer> calculatedValueSupplier = () -> { // your logic here using both optional as state}

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

calculatedValueSupplier.apply();

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

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

Сварадж Ядав
источник
0

Сначала я также предпочел передать Optionals в качестве параметра, но если вы переключитесь с перспективы API-Designer на перспективу API-User, вы увидите недостатки.

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

Optional<String> p1 = otherObject.getP1();
Optional<BigInteger> p2 = otherObject.getP2();

MyCalculator mc = new MyCalculator();
p1.map(mc::setP1);
p2.map(mc::setP2);
int result = mc.calculate();
Торстен
источник
0

Я знаю, что этот вопрос больше касается мнения, а не убедительных фактов. Но недавно я перешел от разработки .net к разработке на Java, поэтому я только недавно присоединился к группе Optional. Кроме того, я бы предпочел указать это как комментарий, но так как мой уровень баллов не позволяет мне комментировать, я вынужден вместо этого поставить это как ответ.

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

Если меня интересует только значение, я проверяю isPresent перед вызовом метода, если у меня есть какая-то логика или другая логика в методе, которая зависит от того, существует ли значение, тогда я с радостью передам в Optional.

блэр
источник
0

Это потому, что у нас разные требования к пользователю API и разработчику API.

Разработчик несет ответственность за предоставление точной спецификации и правильной реализации. Поэтому, если разработчик уже знает, что аргумент является необязательным, реализация должна правильно с ним работать, независимо от того, является ли он пустым или необязательным. API должен быть максимально простым для пользователя, а null - самым простым.

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

speedogoo
источник
0

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

int result = myObject.calculateSomething(p1.orElse(null), p2.orElse(null));

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

public int calculateSomething(String p1OrNull, BigDecimal p2OrNull)

Таким образом, ясно, что допустимы нулевые значения.

Ваше использование p1.orElse(null)иллюстрирует, насколько многословен наш код при использовании Optional, поэтому я избегаю этого. Необязательно был написан для функционального программирования. Потоки это нужно. Ваши методы, вероятно, никогда не должны возвращать Optional, если в них нет необходимости использовать их в функциональном программировании. Существуют методы, например, Optional.flatMap()method, для которых требуется ссылка на функцию, которая возвращает Optional. Вот его подпись:

public <U> Optional<U> flatMap(Function<? super T, ? extends Optional<? extends U>> mapper)

Так что это обычно единственная причина написать метод, который возвращает Optional. Но даже там этого можно избежать. Вы можете передать метод получения, который не возвращает Optional, методу, подобному flatMap (), обернув его в другой метод, который преобразует функцию в правильный тип. Метод обертки выглядит так:

public static <T, U> Function<? super T, Optional<U>> optFun(Function<T, U> function) {
    return t -> Optional.ofNullable(function.apply(t));
}

Итак, предположим, что у вас есть такой получатель: String getName()

Вы не можете передать его в flatMap следующим образом:

opt.flatMap(Widget::getName) // Won't work!

Но вы можете передать это так:

opt.flatMap(optFun(Widget::getName)) // Works great!

Вне функционального программирования следует избегать опций.

Брайан Гетц сказал это лучше всего, когда он сказал это:

Причина, по которой Optional был добавлен в Java, заключается в следующем:

return Arrays.asList(enclosingInfo.getEnclosingClass().getDeclaredMethods())
    .stream()
    .filter(m -> Objects.equals(m.getName(), enclosingInfo.getName())
    .filter(m ->  Arrays.equals(m.getParameterTypes(), parameterClasses))
    .filter(m -> Objects.equals(m.getReturnType(), returnType))
    .findFirst()
    .getOrThrow(() -> new InternalError(...));

чище, чем это:

Method matching =
    Arrays.asList(enclosingInfo.getEnclosingClass().getDeclaredMethods())
    .stream()
    .filter(m -> Objects.equals(m.getName(), enclosingInfo.getName())
    .filter(m ->  Arrays.equals(m.getParameterTypes(), parameterClasses))
    .filter(m -> Objects.equals(m.getReturnType(), returnType))
    .getFirst();
if (matching == null)
  throw new InternalError("Enclosing method not found");
return matching;
MiguelMunoz
источник
1
Ну, это одна из причин, по которой он был добавлен в Java. Есть много других. Замена длинных цепочек вложенных операторов if, которые переходят в структуру данных, одной последовательной цепочкой вызовов Optional.map - мой личный фаворит. Мир программирования на функциональных языках имеет много интересных применений для Optional, кроме простой замены нулевых проверок, подобных этой.
Какой-то парень