Por que o Java 8's Optional não deve ser usado em argumentos

392

Eu li em muitos sites. Opcional deve ser usado apenas como um tipo de retorno e não usado em argumentos de método. Estou lutando para encontrar uma razão lógica. Por exemplo, eu tenho um pedaço de lógica que possui 2 parâmetros opcionais. Portanto, acho que faria sentido escrever minha assinatura de método assim (solução 1):

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

Muitas páginas da Web especificam Opcional não devem ser usadas como argumentos de método. Com isso em mente, eu poderia usar a seguinte assinatura de método e adicionar um comentário claro do Javadoc para especificar que os argumentos podem ser nulos, esperando que futuros mantenedores leiam o Javadoc e, portanto, sempre realizem verificações nulas antes de usar os argumentos (solução 2) :

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

Como alternativa, eu poderia substituir meu método por quatro métodos públicos para fornecer uma interface melhor e tornar mais óbvio que p1 e p2 são opcionais (solução 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
}

Agora, tento escrever o código da classe que invoca esse pedaço de lógica para cada abordagem. Primeiro, recupero os dois parâmetros de entrada de outro objeto que retorna Optionals e depois invoco calculateSomething. Portanto, se a solução 1 for usada, o código de chamada ficaria assim:

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

se a solução 2 for usada, o código de chamada ficaria assim:

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

se a solução 3 for aplicada, eu poderia usar o código acima ou o seguinte (mas é significativamente mais código):

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

Portanto, minha pergunta é: Por que é considerado uma prática ruim usar Optionals como argumentos de método (consulte a solução 1)? Parece a solução mais legível para mim e torna mais óbvio que os parâmetros podem estar vazios / nulos para futuros mantenedores. (Estou ciente de que os designers Optionalpretendem que ele seja usado apenas como um tipo de retorno, mas não consigo encontrar razões lógicas para não usá-lo nesse cenário).

Neil Stevens
fonte
16
Se você usasse opcionais, não precisaria verificar se o opcional transmitido como parâmetro não é null?
14
17
Sim, mas isso tornaria óbvio para alguma outra pessoa manter o código no futuro que o parâmetro pode ser / null vazio, portanto, potencialmente evitando uma exceção de ponteiro nulo no futuro
Neil Stevens
11
Uau. Argumentos nulos sendo passados ​​para um método? Isso é tão Visual Basic. Que princípio está violando? SRP (talvez). Ele também viola outro princípio, cujo nome me deixa desprovido, seguindo as linhas de transmissão de APENAS as informações necessárias para que um método ou função faça seu trabalho.
Luminous
20
Tudo teoricamente possivelmente sendo nulo é como todo método em uma biblioteca possivelmente chamando System.exit (0). Você não pode checar contra isso e não deve checar contra isso. Tudo o que você teria que fazer o tempo todo, na verdade nunca deveria (quase) fazer. Como tornar todos os parâmetros finais. Deixe suas ferramentas ajudá-lo a impedir a alteração dos valores dos parâmetros ou o esquecimento de inicializar os campos, em vez de tornar seu código ilegível por mil finais e pelo mesmo número de verificações nulas.
193
6
Na verdade, basta usar as anotações Não Nulo / Nulo, é o que você está procurando nesta situação, não opcional.
Bill K

Respostas:

202

Ah, esses estilos de codificação devem ser tomados com um pouco de sal.

  1. (+) Passar um resultado opcional para outro método, sem nenhuma análise semântica; deixando isso para o método, está tudo bem.
  2. (-) Usar parâmetros opcionais que causam lógica condicional dentro dos métodos é literalmente contraproducente.
  3. (-) A necessidade de empacotar um argumento em um Opcional é subótima para o compilador e faz um empacotamento desnecessário.
  4. (-) Em comparação com parâmetros anuláveis ​​Opcional é mais caro.

Em geral: opcional unifica dois estados, que precisam ser desvendados. Portanto, é mais adequado para resultado do que para entrada, para a complexidade do fluxo de dados.

