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 es Optional y, si se invoca, flatMap no lo envuelve con un Optional 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);


Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow