2010-03-04 7 views
24

Este fragmento arroja un NullPointerException debido a que se llama unboxed a un tipo primitivo y se llama Long.longValue(), ¿verdad?Unboxing Null-Object a resultados largos en NullPointerException, ¿está bien?

Eso es incluso fácil para ver si tiene un fragmento de esta manera:

long value = (Long) null; 

Pero el NullPointerException es aún más difícil de conseguir en una situación más compleja como esta:

long propertyValue = (Long) obj.getProperty(propertyModel.getName()); 

Así ISN' ¿Hay alguna posibilidad de que Java-Compiler haga una Excepción más cómoda de esto? Preferiría un IllegalArgumentException con un mensaje como "Estás tratando de convertir un objeto nulo en un tipo primitivo, ¡esto no se puede hacer!"

¿No sería esto más apropiado? ¿Qué piensas? ¿Esto es posible incluso en tiempo de ejecución? ¿Podemos determinar este elenco? Todavía no he visto el bytecode de java. Tal vez podría ser utilizado en una solución.

Responde a esta pregunta: Me gustaría saber si es posible lograr este comportamiento.

+0

NPE parece bien a mí. La anotación de Nullability puede ayudar. (** Un ** boxing, btw.) –

Respuesta

55

De acuerdo con la Java language specification, unboxing pasa a través de llamar Number.longValue(), Number.intValue(), etc. No hay magia código de bytes especial sucediendo, que es exactamente lo mismo que si se llama a estos métodos de forma manual. Por lo tanto, el NullPointerException es el resultado natural de unboxing null (y de hecho ordenado por el JLS).

Lanzar una excepción diferente requeriría la comprobación de null dos veces durante cada conversión unboxing (una vez para determinar si se debe iniciar la excepción especial, y una vez implícitamente cuando el método se llama en realidad). Supongo que los diseñadores de idiomas no pensaron que fuera lo suficientemente útil para garantizar eso.

+2

una gran ventaja para explicar POR QUÉ sucede: se invoca un método como longValue() o doubleValue() en un objeto nulo. Muchas respuestas en hilos similares terminan diciendo "porque unboxing arroja NullPointerException" – kiedysktos

1

Eso no es lo que significa IllegalArgumentException. El compilador no garantiza que el valor será null hasta el tiempo de ejecución. Todo lo que sabe es el tipo, que en su ejemplo es probable que sea String.

Ciertamente en tiempo de ejecución, cuando se lanza la excepción, el compilador sabe que el problema es un valor null. Puedes ver esto tú mismo si estás usando un depurador. Entonces, desde el punto de vista tecnológico - y aquí está la respuesta corta a su pregunta - sí, sería posible crear un compilador que incluya eso en la descripción del error. Pero si desea un mensaje especial para los valores null, ¿qué sigue? ¿Mensajes especiales para enteros que están fuera de algunos límites aceptables por más de 10? Es cierto que es un ejemplo tonto, pero espero que sea ilustrativo.

+0

El tipo de devolución en mi ejemplo es Object, sería String podría usar Long.valueOf(). No está forzado a ser una excepción ilegal de argumentación. Me gustaría una Excepción especial porque se hace algo de magia para que las personas no conozcan el boxeo/unboxing. Pero está bien, es tu opinión :) – codevour

+0

No entiendo lo que quieres decir con forzar y magia, pero si tienes un problema más específico, publica un código de muestra adicional. La información como los tipos de variables sería especialmente útil. – Pops

1

Es una buena idea escribir un pequeño ayudante privado para casos como este. Esos pueden manejar la producción de moldes, mensajes de error y valores predeterminados correctos.

Es bueno poner suficiente "estado" de la operación en la excepción (en este caso, el nombre de la opción y el valor - tal vez incluso una representación de cadena del mapa de opciones si no se encuentra).

Algo así como:

private long safeGetLong(Map<String, Option> options, String name) { 
    if (name == null || options == null) 
    throw new IllegalArgumentExcption("You need to give options and name. (name="+name+", opts=" + options)); 
    Object val = options.get(name); 
    if (val == null) 
    throw new ConfigurationException("The option name="+name+" is unknown"); 
    if (val instanceof Long) 
    return val.longValue(); 

    String strVal = null; 
    try 
    { 
    strVal = val.toString(); 
    return Long.parseValue(strVal); 
    } catch (Exception ex) { 
    throw new ConfigurationException("Cannot parse " + name + "=" + strVal + " into a Long."); 
    } 
} 

Por supuesto, tener un objeto de configuración que permite el acceso escrito es aún mejor.

Existen algunos marcos de validación que podrían hacer eso por usted, pero normalmente termino escribiendo el código por mí mismo, ya que se ajusta mejor a IN8L y excepciones, o convenciones de registro de la aplicación en cuestión. Es difícil hacer eso genérico.

0

Desde Java SE 8 también hay Optional.ofNullable

long value = Optional.ofNullable(obj.getProperty(propertyModel.getName())).orElse(0L))); 
Cuestiones relacionadas