Joop Eggen
fonte
38
Na verdade, ter um Optionalparâmetro representa um dos três estados: a nullOpcional, um não nulo Optionalcom isPresent() == falsee um não nulo Optionalenvolvendo um valor real.
biziclop
16
@ Biziclop Sim, um ponto inevitável já criticado. Mas a intenção é ter apenas expressões não nulas. Que não demorou muito tempo, ouvir o conselho para evitar o Opcional também em alguns casos, é bastante irônico. Um @NotNull Optional.
Joop Eggen
80
Nota @biziclop que se você estiver usando Optionalem tudo, então o estado 1 ( nullOpcional) geralmente indica um erro de programação, assim que você poderia muito bem não lidar com isso (apenas deixá-lo jogar um NullPointerException)
user253751
50
"subótimo para o compilador", "Em comparação com parâmetros anuláveis ​​Opcional é mais caro" - esses argumentos podem ser válidos para a linguagem C e não para a linguagem Java. Os programadores Java devem se concentrar em código limpo, portabilidade, testabilidade, boa arquitetura, modularidade etc., e não em "Opcional é mais caro que a referência nula". E se você achar que precisa se concentrar em micro-otimizações, é melhor pular Objetos, Listas, Genéricos e mudar para matrizes e primitivas (não quero ser ofensivo aqui, estou apenas compartilhando minha opinião) .
Kacper86
15
"subótimo para o compilador": a otimização prematura é a raiz de todos os males ... se você não estiver escrevendo um código crítico de desempenho (o que geralmente acontece ao tentar especificar uma interface limpa), isso não deve ser uma preocupação.
Mohan
165

O melhor post que vi sobre o assunto foi escrito por Daniel Olszewski :

Embora possa ser tentador considerar Opcional para parâmetros de método não obrigatórios, essa solução é pálida em comparação com outras alternativas possíveis. Para ilustrar o problema, examine a seguinte declaração do construtor:

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

À primeira vista, pode parecer uma decisão de design correta. Afinal, marcamos explicitamente o parâmetro de anexo como opcional. No entanto, quanto à chamada do construtor, o código do cliente pode se tornar um pouco desajeitado.

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

Em vez de fornecer clareza, os métodos de fábrica da classe Opcional apenas distraem o leitor. Observe que há apenas um parâmetro opcional, mas imagine ter dois ou três. Tio Bob definitivamente não ficaria orgulhoso de tal código 😉

Quando um método pode aceitar parâmetros opcionais, é preferível adotar uma abordagem comprovada e projetar esse caso usando sobrecarga de método. No exemplo da classe SystemMessage, declarar dois construtores separados é superior ao uso de Optional.

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

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

Essa alteração torna o código do cliente muito mais simples e fácil de ler.

SystemMessage withoutAttachment = new SystemMessage("title", "content");
Attachment attachment = new Attachment();
SystemMessage withAttachment = new SystemMessage("title", "content", attachment);
Gili
fonte
10
É muito copiar e colar quando apenas um ou dois parágrafos são relevantes.
Garret Wilson
47
Infelizmente, essa explicação não aborda a preocupação de quando o chamador está analisando, por exemplo, algumas informações que podem ser opcionais. Com a sobrecarga de método (como recomendado acima), o código de chamada deve dizer: "X está presente? Nesse caso, chamarei o método A. sobrecarregado A. Y está presente? Terei de chamar o método sobrecarregado B. Se X e Y estão presentes, terei que chamar o método sobrecarregado C. " E assim por diante. Pode haver uma boa resposta para isso, mas essa explicação do "porquê" não cobre isso.
30517 Garret Wilson
9
Além disso, quando se trata de coleções, há uma diferença distinta entre uma coleção vazia e nenhuma coleção. Por exemplo, um cache. Foi uma falta de cache? opcional / nulo vazio. Houve um acerto no cache que por acaso é uma coleção vazia? opcional / coleção completa.
Ajax
11
@ Ajax Eu acho que você está entendendo mal o artigo. Eles estão citando um ponto preconizado pelo livro Java Efetivo , que diz que quando um tipo de retorno de método é uma Coleção (não um objeto arbitrário como o cache retornaria), você deve favorecer o retorno de uma coleção vazia em vez de nullou Optional.
Gilili
4
Claro, você deve favorecer isso, mas nem sempre tem controle sobre algum código e, em um sentido muito real, convém diferenciar entre "existe um valor e é uma coleção vazia" versus "não há valor definido (ainda) ". Como "nulo mágico" também é uma prática desencorajada, cabe a você, o desenvolvedor, escolher a opção menos ruim. Prefiro opcional vazio para representar uma falta de cache em vez de uma coleção vazia, pois o valor em cache real pode ser uma coleção vazia.
Ajax
86

Quase não existem boas razões para não usar Optionalcomo parâmetros. Os argumentos contra isso se baseiam em argumentos da autoridade (consulte Brian Goetz - seu argumento é que não podemos aplicar opcionais não nulos) ou que os Optionalargumentos podem ser nulos (essencialmente o mesmo argumento). Obviamente, qualquer referência em Java pode ser nula, precisamos incentivar regras sendo impostas pelo compilador, não a memória dos programadores (o que é problemático e não é escalável).

