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