sirve - usar codigo html en java




Usos para Opcional (9)

1 - Como tipo de retorno de método público cuando el método podría devolver nulo:

Aquí hay un buen artículo que muestra la utilidad de usecase # 1. Hay este codigo

...
if (user != null) {
    Address address = user.getAddress();
    if (address != null) {
        Country country = address.getCountry();
        if (country != null) {
            String isocode = country.getIsocode();
            if (isocode != null) {
                isocode = isocode.toUpperCase();
            }
        }
    }
}
...

se transforma en esto

String result = Optional.ofNullable(user)
  .flatMap(User::getAddress)
  .flatMap(Address::getCountry)
  .map(Country::getIsocode)
  .orElse("default");

utilizando Opcional como valor de retorno de los métodos getter respectivos.

Habiendo estado usando Java 8 ahora por más de 6 meses, estoy muy contento con los nuevos cambios en la API. Un área en la que aún no confío es en cuándo usar Optional . Parece que me muevo entre querer usarlo en todas partes, algo puede ser null y en ninguna parte.

Parece que hay muchas situaciones en las que podría usarlo, y nunca estoy seguro de si agrega beneficios (legibilidad / seguridad nula) o si solo genera una sobrecarga adicional.

Por lo tanto, tengo algunos ejemplos y me interesaría saber qué piensa la comunidad sobre si lo Optional es beneficioso.

1 - Como tipo de retorno de método público cuando el método podría devolver null :

public Optional<Foo> findFoo(String id);

2 - Como parámetro de método cuando el parámetro puede ser null :

public Foo doSomething(String id, Optional<Bar> barOptional);

3 - Como miembro opcional de un bean:

public class Book {

  private List<Pages> pages;
  private Optional<Index> index;

}

4 - En Collections :

En general no creo:

List<Optional<Foo>>

agrega cualquier cosa, especialmente porque se puede usar filter() para eliminar valores null , etc., pero ¿hay algún buen uso para Optional en las colecciones?

¿Algún caso me he perdido?


Aquí hay un uso interesante (creo) para ... Pruebas.

Tengo la intención de probar en gran medida uno de mis proyectos y, por lo tanto, construyo afirmaciones; solo hay cosas que tengo que verificar y otras que no.

Por lo tanto, construyo cosas para afirmar y uso una afirmación para verificarlas, como esto:

public final class NodeDescriptor<V>
{
    private final Optional<String> label;
    private final List<NodeDescriptor<V>> children;

    private NodeDescriptor(final Builder<V> builder)
    {
        label = Optional.fromNullable(builder.label);
        final ImmutableList.Builder<NodeDescriptor<V>> listBuilder
            = ImmutableList.builder();
        for (final Builder<V> element: builder.children)
            listBuilder.add(element.build());
        children = listBuilder.build();
    }

    public static <E> Builder<E> newBuilder()
    {
        return new Builder<E>();
    }

    public void verify(@Nonnull final Node<V> node)
    {
        final NodeAssert<V> nodeAssert = new NodeAssert<V>(node);
        nodeAssert.hasLabel(label);
    }

    public static final class Builder<V>
    {
        private String label;
        private final List<Builder<V>> children = Lists.newArrayList();

        private Builder()
        {
        }

        public Builder<V> withLabel(@Nonnull final String label)
        {
            this.label = Preconditions.checkNotNull(label);
            return this;
        }

        public Builder<V> withChildNode(@Nonnull final Builder<V> child)
        {
            Preconditions.checkNotNull(child);
            children.add(child);
            return this;
        }

        public NodeDescriptor<V> build()
        {
            return new NodeDescriptor<V>(this);
        }
    }
}

En la clase NodeAssert, hago esto:

public final class NodeAssert<V>
    extends AbstractAssert<NodeAssert<V>, Node<V>>
{
    NodeAssert(final Node<V> actual)
    {
        super(Preconditions.checkNotNull(actual), NodeAssert.class);
    }

    private NodeAssert<V> hasLabel(final String label)
    {
        final String thisLabel = actual.getLabel();
        assertThat(thisLabel).overridingErrorMessage(
            "node's label is null! I didn't expect it to be"
        ).isNotNull();
        assertThat(thisLabel).overridingErrorMessage(
            "node's label is not what was expected!\n"
            + "Expected: '%s'\nActual  : '%s'\n", label, thisLabel
        ).isEqualTo(label);
        return this;
    }

    NodeAssert<V> hasLabel(@Nonnull final Optional<String> label)
    {
        return label.isPresent() ? hasLabel(label.get()) : this;
    }
}

¡Lo que significa que la afirmación realmente solo se activa si quiero comprobar la etiqueta!


Desde el tutorial de Oracle :

El propósito de Opcional no es reemplazar cada referencia nula en su base de código, sino ayudar a diseñar mejores API en las que, solo con leer la firma de un método, los usuarios pueden decir si deben esperar un valor opcional. Además, la Opcional lo obliga a desenvolver activamente una Opcional para tratar la ausencia de un valor; como resultado, protege su código contra excepciones de puntero nulo no deseadas.


El punto principal de Optional es proporcionar un medio para que una función devuelva un valor para indicar la ausencia de un valor de retorno. Vea esta discusión . Esto permite a la persona que llama continuar con una cadena de llamadas de métodos fluidos.

Esto concuerda más con el caso de uso # 1 en la pregunta del OP. Aunque, la ausencia de un valor es una formulación más precisa que nula, ya que algo como IntStream.findFirst nunca podría devolver nulo.

Para el caso de uso n . ° 2 , al pasar un argumento opcional a un método, esto podría funcionar, pero es bastante torpe. Supongamos que tiene un método que toma una cadena seguida de una segunda cadena opcional. Aceptar un Optional como el segundo argumento resultaría en un código como este:

foo("bar", Optional.of("baz"));
foo("bar", Optional.empty());

Incluso aceptar nulo es mejor

foo("bar", "baz");
foo("bar", null);

Probablemente lo mejor es tener un método sobrecargado que acepte un solo argumento de cadena y proporcione un valor predeterminado para el segundo:

foo("bar", "baz");
foo("bar");

Esto tiene limitaciones, pero es mucho mejor que cualquiera de los anteriores.

Los casos de uso # 3 y # 4 , que tienen un Optional en un campo de clase o en una estructura de datos, se consideran un mal uso de la API. Primero, va en contra del objetivo principal de diseño de Optional como se indica en la parte superior. En segundo lugar, no agrega ningún valor.

Hay tres formas de lidiar con la ausencia de un valor en una Optional : proporcionar un valor sustituto, llamar a una función para proporcionar un valor sustituto o lanzar una excepción. Si está almacenando en un campo, lo haría en el momento de la inicialización o asignación. Si agrega valores a una lista, como se mencionó en el OP, tiene la opción adicional de simplemente no agregar el valor, por lo tanto "aplanar" los valores ausentes.

Estoy seguro de que alguien podría idear algunos casos ideados donde realmente quieran almacenar un Optional en un campo o una colección, pero en general, es mejor evitar hacer esto.


Llego tarde al juego, pero para lo que valga, quiero agregar mis 2 centavos. Van en contra del objetivo de diseño de Optional , que está bien resumido por la respuesta de Stuart Marks , pero todavía estoy convencido de su validez (obviamente).

Uso opcional en todas partes

En general

Escribí una publicación de blog completa sobre el uso de Optional pero básicamente se trata de esto:

  • Diseña tus clases para evitar la opcionalidad siempre que sea posible
  • en todos los casos restantes, el valor predeterminado debe ser utilizar Optional lugar de null
  • posiblemente haga excepciones para:
    • variables locales
    • Devuelve valores y argumentos a métodos privados.
    • bloques de código críticos para el rendimiento (sin conjeturas, use un generador de perfiles)

Las dos primeras excepciones pueden reducir la sobrecarga percibida de envolver y desempaquetar referencias en Optional . Se eligen de tal manera que un nulo nunca puede pasar legalmente un límite de una instancia a otra.

Tenga en cuenta que esto casi nunca permitirá s Optional en colecciones, que es casi tan mala como null . Simplemente no lo hagas. ;)

Respecto a tus preguntas.

  1. Sí.
  2. Si la sobrecarga no es una opción, sí.
  3. Si otros enfoques (subclasificación, decoración, ...) no son una opción, sí.
  4. ¡Por favor no!

Ventajas

Hacer esto reduce la presencia de null s en su base de código, aunque no los erradique. Pero ese ni siquiera es el punto principal. Hay otras ventajas importantes:

Aclara la intención

El uso de Optional expresa claramente que la variable es, bueno, opcional. Cualquier lector de su código o consumidor de su API será golpeado en la cabeza con el hecho de que podría no haber nada allí y que es necesario realizar una verificación antes de acceder al valor.

Elimina la incertidumbre

Sin Optional el significado de una ocurrencia null no está claro. Podría ser una representación legal de un estado (ver Map.get ) o un error de implementación, como una inicialización faltante o fallida.

Esto cambia dramáticamente con el uso persistente de Optional . Aquí, ya la aparición de null significa la presencia de un error. (Debido a que si se permitiera que faltara el valor, se habría utilizado un Optional ). Esto hace que la depuración de una excepción de puntero nulo sea mucho más fácil, ya que la pregunta sobre el significado de este null ya está respondida.

Más cheques nulos

Ahora que ya nada puede ser null , esto puede aplicarse en todas partes. Ya sea con anotaciones, aserciones o comprobaciones simples, nunca debe pensar si este argumento o ese tipo de retorno puede ser nulo. No se puede

Desventajas

Por supuesto, no hay bala de plata ...

Actuación

Ajustar los valores (especialmente los primitivos) en una instancia adicional puede degradar el rendimiento. En bucles apretados, esto podría volverse perceptible o incluso peor.

Tenga en cuenta que el compilador podría burlar la referencia adicional para tiempos de vida cortos de Optional s. En Java 10 , los tipos de valor podrían reducir o eliminar aún más la penalización.

Publicación por entregas

Optional no es serializable pero una workaround no es demasiado complicada.

Invariancia

Debido a la invariancia de los tipos genéricos en Java, ciertas operaciones se vuelven engorrosas cuando el tipo de valor real se inserta en un argumento de tipo genérico. Aquí se da un ejemplo (ver "Polimorfismo paramétrico") .


No creo que Opcional sea un sustituto general de los métodos que potencialmente devuelven valores nulos.

La idea básica es: la ausencia de un valor no significa que esté potencialmente disponible en el futuro. Es una diferencia entre findById (-1) y findById (67).

La información principal de Optionals para el llamante es que puede que no cuente con el valor dado, pero puede estar disponible en algún momento. Tal vez desaparezca y vuelva más tarde una vez más. Es como un interruptor de encendido / apagado. Tienes la "opción" para encender o apagar la luz. Pero no tiene opción si no tiene una luz para encender.

Por lo tanto, me parece demasiado complicado introducir Optionals en todos los lugares donde antes se devolvía potencialmente nulo. Seguiré usando nulo, pero solo en áreas restringidas como la raíz de un árbol, inicialización lenta y métodos de búsqueda explícitos.


Personalmente, prefiero usar la herramienta de inspección de código de IntelliJ para usar los controles @NotNull y @Nullable , ya que estos son en gran medida el tiempo de compilación (puede tener algunos controles de tiempo de ejecución) Esto tiene una sobrecarga menor en términos de legibilidad de código y rendimiento de tiempo de ejecución. No es tan riguroso como el uso de Opcional, sin embargo, esta falta de rigor debe estar respaldada por pruebas de unidades decentes.

public @Nullable Foo findFoo(@NotNull String id);

public @NotNull Foo doSomething(@NotNull String id, @Nullable Bar barOptional);

public class Book {

  private List<Pages> pages;
  private @Nullable Index index;

}

List<@Nullable Foo> list = ..

Esto funciona con Java 5 y no es necesario envolver y desenvolver valores. (o crear objetos envoltorios)


Si no te gusta comprobar de esta manera

if(obj!=null){

}

Entonces puedes hacerlo de esta manera, eso es todo lo que veo.

if(Optional.ofNullable(obj).isPresent()){

}

Básicamente, es para dar la ilusión de que maneja los valores nulos de manera más efectiva.


Optional clase Optional permite evitar el uso null y brindar una mejor alternativa:

  • Esto alienta al desarrollador a realizar comprobaciones de presencia para evitar las NullPointerException no detectadas.

  • La API se documenta mejor porque es posible ver, dónde esperar los valores que pueden estar ausentes.

Optional proporciona una API conveniente para seguir trabajando con el objeto: isPresent() ; get() ; orElse() ; orElseGet() ; orElseThrow() ; map() ; filter() ; flatmap() .

Además, muchos marcos usan activamente este tipo de datos y los devuelven desde su API.





optional