Tabla de contenido

Muy buenas a todos,
Hoy vamos a tratar un tema de Java bastante interesante: las excepciones. En concreto, las NullPointerException (NPE), las cuales supongo que a todos, y más en los inicios, nos dan tantísimos quebraderos de cabeza y a veces nos saltan en tiempo de ejecución.
Nos podemos pasa un rato buscando dónde se producen o porqué, y luego al final terminamos “solucionándolo” con un simple: if(object != null), el cual queda como un parche mal puesto aunque hace su trabajo.

Otra forma, para usuarios más avanzados para evitar estas excepciones es la captura de las mismas y su manejo, pero que las tratemos no quiere decir que no aparezcan durante la ejecución, aunque a veces es cierto que es imposible evitarlas, como por ejemplo, la entrada vacía en un cuadro de texto por parte de un usuario de nuestra aplicación.

Uno de los problemas que le veo a Java, dado que es un lenguaje de programación orientado a objetos, es que prácticamente todos han de ser inicializados. Y digo prácticamente porque no hemos de inicializar los tipos básicos, pero claro, tampoco los podemos considerar objetos de hecho.
Esta simpática excepción nos suele aparecer cuando menos nos lo esperamos, y da igual si se trata de un proyecto grande o pequeño. Puede aparecer en una aplicación que nos han mandado en una asignatura, o durante una reunión de trabajo con un cliente, haciéndonos quedar un poco regular con el cliente y con nuestro jefe.

Sin embargo, hasta ahora todo lo que he dicho han sido cosas malas de ella. Pero, ¿para qué sirve realmente esta excepción? Bueno, pues como toda excepción que se precie de llamarse así, es la mejor forma de resolver un problema en nuestro código durante la ejecución. Y diréis, ¿pero qué dice este tío?

Claro, a ver, es la mejor manera de resolver una referencia nula siempre y cuando ese caso no esté controlado, de modo que al cortar la ejecución en ese punto evita futuros problemas que podrían llegar a causar grandes daños. Esto nos permite gozar de programas robustos y que trabajan de forma suave. Cómo se suele decir: “Más vale prevenir que curar…”.

Afortunadamente, aplicando algunas técnicas defensivas en nuestro código y sabiendo siempre lo que hacemos, podemos reducir el número de NPE que nos encontraremos en gran medida. Esto será lo que haremos en esta lección que requerirá al menos dos partes. Comenzaremos explicando qué son y cómo solucionar las NullPointerException y seguiremos dando algunos consejos para programar de forma más segura.

¿Qué es una NullPointerException?

Bueno, se trata de un error, o más bien de una excepción que aparece cuando intentamos aplicar operaciones sobre un objeto que es nulo. En Java, al crear cualquier variable de tipo Objeto al inicio apunta a nulo, lo que requiere que dicha variable sea inicializada con su constructor correspondiente. Por tanto, si intentamos acceder a una variable que apunta a nulo, o realizar alguna operación con ella, obtendremos dicha excepción.

A continuación veremos escenarios muy típicos dónde nos salta dicha excepción. Para dichos escenarios vamos a usar una clase muy famosas de Java cuando se está comenzado a programar, aunque con algunas modificaciones y sólo implementando lo más básico. A mí me sirvió de mucha ayuda en mis inicios, dado que con este ejemplo vi a qué se refería la idea de orientación a objetos.

La clase Jarra:

A continuación vamos a ver los escenarios más comunes en los que podemos ver dicha excepción:

Escenario 1
java.lang.NullPointerException al llamar a un método de instancia sobre objetos nulos.
Este puede que sea el error más común que nos podemos encontrar. En este ejemplo es trivial verlo, es más, Eclipse nos avisa de que el objeto será nulo en ese punto, pero en aplicaciones más grandes puede llegar a ser un gran problema.

Recuerda siempre inicializar todos los objetos de forma correcta. Aun así, no obtendremos la excepción si llamamos un método estático. Dichos métodos no requieren una instancia para poder ser llamados.

Escenario 2
java.lang.NullPointerException al acceder a una variable de una referencia nula.
Es muy parecida al caso anterior. Si suponemos que dicha variable es pública, y que puede ser accedida desde el exterior, nos aparecerá nuestra querida excepción.

