Eu tenho trabalhado com o novo tipo opcional no Java 8 e me deparei com o que parece ser uma operação comum sem suporte funcional: um "ouElseOptional"
Considere o seguinte padrão:
Optional<Result> resultFromServiceA = serviceA(args);
if (resultFromServiceA.isPresent) return result;
else {
Optional<Result> resultFromServiceB = serviceB(args);
if (resultFromServiceB.isPresent) return resultFromServiceB;
else return serviceC(args);
}
Existem muitas formas desse padrão, mas tudo se resume a querer um "orElse" em um opcional que assume uma função que produz um novo opcional, chamado apenas se o atual não existir.
Sua implementação ficaria assim:
public Optional<T> orElse(Supplier<Optional<? extends T>> otherSupplier) {
return value != null ? this : other.get();
}
Estou curioso para saber se existe um motivo para que esse método não exista, se estou apenas usando o Opcional de maneira não intencional e de que outras maneiras as pessoas inventaram para lidar com esse caso.
Devo dizer que acho que as soluções que envolvem classes / métodos de utilitários personalizados não são elegantes porque as pessoas que trabalham com meu código não necessariamente sabem que elas existem.
Além disso, se alguém souber, esse método será incluído no JDK 9, e onde devo propor esse método? Isso parece uma omissão bastante flagrante para a API para mim.
orElseGet()
que o OP precisa, mas não gera uma sintaxe em cascata agradável.Respostas:
Isso faz parte do JDK 9 na forma de
or
, que leva aSupplier<Optional<T>>
. Seu exemplo seria então:Para detalhes, consulte o Javadoc ou este post que escrevi.
fonte
ifPresent
. Mas de qualquer maneira, acho que o nomeifPresent
não é bom de qualquer maneira. Para todos os outros métodos não tendo “senão” no nome (comomap
,filter
,flatMap
), fica implícito que eles não fazem nada se nenhum valor estiver presente, então por queifPresent
...Optional<T> perform(Consumer<T> c)
método para permitir o encadeamentoperform(x).orElseDo(y)
(orElseDo
como uma alternativa à propostaifEmpty
, para ter consistência noelse
nome de todo método que possa fazer algo por valores ausentes). Você pode imitar issoperform
no Java 9,stream().peek(x).findFirst()
apesar de ser um abuso da API e ainda não há como executar umRunnable
sem especificar umConsumer
ao mesmo tempo ...A abordagem mais limpa de "experimentar serviços", dada a API atual, seria:
O aspecto importante não é a cadeia (constante) de operações que você precisa escrever uma vez, mas a facilidade de adicionar outro serviço (ou modificar a lista de serviços é geral). Aqui, adicionando ou removendo um único
()->serviceX(args)
é suficiente.Devido à avaliação lenta dos fluxos, nenhum serviço será chamado se um serviço anterior retornar um não vazio
Optional
.fonte
.map(Optional::get)
com.findFirst()
tornará mais fácil a "leitura", por exemplo,.filter(Optional::isPresent).findFirst().map(Optional::get)
pode ser "lido" como "encontrar o primeiro elemento no fluxo para o qual Optional :: isPresent é verdadeiro e achatá-lo aplicando Optional :: get"?Não é bonito, mas isso funcionará:
.map(func).orElseGet(sup)
é um padrão bastante útil para uso comOptional
. Significa "Se issoOptional
contém valorv
, me dêfunc(v)
, caso contrário, me dêsup.get()
".Nesse caso, chamamos
serviceA(args)
e obtemos umOptional<Result>
. Se issoOptional
contém valorv
, queremos obterOptional.of(v)
, mas se estiver vazio, queremos obterserviceB(args)
. Repita a lavagem com mais alternativas.Outros usos desse padrão são
.map(Stream::of).orElseGet(Stream::empty)
.map(Collections::singleton).orElseGet(Collections::emptySet)
fonte
() -> {}
não retorna umOptional
. O que você está tentando realizar?or(Supplier<Optional<T>>)
de Java 9.map()
em um vazioOptional
produzirá um vazioOptional
.Talvez seja isso que você procura: obtenha valor de um opcional ou de outro
Caso contrário, você pode querer dar uma olhada
Optional.orElseGet
. Aqui está um exemplo do que eu acho que você procura:fonte
ofNullable
é a coisa mais legal que eu já vi.Supondo que você ainda esteja no JDK8, existem várias opções.
Opção 1: crie seu próprio método auxiliar
Por exemplo:
Para que você possa fazer:
Opção 2: use uma biblioteca
Por exemplo, o opcional do google guava suporta uma
or()
operação adequada (como o JDK9), por exemplo:(Onde cada um dos serviços retorna
com.google.common.base.Optional
, em vez dejava.util.Optional
).fonte
Optional<T>.or(Supplier<Optional<T>>)
nos documentos da Goiaba. você tem um link para isto?Este é parece um bom ajuste para correspondência de padrão e uma interface opção mais tradicional com alguns e nenhum implementações (tais como aqueles em Javaslang , FunctionalJava ) ou um preguiçoso Talvez implementação em cyclops-reagir .Eu estou o autor desta biblioteca.
Com o cyclops-react, você também pode usar a correspondência de padrões estruturais nos tipos JDK. Para Opcional, você pode corresponder nos casos presentes e ausentes por meio do padrão de visitante . seria algo parecido com isto -
fonte