type que found ejemplo java lambda java-8 optional java-9

que - optional type in java 8



Opcional o Else Opcional en Java (6)

Asumiendo que todavía estás en JDK8, hay varias opciones.

Opción # 1: crea tu propio método auxiliar

P.ej:

public class Optionals { static <T> Optional<T> or(Supplier<Optional<T>>... optionals) { return Arrays.stream(optionals) .map(Supplier::get) .filter(Optional::isPresent) .findFirst() .orElseGet(Optional::empty); } }

Para que puedas hacer:

return Optionals.or( ()-> serviceA(args), ()-> serviceB(args), ()-> serviceC(args), ()-> serviceD(args) );

Opción # 2: usa una biblioteca

Por ejemplo, Google guava''s Opcional admite una operación adecuada or() (como JDK9), por ejemplo:

return serviceA(args) .or(() -> serviceB(args)) .or(() -> serviceC(args)) .or(() -> serviceD(args));

(Donde cada uno de los servicios devuelve com.google.common.base.Optional , en lugar de java.util.Optional ).

He estado trabajando con el nuevo tipo Opcional en Java 8 , y me he encontrado con lo que parece una operación común que no es compatible funcionalmente: un "orElseOptional"

Considere el siguiente patrón:

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

Hay muchas formas de este patrón, pero se reduce a querer un "o Else" en un opcional que toma una función que produce un nuevo opcional, llamado solo si el actual no existe.

Su implementación se vería así:

public Optional<T> orElse(Supplier<Optional<? extends T>> otherSupplier) { return value != null ? this : other.get(); }

Tengo curiosidad por saber si hay una razón por la que dicho método no existe, si solo estoy usando Opcional de forma no intencionada, y qué otras formas han encontrado las personas para tratar este caso.

Debo decir que creo que las soluciones que involucran clases / métodos de utilidad personalizados no son elegantes porque las personas que trabajan con mi código no necesariamente sabrán que existen.

Además, si alguien sabe, ¿se incluirá dicho método en JDK 9, y dónde podría proponerlo? Esto me parece una omisión bastante evidente de la API.


El enfoque más limpio de "probar servicios" dada la API actual sería:

Optional<Result> o = Stream.<Supplier<Optional<Result>>>of( ()->serviceA(args), ()->serviceB(args), ()->serviceC(args), ()->serviceD(args)) .map(Supplier::get) .filter(Optional::isPresent) .map(Optional::get) .findFirst();

El aspecto importante no es la cadena (constante) de operaciones que tiene que escribir una vez, sino lo fácil que es agregar otro servicio (o modificar la lista de servicios es general). Aquí, agregar o eliminar un solo ()->serviceX(args) es suficiente.

Debido a la evaluación diferida de las secuencias, no se invocará ningún servicio si un servicio anterior devolvió un Optional no vacío.


Esto es parte de JDK 9 en forma de or , que toma un Supplier<Optional<T>> . Su ejemplo sería entonces:

return serviceA(args) .or(() -> serviceB(args)) .or(() -> serviceC(args));

Para más detalles, consulte el Javadoc o esta publicación que escribí.


Esto parece un buen ajuste para la coincidencia de patrones y una interfaz de opción más tradicional con implementaciones de Some and None (como las de Javaslang , FunctionalJava ) o una implementación de Maybe flojo en cyclops-react Soy el autor de esta biblioteca.

Con cyclops-react también puede usar la coincidencia de patrones estructurales en los tipos JDK. Para Opcional, puede coincidir en los casos presentes y ausentes a través del patrón de visitante . se vería así:

import static com.aol.cyclops.Matchables.optional; optional(serviceA(args)).visit(some -> some , () -> optional(serviceB(args)).visit(some -> some, () -> serviceC(args)));


No es bonito, pero esto funcionará:

return serviceA(args) .map(Optional::of).orElseGet(() -> serviceB(args)) .map(Optional::of).orElseGet(() -> serviceC(args)) .map(Optional::of).orElseGet(() -> serviceD(args));

.map(func).orElseGet(sup) es un patrón bastante útil para usar con Optional . Significa "Si este Optional contiene el valor v , dame func(v) , de lo contrario dame sup.get() ".

En este caso, llamamos al serviceA(args) y obtenemos un Optional<Result> . Si ese Optional contiene el valor v , queremos obtener Optional.of(v) , pero si está vacío, queremos obtener el servicio serviceB(args) . Enjuague y repita con más alternativas.

Otros usos de este patrón son

  • .map(Stream::of).orElseGet(Stream::empty)
  • .map(Collections::singleton).orElseGet(Collections::emptySet)

Quizás esto es lo que buscas: obtener valor de uno opcional u otro

De lo contrario, es posible que desee echar un vistazo a Optional.orElseGet . Aquí hay un ejemplo de lo que creo que buscas:

result = Optional.ofNullable(serviceA().orElseGet( () -> serviceB().orElseGet( () -> serviceC().orElse(null))));