Escenario 3
java.lang.NullPointerException al lanzar una Excepción cualquiera sin inicializar.
Las excepciones, como todos los demás, son objetos y por tanto han de ser inicializados antes de poder acceder a sus métodos.

Escenario 4
java.lang.NullPointerException al intentar obtener la longitud de un array que es nulo.

Escenario 5
java.lang.NullPointerException al acceder a un elemento de un array que es nulo.

Obviamente, este escenario y el anterior pueden ser trasladados al uso de cualquier tipo de estructura de datos. En este caso hemos usado los array porque son los objetos más simples que podemos usar, pero por ejemplo se podría haber mostrado con listas o conjuntos.

Escenario 6
java.lang.NullPointerException al intentar usar synchronize sobre objetos nulos o intentar usar objetos nulos dentro de bloques synchronized.

¿Cómo resolver las NullPointerException en Java?

Para resolverlas, lo primero que hemos de conocer es qué las causa. Esto puede llegar a ser una tarea muy sencilla si sabemos dónde buscar. Toda la información que necesitamos la encontremos en la traza de errores en la consola de nuestro entorno de desarrollo (IDE), incluyendo la línea exacta dónde se ha producido el lanzamiento de la excepción y la pila de llamada de métodos antes de que se produjera.

El siguiente paso será buscar en esa línea o adyacentes qué objeto es el que causa la excepción, y ya tenemos la mitad del trabajo hecho. El resto de la tarea será saber por qué ese objeto es nulo en ese momento. Puede que se deba a un error en la creación del objeto o cualquier otro motivo, por lo que esta tarea varía y no puedo dar una solución exacta. A veces la mejor solución es tener mucho cuidado al desarrollar, aplicar técnicas preventivas para objetos nulos y usar métodos Null Safe.

Cuando no aparece NullPointerException

Si accedemos a métodos o clases estáticas nunca obtendremos dicha excepción, incluso si hacemos referencias a variables que apuntan a nulo. Esto es debido a que las variables y métodos estáticos son, en tiempo de compilación, ‘atados’ basándose en el nombre de la clase y no son asociados con objetos. En el siguiente ejemplo no saltará una excepción, dado que la variable nombre es estática, y en su lugar nos imprimirá por pantalla el valor real de la variable, que en este caso es: ‘null’.

Algunos puntos importantes de las NullPointerException

Para terminar con esta primera parte de la lección vamos a dar algunos consejos, sugerencias y detalles a tener en cuenta con estas caprichosas excepciones.

  1. Las NullPointerException con excepciones no comprobadas porque extienden (son hijas de) RuntimeException y por lo tanto no es necesario controlarlas con un bloque try-catch.
  2. Cuando obtengas una excepción NullPointerException busca la línea en la que se ha producido para encontrar al objeto que la causa.
  3. Los IDE modernos, como por ejemplo Eclipse o Netbeans, nos dan un enlace en la consola para ir directamente a la clase y línea donde se ha producido la excepción.
  4. Se pueden usar puntos de ruptura en el modo Debug del IDE para suspender la ejecución del programa cuando la excepción ocurre, de modo que se nos permite ver el valor de todas las variables en memoria y comprobar qué está fallando.
  5. Nunca olvides mirar el nombre del hilo de ejecución donde se ha producido la excepción. Si desarrollamos una aplicación multi-hilo se puede poner la cosa muy difícil si por algún motivo algún hilo hace referencia a nulo en algún momento.
  6. Lo mejor es evitar las NullPointerException durante el desarrollo siguiendo algunas técnicas de prevención o añadiendo comprobaciones en las bases de datos como restricciones.

Por el momento esto es todo. En la siguiente parte vamos a poner en práctica algunas técnicas de prevención útiles para evitar las NullPointerException en Java.

Saludos,
Lázarus Surazal.

Entradas relacionadas

Perfil
prLázarus logo info
Carlos J. Peláez Rivas (Lázarus Surazal)
Graduado y Máster en Ingeniería Informática por la Universidad de Málaga. Actualmente trabajando como desarrollador de aplicaciones en Java usando Vaadin.
Apasionado de los videojuegos, la música y alguna que otra tecnología, siempre buscando cosas nuevas que aprender y hacer.
Más sobre mi...
Contacto
Notificaciones