util ejemplo baeldung java java-8 optional

ejemplo - optional lambda java



Obtener valor de uno opcional u otro (4)

Sé que esta pregunta es antigua, pero ¿por qué no utilizar en este tipo de casos algo que se ha demostrado como un patrón de cadena de responsabilidad? Está hecho / diseñado para casos como el tuyo. Y como beneficio adicional, es bastante fácil agregar servicios adicionales a la lista.

Aquí hay un enlace que describe el patrón: https://sourcemaking.com/design_patterns/chain_of_responsibility

Tengo dos instancias java.util.Optional y quiero obtener un Optional que:

  • Tiene el valor de la primera opción, si tiene un valor.
  • Tiene el valor del segundo opcional, si tiene un valor.
  • Está vacío de ninguno Opcional tiene un valor.

¿Existe una manera directa de hacerlo, es decir, ya hay alguna API para hacer eso?

Las siguientes expresiones harán eso, pero debo mencionar la primera opción dos veces:

firstOptional.isPresent() ? firstOptional : secondOptional

Esto es exactamente lo que hace com.google.common.base.Optional.or() , pero ese método no está presente en la API de Java 8.

La respuesta aceptada por aioobe enumera algunos enfoques alternativos para superar esta omisión de la API Optional justo donde se tiene que calcular dicho valor (lo que responde a mi pregunta). Ahora he optado por agregar una función de utilidad a mi base de código:

public static <T> Optional<T> or(Optional<T> a, Optional<T> b) { if (a.isPresent()) return a; else return b; }


Tuve algunos encuentros con un problema que podría haberse resuelto con JDK 9 Optional::or no, porque usamos JDK 8. Finalmente agregué una clase util con este método:

@SafeVarargs public static <T> Optional<T> firstPresent(final Supplier<Optional<T>>... optionals) { return Stream.of(optionals) .map(Supplier::get) .filter(Optional::isPresent) .findFirst() .orElse(Optional.empty()); }

Ahora puede suministrar cualquier cantidad de opciones opcionales para este método y se evaluarán de forma diferida de la siguiente manera:

final Optional<String> username = OptionalUtil.firstPresent( () -> findNameInUserData(user.getBasicData()), () -> findNameInUserAddress(user.getAddress()), () -> findDefaultUsername());

Ahora, findNameInUserAddress solo se findNameInUserData si findNameInUserData devuelve vacío. findDefaultUsername solo se findNameInUserData si findNameInUserData y findNameInUserAddress devuelven el valor vacío, etc.


EDITAR: creía totalmente que estabas usando originalmente el Guava''s Optional . He actualizado mi respuesta para proporcionar la sintaxis de Guava y Java 8 para sus respectivas clases Optional .

Java 8 opcional

Puedes acortarlo hasta esto:

firstOptional.orElse(secondOptional.orElse(EMPTY_VALUE))

No estoy seguro de lo que quería decir en su tercera viñeta con "vacío". Si te refieres a null entonces esto hará el truco:

firstOptional.orElse(secondOptional.orElse(null))

orElse() es un método en Optional que devolverá el valor si está presente; de ​​lo contrario, devolverá el valor que proporcionó como argumento a orElse() .

Guava Opcional

Puedes acortarlo hasta esto:

firstOptional.or(secondOptional.or(EMPTY_VALUE))

No estoy seguro de lo que quería decir en su tercera viñeta con "vacío". Si te refieres a null entonces esto hará el truco:

firstOptional.or(secondOptional.orNull())

or() es un método en Optional que devolverá el valor si está presente; de ​​lo contrario, devolverá el valor que proporcionó como argumento a or() .


Actualización: a partir de Java 9 ( changeset 12885 ) puede hacer

firstOptional.or(() -> secondOptional);

Para Java 8, sigue leyendo ...

Si quiere evitar mencionar firstOptional dos veces, probablemente tenga que ir con algo como

firstOptional.map(Optional::of).orElse(secondOptional);

o

Optional.ofNullable(firstOptional.orElse(secondOptional.orElse(null)));

Pero la variante más fácil de leer es simplemente hacer

Optional<...> opt = firstOptional.isPresent() ? firstOptional : secondOptional.isPresent() ? secondOptional : Optional.empty();

Si alguien tropieza con esta pregunta pero tiene una lista de opciones, sugeriría algo como

Optional<...> opt = optionals.stream() .filter(Optional::isPresent) .findFirst() .orElse(Optional.empty());