Obteniendo un valor sin tener que anular la comprobación en Java

12

Muchas veces me encuentro nulo al buscar un valor de alguna jerarquía de datos para evitar NullPointerExceptions, lo que me parece propenso a errores y necesita mucha repetición.

He escrito una rutina muy simple que me permite omitir la comprobación nula al recuperar un objeto ...

public final class NoNPE {

    public static <T> T get(NoNPEInterface<T> in) {
        try {
            return in.get();
        } catch (NullPointerException e) {
            return null;
        }
    }

    public interface NoNPEInterface<T> {
        T get();
    }
}

Lo uso un poco así ...

Room room = NoNPE.get(() -> country.getTown().getHouses().get(0).getLivingRoom());

Lo anterior hizo que obtuviera un objeto Room o un valor nulo, sin tener que anular la comprobación de todos los niveles principales.

¿Qué piensas de lo anterior? ¿Estoy creando un patrón problemático? En tu opinión, ¿hay una mejor manera de hacerlo?

    
pregunta Eurig Jones 15.01.2017 - 02:24

4 respuestas

12

Su solución es muy inteligente. El problema que veo es el hecho de que no sabes por qué obtuviste un null ? ¿Fue porque la casa no tenía habitaciones? ¿Fue porque la ciudad no tenía casas? ¿Fue porque el país no tenía pueblos? ¿Fue porque hubo un null en la posición 0 de la colección debido a un error incluso cuando hay casas en las posiciones 1 y mayores?

Si hace un uso extensivo de la clase NonPE , tendrá serios problemas de depuración. Creo que es mejor saber dónde se rompe exactamente la cadena que obtener silenciosamente un null que podría estar ocultando un error más profundo.

También esto viola la Ley de Demeter : country.getTown().getHouses().get(0).getLivingRoom() . La mayoría de las veces, violar un buen principio hace que tenga que implementar soluciones poco ortodoxas para resolver el problema causado por la violación de tal principio.

Mi recomendación es que lo uses con precaución e intentes resolver el defecto de diseño que hace que tengas que incurrir en el train wreck antipattern (para que no tenga que usar NonPE en todas partes). De lo contrario, es posible que tenga errores que serán difíciles de detectar.

    
respondido por el Tulains Córdova 15.01.2017 - 02:48
10

La idea está bien, de hecho es realmente buena. Ya que Java 8 existen los tipos Optional , se puede encontrar una explicación detallada en Tipo opcional de Java . Un ejemplo con lo que has publicado es

Optional.ofNullable(country)
    .map(Country::getTown)
    .map(Town::Houses);

Y más adelante.

    
respondido por el J. Pichardo 15.01.2017 - 05:38
0

Su método funciona lo suficientemente bien para su propósito previsto, aunque devolver null s cuando obtiene NullPointerException suena como un mal diseño.

Intente evitar null s cuando puede y solo páselos cuando representan algo o tienen un significado especial y solo devuélvalos cuando representan / significan algo; de lo contrario, debe lanzar un NullPointerException . Esto evita errores y confusiones. Si un Object no debería ser null , debería lanzarse un NullPointer . Si un objeto puede ser null , entonces nada saldrá mal cuando se pasa uno. De lo contrario, su método anterior funciona.

    
respondido por el Luke Melaia 15.01.2017 - 17:36
0

Puedo sentir tu dolor, pero la solución propuesta es una mala idea.

  • Si uno de los captadores lanza un NPE por algún otro motivo, lo ignorará.
  • Existe un riesgo de que la lambda interna se convierta en un código horrible. Por ejemplo, si hay un nuevo requisito para devolver una constante especial cuando no hay casas en la ciudad, un programador perezoso puede extender la lamda, dejando todo envuelto en NoNPE.get .
  • Como ya se mencionó, Optional.map es lo que está buscando.
  • La penalización de crear una nueva instancia de NullPointerException suele ser importante. Son muchos microsegundos, especialmente a medida que la pila de llamadas aumenta de tamaño. Es difícil predecir dónde se utilizará su utilidad.

Como nota al margen, NoNPEInterface es un duplicado de java.util.function.Supplier .

En algunos casos, podría considerar el uso de utilidades de evaluación de expresiones que están presentes en muchos marcos (por ejemplo: EL, SpEL):

evaluateProperty(country, "town.houses[0].livingRoom")
    
respondido por el Mateusz Stefek 15.01.2017 - 22:09

Lea otras preguntas en las etiquetas