Linguagens de programação funcional incentivam Optionalparâmetros. Uma das melhores maneiras de usar isso é ter vários parâmetros opcionais e liftM2usar uma função assumindo que os parâmetros não estejam vazios e retornando uma opção opcional (consulte http://www.functionaljava.org/javadoc/4.4/functionaljava/fj/ data / Option.html # liftM2-fj.F- ). Infelizmente, o Java 8 implementou uma biblioteca muito limitada, suportando opcional.

Como programadores Java, devemos usar nulo apenas para interagir com bibliotecas herdadas.

Mark Perry
fonte
3
Que tal usar @Nonnulle @Nullabledo javax.annotation? Eu os uso extensivamente em uma biblioteca que desenvolvo, e o suporte fornecido pelo IDE (IntelliJ) é muito bom.
Rogério
11
Isso é bom, mas você tem que usar esta anotação em todos os lugares e você precisa de uma biblioteca de métodos de apoio, como mapa, flatMap / bind, liftM2, seqüência, etc.
Mark Perry
14
Linguagens de programação funcional incentivam parâmetros opcionais. Citação necessária. A maioria das funções não deve ser opcional; em vez disso, o ônus de lidar (usando funções apropriadas de ordem superior) com a presença ou ausência de um valor está no chamador da função em questão.
Jb0bs 28/07/16
5
Este. De fato, nenhuma das respostas é convincente o suficiente e nenhuma delas responde a essa pergunta específica "por que usar opcionais como parâmetros de método é considerado uma prática ruim, enquanto a anotação de parâmetros de método @NonNullé totalmente adequada se eles servem ao mesmo propósito de maneiras diferentes?" Para mim, há apenas um argumento que faz pelo menos algum sentido: "Opcional deve ser usado para fornecer APIs melhores, com um tipo de retorno claro. No entanto, para argumentos de método, funções sobrecarregadas podem ser usadas". - ainda assim, não acho que esse argumento seja suficientemente forte.
Utku Özdemir
11
Claro, preferrable como nulo, mas o que é ainda mais preferível é não precisar de um monte de valores opcionais em primeiro lugar, porque um bom design: D
yeoman
12

Este conselho é uma variante da regra prática "seja o mais inespecífico possível em relação às entradas e o mais específico possível em relação às saídas".

Geralmente, se você possui um método que usa um valor não nulo simples, é possível mapeá-lo sobre o Optional, para que a versão simples seja estritamente mais inespecífica em relação às entradas. No entanto, existem várias razões possíveis pelas quais você desejaria exigir um Optionalargumento:

  • você deseja que sua função seja usada em conjunto com outra API que retorne um Optional
  • Sua função deve retornar algo diferente de um vazio Optionalse o valor especificado estiver vazio
  • Você acha Optionaltão incrível que quem usa sua API deve aprender sobre ela ;-)
llogiq
fonte
10

O padrão com Optionalé para evitar o retorno null . Ainda é perfeitamente possível passar nullpara um método.

Embora ainda não sejam realmente oficiais, é possível usar anotações no estilo JSR-308 para indicar se você aceita ou não nullvalores na função. Observe que você precisaria ter as ferramentas certas para realmente identificá-lo e forneceria mais uma verificação estática do que uma política de tempo de execução aplicável, mas ajudaria.

public int calculateSomething(@NotNull final String p1, @NotNull final String p2) {}
Makoto
fonte
O problema aqui é que o @NotNull não é o caso padrão e deve ser anotado explicitamente - daí o clichê e outras coisas que as pessoas simplesmente não farão devido à preguiça.
dwegener
11
@dwegener Sim, mas Optionaltambém não resolve o problema, daí a minha sugestão para as anotações.
Makoto
2
É muito mais difícil ignorar Opcional do que ignorar uma anotação que você só notará se ler os documentos / fonte ou se suas ferramentas puderem capturá-la (a análise estática nem sempre pode determinar a anulabilidade corretamente).
Ajax
Observe que @Nullable pode não significar que você "aceita" nulo como um valor válido, ou seja, não lança nenhuma exceção. Pode apenas significar que você se protege contra esse caso, mas ainda gera uma exceção (esta é a semântica do Findbugs). Portanto, você pode introduzir ambiguidade com essas anotações em vez de clareza.
tkruse
Não tenho certeza de qual ambiguidade existe @ user2986984. "Não manipular nulo" só pode significar realisticamente que uma exceção é lançada.
Makoto
7

Isso me parece um pouco tolo, mas a única razão pela qual consigo pensar é que os argumentos do objeto nos parâmetros do método já são opcionais de certa forma - eles podem ser nulos. Portanto, forçar alguém a pegar um objeto existente e envolvê-lo em um opcional é meio inútil.

