Java Language
Opcional
Buscar..
Introducción
Optional
es un objeto contenedor que puede o no contener un valor no nulo. Si hay un valor presente, isPresent()
devolverá true
y get()
devolverá el valor.
Se proporcionan métodos adicionales que dependen de la presencia del valor contenido, como orElse()
, que devuelve un valor predeterminado si el valor no está presente, y ifPresent()
que ejecuta un bloque de código si el valor está presente.
Sintaxis
- Optional.empty () // Crea una instancia opcional vacía.
- Optional.of (value) // Devuelve un Optional con el valor no nulo especificado. Se emitirá una NullPointerException si el valor pasado es nulo.
- Optional.ofNullable (valor) // Devuelve un opcional con el valor especificado que puede ser nulo.
Devolver valor predeterminado si Opcional está vacío
No solo use Optional.get()
ya que puede lanzar NoSuchElementException
. Los métodos Optional.orElse(T)
y Optional.orElseGet(Supplier<? extends T>)
proporcionan una manera de proporcionar un valor predeterminado en caso de que el Opcional esté vacío.
String value = "something";
return Optional.ofNullable(value).orElse("defaultValue");
// returns "something"
return Optional.ofNullable(value).orElseGet(() -> getDefaultValue());
// returns "something" (never calls the getDefaultValue() method)
String value = null;
return Optional.ofNullable(value).orElse("defaultValue");
// returns "defaultValue"
return Optional.ofNullable(value).orElseGet(() -> getDefaultValue());
// calls getDefaultValue() and returns its results
La diferencia crucial entre orElse
y orElseGet
es que este último solo se evalúa cuando el opcional está vacío, mientras que el argumento suministrado al anterior se evalúa incluso si el opcional no está vacío. Por lo tanto, el orElse
solo debe usarse para constantes y nunca para suministrar valor en base a ningún tipo de cálculo.
Mapa
Use el método map()
de Optional
para trabajar con valores que podrían ser null
sin hacer verificaciones null
explícitas:
(Tenga en cuenta que las operaciones map()
y filter()
se evalúan inmediatamente, a diferencia de sus contrapartes de Stream que solo se evalúan en una operación de terminal ).
Sintaxis:
public <U> Optional<U> map(Function<? super T,? extends U> mapper)
Ejemplos de código:
String value = null;
return Optional.ofNullable(value).map(String::toUpperCase).orElse("NONE");
// returns "NONE"
String value = "something";
return Optional.ofNullable(value).map(String::toUpperCase).orElse("NONE");
// returns "SOMETHING"
Dado que Optional.map () devuelve un opcional vacío cuando su función de asignación devuelve un valor nulo, puede encadenar varias operaciones map () como una forma de desreferenciación segura de nulos. Esto también se conoce como encadenamiento Null-safe .
Considere el siguiente ejemplo:
String value = foo.getBar().getBaz().toString();
Cualquiera de getBar
, getBaz
y toString
puede lanzar una NullPointerException
.
Aquí hay una forma alternativa de obtener el valor de toString()
usando Optional
:
String value = Optional.ofNullable(foo)
.map(Foo::getBar)
.map(Bar::getBaz)
.map(Baz::toString)
.orElse("");
Esto devolverá una cadena vacía si alguna de las funciones de mapeo devuelve un valor nulo.
A continuación se muestra otro ejemplo, pero ligeramente diferente. Imprimirá el valor solo si ninguna de las funciones de asignación devolvió un valor nulo.
Optional.ofNullable(foo)
.map(Foo::getBar)
.map(Bar::getBaz)
.map(Baz::toString)
.ifPresent(System.out::println);
Lanzar una excepción, si no hay valor.
Use el método orElseThrow()
de Optional
para obtener el valor contenido o lanzar una excepción, si no se ha establecido. Esto es similar a llamar a get()
, excepto que permite tipos de excepción arbitrarios. El método toma un proveedor que debe devolver la excepción para ser lanzado.
En el primer ejemplo, el método simplemente devuelve el valor contenido:
Optional optional = Optional.of("something");
return optional.orElseThrow(IllegalArgumentException::new);
// returns "something" string
En el segundo ejemplo, el método lanza una excepción porque no se ha establecido un valor:
Optional optional = Optional.empty();
return optional.orElseThrow(IllegalArgumentException::new);
// throws IllegalArgumentException
También puede usar la sintaxis lambda si se necesita lanzar una excepción con el mensaje:
optional.orElseThrow(() -> new IllegalArgumentException("Illegal"));
Filtrar
filter()
se usa para indicar que le gustaría el valor solo si coincide con su predicado.
Piense en ello como if (!somePredicate(x)) { x = null; }
.
Ejemplos de código:
String value = null;
Optional.ofNullable(value) // nothing
.filter(x -> x.equals("cool string"))// this is never run since value is null
.isPresent(); // false
String value = "cool string";
Optional.ofNullable(value) // something
.filter(x -> x.equals("cool string"))// this is run and passes
.isPresent(); // true
String value = "hot string";
Optional.ofNullable(value) // something
.filter(x -> x.equals("cool string"))// this is run and fails
.isPresent(); // false
Usando contenedores opcionales para tipos de números primitivos
OptionalDouble
, OptionalInt
y OptionalLong
funcionan como Optional
, pero están diseñados específicamente para envolver tipos primitivos:
OptionalInt presentInt = OptionalInt.of(value);
OptionalInt absentInt = OptionalInt.empty();
Debido a que los tipos numéricos tienen un valor, no hay un manejo especial para el valor nulo. Los contenedores vacíos se pueden revisar con:
presentInt.isPresent(); // Is true.
absentInt.isPresent(); // Is false.
Del mismo modo, existen métodos abreviados para ayudar a la gestión del valor:
// Prints the value since it is provided on creation.
presentInt.ifPresent(System.out::println);
// Gives the other value as the original Optional is empty.
int finalValue = absentInt.orElseGet(this::otherValue);
// Will throw a NoSuchElementException.
int nonexistentValue = absentInt.getAsInt();
Ejecutar código solo si hay un valor presente
Optional<String> optionalWithValue = Optional.of("foo");
optionalWithValue.ifPresent(System.out::println);//Prints "foo".
Optional<String> emptyOptional = Optional.empty();
emptyOptional.ifPresent(System.out::println);//Does nothing.
Proporcionar perezosamente un valor predeterminado utilizando un Proveedor
El método normal orElse
toma un Object
, por lo que podría preguntarse por qué hay una opción para proporcionar un Supplier
aquí (el método orElseGet
).
Considerar:
String value = "something";
return Optional.ofNullable(value)
.orElse(getValueThatIsHardToCalculate()); // returns "something"
Todavía llamaría a getValueThatIsHardToCalculate()
aunque su resultado no se use porque el opcional no está vacío.
Para evitar esta penalización, debe suministrar un proveedor:
String value = "something";
return Optional.ofNullable(value)
.orElseGet(() -> getValueThatIsHardToCalculate()); // returns "something"
De esta manera, solo se llamará a getValueThatIsHardToCalculate()
si el Optional
está vacío.
Mapa plano
flatMap
es similar al map
. La diferencia es descrita por el javadoc de la siguiente manera:
Este método es similar al
map(Function)
, pero el asignador proporcionado es uno cuyo resultado ya esOptional
y, si se invoca,flatMap
no lo envuelve con unOptional
adicional.
En otras palabras, cuando encadena una llamada de método que devuelve un Optional
, el uso de Optional.flatMap
evita la creación de Optionals
anidados.
Por ejemplo, dadas las siguientes clases:
public class Foo {
Optional<Bar> getBar(){
return Optional.of(new Bar());
}
}
public class Bar {
}
Si usa Optional.map
, obtendrá un Optional
anidado; es decir, Optional<Optional<Bar>>
.
Optional<Optional<Bar>> nestedOptionalBar =
Optional.of(new Foo())
.map(Foo::getBar);
Sin embargo, si utiliza Optional.flatMap
, obtendrá un Optional
; es decir, Optional<Bar>
.
Optional<Bar> optionalBar =
Optional.of(new Foo())
.flatMap(Foo::getBar);