tutorial ejemplo java lambda java-8 optional

ejemplo - text box java



Encadenamiento de opcionales en Java 8 (5)

Buscando una forma de encadenar opciones para que se devuelva el primero que está presente. Si no hay ninguno, debe devolverse Optional.empty() .

Suponiendo que tengo varios métodos como este:

Optional<String> find1()

Estoy tratando de encadenarlos:

Optional<String> result = find1().orElse( this::find2 ).orElse( this::find3 );

pero, por supuesto, eso no funciona porque o orElse espera un valor y orElseGet espera un Supplier .


Inspirado por la respuesta de Sauli, es posible usar el método flatMap() .

Stream.of(this::find1, this::find2, this::find3) .map(Supplier::get) .flatMap(o -> o.map(Stream::of).orElseGet(Stream::empty)) .findFirst();

Convertir un Opcional en un Stream es engorroso. Aparentemente, esto se solucionará con JDK9 . Entonces esto podría escribirse como

Stream.of(this::find1, this::find2, this::find3) .map(Supplier::get) .flatMap(Optional::stream) .findFirst();

Actualización después del lanzamiento de Java 9

Aunque la pregunta original era sobre Java 8, Optional::or se introdujo en Java 9. Con él, el problema podría resolverse de la siguiente manera

Optional<String> result = find1() .or(this::find2) .or(this::find3);


Para realizar el encadenamiento opcional, primero convierta la secuencia a opcional utilizando cualquiera de los dos métodos

  1. findAny () o findFirst ()
  2. mínimo máximo()

Una vez que se obtiene opcional, opcional tiene dos métodos de instancia más que también están presentes en la clase Stream, es decir, filter y map (). utilícelos en métodos y para verificar la salida use ifPresent (System.out :: Println)

ex:

Stream s = Stream.of (1,2,3,4);

s.findFirst (). filter ((a) -> a + 1) .ifPresent (System.out :: Println)

La salida es: 2


Podrías hacerlo así:

Optional<String> resultOpt = Optional.of(find1() .orElseGet(() -> find2() .orElseGet(() -> find3() .orElseThrow(() -> new WhatEverException()))));

Aunque no estoy seguro de que mejore la legibilidad de la OMI. La guayaba proporciona una forma de encadenar las opciones:

import com.google.common.base.Optional; Optional<String> resultOpt = s.find1().or(s.find2()).or(s.find3());

Podría ser otra alternativa para su problema, pero no utiliza la clase Opcional estándar en el JDK.

Si desea mantener la API estándar, puede escribir un método de utilidad simple:

static <T> Optional<T> or(Optional<T> first, Optional<T> second) { return first.isPresent() ? first : second; }

y entonces:

Optional<String> resultOpt = or(s.find1(), or(s.find2(), s.find3()));

Si tiene muchas opciones para las cadenas, tal vez sea mejor usar el enfoque Stream como ya se mencionó.


Tal vez uno de

public <T> Optional<? extends T> firstOf(Optional<? extends T> first, @SuppressWarnings("unchecked") Supplier<Optional<? extends T>>... supp) { if (first.isPresent()) return first; for (Supplier<Optional <? extends T>> sup : supp) { Optional<? extends T> opt = sup.get(); if (opt.isPresent()) { return opt; } } return Optional.empty(); } public <T> Optional<? extends T> firstOf(Optional<? extends T> first, Stream<Supplier<Optional<? extends T>>> supp) { if (first.isPresent()) return first; Stream<Optional<? extends T>> present = supp.map(Supplier::get).filter(Optional::isPresent); return present.findFirst().orElseGet(Optional::empty); }

lo haré

El primero itera sobre una variedad de proveedores. Se devuelve el primer Optional<> no vacío. Si no encontramos uno, devolvemos un Optional vacío.

El segundo hace lo mismo con un Stream de Suppliers que se atraviesa, cada uno pregunta (perezosamente) por su valor, que luego se filtra por vacíos Optional . Se devuelve el primer no vacío o, si no existe, uno vacío.


Use una corriente:

Stream.of(find1(), find2(), find3()) .filter(Optional::isPresent) .map(Optional::get) .findFirst();

Si necesita evaluar los métodos de búsqueda perezosamente, use las funciones del proveedor:

Stream.of(this::find1, this::find2, this::find3) .map(Supplier::get) .filter(Optional::isPresent) .map(Optional::get) .findFirst();