Dito isto, encadear métodos que aceitem / devolvam opcionais é uma coisa razoável a se fazer, por exemplo, talvez mônada.

Steve B.
fonte
7
Os valores e os campos não podem retornar nulos também? Então, Optionalé totalmente inútil?
Samuel Edwin Ward
4

Minha opinião é que o opcional deve ser uma mônada e eles não são concebíveis em Java.

Na programação funcional, você lida com funções de ordem pura e superior que recebem e compõem seus argumentos apenas com base em seu "tipo de domínio de negócios". A composição de funções que se alimentam ou cujo cálculo deve ser relatado para o mundo real (os chamados efeitos colaterais) requer a aplicação de funções que cuidam de descompactar automaticamente os valores das mônadas que representam o mundo externo (Estado, Configuração, Futuros, Talvez, Qualquer Um, Escritor, etc ...); isso é chamado de elevação. Você pode pensar nisso como uma espécie de separação de preocupações.

A mistura desses dois níveis de abstração não facilita a legibilidade, portanto é melhor evitá-la.

Eddy
fonte
3

Outro motivo para ter cuidado ao passar um Optionalparâmetro as é que um método deve fazer uma coisa ... Se você passar um Optionalparâmetro, pode ser a favor de mais de uma coisa, pode ser semelhante a passar um parâmetro booleano.

public void method(Optional<MyClass> param) {
     if(param.isPresent()) {
         //do something
     } else {
         //do some other
     }
 }
Pau
fonte
Eu acho que não é uma boa razão. A mesma lógica pode ser aplicada para verificar se param é nulo quando não opcional é usado. Na verdade, o if(param.isPresent())não é a melhor abordagem para uso opcional, em vez disso você pode usar:param.forEach(() -> {...})
hdkrus
Também não gosto da ideia de passar parâmetros anuláveis. De qualquer forma, eu disse que você poderia favorecer, é claro que existem exceções que você pode usá-lo, cabe a você, use-o com cuidado, é tudo. Não existe nenhuma regra que se aplique a todos os cenários.
Pau
2

Aceitar Opcional como parâmetros causa quebra desnecessária no nível do chamador.

Por exemplo, no caso de:

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

Suponha que você tenha duas cadeias não nulas (ou seja, retornadas de algum outro método):

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

Você é obrigado a envolvê-los em Opcional, mesmo que saiba que eles não estão vazios.

Isso fica ainda pior quando você precisa compor com outras estruturas "mapeáveis", ou seja. Éteres :

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

ref:

Os métodos não devem esperar a Option como parâmetros; quase sempre é um cheiro de código que indica um vazamento do fluxo de controle do chamador para o chamado, deve ser responsabilidade do chamador verificar o conteúdo de uma opção

ref. https://github.com/teamdigitale/digital-citizenship-functions/pull/148#discussion_r170862749

gpilotino
fonte
1

Eu acho que é porque você normalmente escreve suas funções para manipular dados e, em seguida, eleva-as para o Optionaluso de mapfunções similares. Isso adiciona o Optionalcomportamento padrão a ele. Obviamente, pode haver casos em que é necessário escrever sua própria função auxiliar que funciona Optional.

Danil Gaponov
fonte
1

Acredito que a ressonância de ser é que você deve primeiro verificar se o Opcional é ou não nulo e, em seguida, tentar avaliar o valor que ele envolve. Muitas validações desnecessárias.

Macchiatow
fonte
2
Passar uma referência opcional nula pode ser considerado um erro de programação (porque o Opcional fornece uma maneira explícita de passar um valor "vazio"), portanto, não vale a pena verificar, a menos que você queira evitar exceções em todos os casos.
Pvgoran
1

Os opcionais não foram projetados para essa finalidade, conforme explicado de maneira bastante agradável por Brian Goetz .

Você sempre pode usar @Nullable para indicar que um argumento de método pode ser nulo. O uso de um opcional realmente não permite que você escreva a lógica do método com mais precisão.

Kieran
fonte
5
Sinto muito, mas não posso concordar com o argumento "não foi projetado" ou "alguém recomenda contra". Um engenheiro, devemos ser específicos. O uso de @Nullable é muito pior do que o opcional, porque os opcionais são muito mais detalhados do ponto de vista da API. Eu não vejo quaisquer boas razões contra o uso Opcionais como argumentos (desde que você não quer utilizar o método sobrecarga)
Kacper86
0

Mais uma abordagem, o que você pode fazer é

// 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}

