Estou tentando entender a diferença entre os métodos Optional<T>.orElse()
e Optional<T>.orElseGet()
.
A descrição para o orElse()
método é "Retorne o valor se presente, caso contrário, retorne outro".
Embora, a descrição para o orElseGet()
método seja "Retorne o valor se presente, caso contrário, invoque other e retorne o resultado dessa invocação".
O orElseGet()
método utiliza uma interface funcional de fornecedor, que essencialmente não aceita parâmetros e retornos T
.
Em que situação você precisaria usar orElseGet()
? Se você tem um método T myDefault()
por que você não apenas fazer optional.orElse(myDefault())
mais do que optional.orElseGet(() -> myDefault())
?
Parece que não orElseGet()
está adiando a execução da expressão lambda para um momento posterior ou algo assim, então qual é o sentido disso? (Eu pensaria que seria mais útil se retornasse um mais seguro, Optional<T>
que get()
nunca lança umNoSuchElementException
e isPresent()
sempre retorna verdadeiro ... mas, evidentemente, não é, apenas retorna T
comoorElse()
).
Falta alguma outra diferença?
orElseGet
, chama o fornecedor apenas se o valor estiver ausente.orElse()
domyDefault()
método ainda é chamado, mas seu valor de retorno só não é usado.orElseGet()
pode resultar em alguns erros graves: medium.com/alphadev-thoughts/...Respostas:
Tome estes dois cenários:
Se
opt
não contém um valor, os dois são realmente equivalentes. Mas seopt
não conter um valor, quantasFoo
objetos serão criados?Ps: é claro que neste exemplo a diferença provavelmente não seria mensurável, mas se você precisar obter seu valor padrão de um serviço da Web remoto, por exemplo, ou de um banco de dados, de repente, isso se tornará muito importante.
fonte
Foo
objeto, enquanto no primeiro caso o criará, mas não o utilizará se houver um valor dentro doOptional
.System.out.println()
é um cálculo, mas uma declaração que produz um efeito colateral observável. E eu já disse que efeitos colaterais observáveis atrapalharão as otimizações (o fluxo de saída do console é um recurso externo).Resposta curta:
Optional.isPresent()
valorOptional.isPresent() == false
No código real, convém considerar a segunda abordagem quando o recurso necessário for caro .
Para mais detalhes, considere o seguinte exemplo com esta função:
A diferença é a seguinte:
Quando
optional.isPresent() == false
, não há diferença entre duas maneiras. No entanto, quandooptional.isPresent() == true
,orElse()
sempre chama a função subseqüente, quer você queira ou não.Por fim, o caso de teste usado é o seguinte:
Resultado:
Código:
fonte
Optional.isPresent() == false
(falso, não é verdadeiro) #Optional.orElse
que os estadosIf a value is present, returns the value, otherwise returns other
podem implicar este comportamento ...orElse()
se comporta semelhante afinally
detry-catch
expressão. Estou correcto?Cheguei aqui para o problema Kudo mencionou.
Estou compartilhando minha experiência para os outros.
orElse
, ouorElseGet
, eis a questão:impressões
orElse
avalia o valor de B () interdependentemente do valor do opcional. Assim,orElseGet
é preguiçoso.fonte
B()
para um método chamadoorElse()
ouabc()
não fizer nenhuma diferença,B()
será avaliado.or
prefixo leva os desenvolvedores (inclusive eu quando perguntei o problema) a pensar que é uma operação em curto-circuito, porque é a isso que estamos acostumados em condições booleanas. No entanto, não é, é apenas um nome de método que possuior
seu prefixo; portanto, seus argumentos serão avaliados, independentemente de oOptional
valor estar ou não. É lamentável que o nome seja confuso, não que possamos fazer algo a respeito.Eu diria que a maior diferença entre
orElse
eorElseGet
vem quando queremos avaliar algo para obter o novo valor naelse
condição.Considere este exemplo simples -
Agora vamos transformar o exemplo acima para usar
Optional
junto comorElse
,Agora vamos transformar o exemplo acima para usar
Optional
junto comorElseGet
,Quando
orElse
é chamado, oapicall().value
é avaliado e passado para o método. Enquanto que, no caso daorElseGet
avaliação, isso só acontece se ooldValue
estiver vazio.orElseGet
permite uma avaliação preguiçosa.fonte
O exemplo a seguir deve demonstrar a diferença:
A resposta também aparece nos documentos.
public T orElseGet(Supplier<? extends T> other)
:O
Supplier
não será invocado se osOptional
presentes. enquanto que,public T orElse(T other)
:Se
other
é um método que retorna uma string, ela será invocada, mas seu valor não será retornado casoOptional
exista.fonte
A diferença é bastante sutil e se você não prestar muita atenção, continuará usando-o de maneira errada.
A melhor maneira de entender a diferença entre
orElse()
eorElseGet()
é queorElse()
sempre será executada seOptional<T>
for nula ou não , masorElseGet()
somente será executada quandoOptional<T>
for nula .O significado do dicionário de orElse é : - executar a parte quando algo não estiver presente, mas aqui contradiz, veja o exemplo abaixo:
Benchmarks :
Espero que esclareça as dúvidas de pessoas como eu que desejam o exemplo básico do terreno :)
fonte
Antes de tudo, verifique a declaração de ambos os métodos.
1) OrElse: Execute a lógica e passe o resultado como argumento.
2) OrElseGet: executar lógica se o valor dentro do opcional for nulo
Algumas explicações sobre a declaração acima: O argumento “Optional.orElse” sempre é executado independentemente do valor do objeto em opcional (nulo, vazio ou com valor). Sempre considere o ponto acima mencionado ao usar “Optional.orElse”, caso contrário, o uso de “Optional.orElse” pode ser muito arriscado na seguinte situação.
Risco-1) Problema no log: se o conteúdo dentro do orElse contiver alguma instrução de log: Nesse caso, você terminará o log todas as vezes.
Risco-2) Problema de desempenho: se o conteúdo no orElse é demorado: o conteúdo intensivo pode ser qualquer chamada de banco de dados de operações de E / S, chamada de API, leitura de arquivo. Se colocarmos esse conteúdo em orElse (), o sistema acabará executando um código inútil.
Risco-3) Estado ilegal ou problema de bug: se o conteúdo dentro do orElse está modificando algum estado do objeto: Podemos estar usando o mesmo objeto em outro local, digamos na função Optional.map e isso pode nos colocar em um bug crítico.
Então, quando podemos ir com orElse ()? Prefira usar orElse quando o valor padrão for algum objeto constante, enum. Em todos os casos acima, podemos usar Optional.orElseGet () (que é executado apenas quando Optional contém valor não vazio) em vez de Optional.orElse (). Por quê?? Em orElse, passamos o valor padrão do resultado, mas em orElseGet passamos como Supplier e o método de Supplier somente é executado se o valor em Opcional for nulo.
Principais conclusões disso:
Eu expliquei isso no ponto 2 ( “Optional.map/Optional.orElse”! = “If / else” ) no meu blog médio. Use Java8 como programador e não como codificador
fonte
Considerando o seguinte código:
se conseguirmos
value
desta forma:Optional.<String>ofNullable(null)
, não há diferença entre orElseGet () e OrElse (), mas se conseguirmosvalue
desta forma:Optional.<String>ofNullable("test")
,orelesMethod()
emorElseGet()
não será chamado, mas emorElse()
que será chamadofonte