Java Opcional y orElse
optional (7)
El problema está en orden de ejecución. Está tratando de calcular el valor para .orElse (...) y lanza MyException en .orElseThrow.
En otras palabras, si t no es nulo, el siguiente flujo de ejecución es el siguiente:
1) calcular el valor de
Optional.ofNullable(t).orElseThrow(() -> new Exception("MyException"))
2) use el valor de (1) en
Optional.ofNullable("notnull").orElse(...)
Esta pregunta ya tiene una respuesta aquí:
Soy nuevo en las opciones Java pero veo este código escrito por otro desarrollador y no lo entiendo:
String t = null;
Optional.ofNullable("notnull")
.orElse(
Optional.ofNullable(t).orElseThrow(() -> new Exception("MyException"))
);
¿Por qué este código arroja la excepción? ¿Por qué incluso va a la rama "o Else"?
¿Esto se debe a una orden de ejecución extraña? Entonces, ¿el valor del primer opcional no se establece antes de evaluar la rama orElse?
El resultado se espera porque en Java antes de invocar un método que toma un parámetro, lo que hace la JVM antes es evaluar el valor del parámetro.
Y ese es el valor del parámetro de la invocación
.orElse()
:
Optional.ofNullable(t).orElseThrow(() -> new Exception("MyException"))
Como
t
refiere a
null
, se espera el lanzamiento de excepción.
Eso es porque el código dentro de
orElse()
siempre será evaluado.
En otras palabras, se ejecutará incluso si especifica un
Optional
no vacío, por eso se lanzará la
Exception
.
Si
orElse()
sección
orElse()
artículo
Java Opcional - orElse () vs orElseGet ()
, puede ver eso en su ejemplo, donde dice:
Podemos inferir fácilmente que el parámetro de orElse () se evalúa incluso cuando se tiene un Opcional no vacío.
Hay algunas cosas que debe tener en cuenta sobre Optional :
-
Si se sabe que el valor que se está ajustando es nulo o no, use Optional.of() u Optional.empty() . Si no está seguro, (por ejemplo, el valor es una variable que obtuvo de otro lugar) use Optional.ofNullable()
-
Hay una diferencia importante entre orElse() y Optional.orElseGet() .
-
orElse
toma un valor ya calculado, si se proporciona una expresión, se ejecuta y evalúa en ese mismo momento. Esto está sucediendo en el código en cuestión . Por lo tanto, esta otra variante debe usarse para valores o primitivas ya disponibles. -
orElseGet
toma una función de proveedor que solo se ejecuta cuando se evalúa la cadena opcional y se solicita un valor alternativo. Esto debería usarse donde el valor alternativo es costoso de producir o calcular.
// Fine Optional<String> name = Optional.of(someValue).orElse("defaultName"); // But this: Optional<String> name = Optional.of(someValue).orElse(db.queryName()); // Is better written as following, as it saves you from an expensive operation Optional<String> name = Optional.of(someValue).orElseGet(() -> db.queryName());
-
La secuencia
orElse
nunca se invoca, pero el método en sí se ejecuta.
Esto significa que también se le pasa el parámetro del método.
Por lo tanto, se
Optional.ofNullable(t).orElseThrow(() -> new Exception("MyException"))
la parte
Optional.ofNullable(t).orElseThrow(() -> new Exception("MyException"))
independientemente del valor pasado a la primera llamada
Optional.ofNullable
.
Si no desea que esto suceda, deberá pasar un
Supplier
como este:
String t = null;
Optional.ofNullable("notnull")
.orElseGet(
() -> Optional.ofNullable(t).orElseThrow(() -> new RuntimeException("MyException"))
);
El proveedor solo se invoca cuando se invoca la secuencia
orElseGet
.
Tenga en cuenta que necesitará una
RuntimeException
lugar de una excepción marcada para poder separarse del proveedor.
Lo que escribiste es igual a esto:
String t = null;
String myException = Optional.ofNullable(t).orElseThrow(() -> new Exception("MyException"));
Optional.ofNullable("notnull").orElse(myException);
Parte o
orElse
de
Optional
se evalúa antes de saber si su valor es nulo o no. Si desea una evaluación
"Lazy"
, considere el método
orElseGet
.
Realmente me pregunto por qué este código se ha escrito de esta manera. Parece que necesitaba desencadenar una excepción con un valor NULL explícito agregado al opcional.
Como ya se dijo al usar
orElse()
lugar de
orElseGet()
el método se evalúa sin importar el valor de T (por ejemplo,
Optional<T>
).
Lo usaría para una mejor moda y comprensión:
String value = "notnull"; // could be null
Optional.ofNullable(value)
.orElseThrow(MyException::new);
En caso de que el valor sea NULL, se activa la excepción.
Tenga en cuenta que puede usar referencias de métodos para invocar excepciones