Depois de criar uma função (neste caso, fornecedor), você poderá repassá-la como qualquer outra variável e poderá chamá-la usando

calculatedValueSupplier.apply();

A idéia aqui é se você tem valor opcional ou não, serão detalhes internos da sua função e não estarão no parâmetro Pensar funciona quando pensar em opcional como parâmetro é, na verdade, uma técnica muito útil que encontrei.

Quanto à sua pergunta, se você deve ou não fazer isso com base em sua preferência, mas como outros disseram, torna sua API feia para dizer o mínimo.

Swaraj Yadav
fonte
0

No começo, eu também preferia passar Optionals como parâmetro, mas se você alternar de uma perspectiva de API-Designer para uma de API-User, verá as desvantagens.

Para o seu exemplo, onde cada parâmetro é opcional, sugiro alterar o método de cálculo para uma própria classe, como a seguir:

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();
Torsten
fonte
0

Eu sei que esta pergunta é mais sobre opinião do que fatos concretos. Mas recentemente mudei de desenvolvedor de .net para java, então ingressei apenas recentemente no grupo Opcional. Além disso, prefiro declarar isso como um comentário, mas, como meu nível de pontuação não me permite comentar, sou forçado a colocar isso como resposta.

O que venho fazendo, o que me serviu bem como regra geral. É usar Opcionais para tipos de retorno e usar Opcionais apenas como parâmetros, se eu exigir o valor do Opcional e o clima ou não, o Opcional possui um valor dentro do método.

Se eu me preocupo apenas com o valor, verifico isPresent antes de chamar o método, se eu tiver algum tipo de log ou lógica diferente no método que depende se o valor existir, passarei feliz pelo Opcional.

Blair
fonte
0

Isso ocorre porque temos requisitos diferentes para um usuário da API e um desenvolvedor da API.

Um desenvolvedor é responsável por fornecer uma especificação precisa e uma implementação correta. Portanto, se o desenvolvedor já estiver ciente de que um argumento é opcional, a implementação deve lidar com ele corretamente, seja ele nulo ou opcional. A API deve ser o mais simples possível para o usuário e nulo é o mais simples.

Por outro lado, o resultado é passado do desenvolvedor da API para o usuário. No entanto, a especificação é completa e detalhada, ainda há uma chance de o usuário desconhecer ou ter preguiça de lidar com ela. Nesse caso, o resultado opcional força o usuário a escrever um código extra para lidar com um possível resultado vazio.

speedogoo
fonte
0

Primeiro de tudo, se você estiver usando o método 3, poderá substituir as últimas 14 linhas de código por:

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

As quatro variações que você escreveu são métodos de conveniência . Você só deve usá-los quando for mais conveniente. Essa também é a melhor abordagem. Dessa forma, a API é muito clara sobre quais membros são necessários e quais não são. Se você não quiser escrever quatro métodos, poderá esclarecer as coisas pela maneira como nomeia seus parâmetros:

public int calculateSomething(String p1OrNull, BigDecimal p2OrNull)

Dessa forma, fica claro que valores nulos são permitidos.

Seu uso p1.orElse(null)ilustra como o código fica detalhado ao usar o Opcional, o que é parte do motivo pelo qual eu o evito. Opcional foi escrito para programação funcional. Os córregos precisam disso. Seus métodos provavelmente nunca devem retornar Opcional, a menos que seja necessário usá-los na programação funcional. Existem métodos, como Optional.flatMap()método, que requerem uma referência a uma função que retorna Opcional. Aqui está a sua assinatura:

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

Portanto, essa é geralmente a única boa razão para escrever um método que retorne Opcional. Mas mesmo lá, isso pode ser evitado. Você pode passar um getter que não retorna Opcional a um método como flatMap (), envolvendo-o em outro método que converte a função no tipo correto. O método wrapper é assim:

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

Então, suponha que você tenha um getter como este: String getName()

Você não pode passá-lo para flatMap como este:

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

Mas você pode passar assim:

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

Fora da programação funcional, os opcionais devem ser evitados.

Brian Goetz disse isso melhor quando disse o seguinte:

A razão pela qual o Opcional foi adicionado ao Java é porque:

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(...));

é mais limpo que isso:

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
fonte
11
Bem, essa é uma das razões pelas quais foi adicionada ao Java. Existem muitos outros. Substituir longas cadeias de instruções 'if' aninhadas que atravessam uma estrutura de dados por uma única sequência de chamadas em cadeia para Optional.map é o meu favorito. O mundo da programação de Idiomas Funcionais tem muitos usos interessantes para o Opcional, além de simplesmente substituir verificações nulas como esta.
Some Guy