java - traducir - No se puede determinar qué está lanzando una excepción NullPointer
nullpointerexception processing (7)
Tengo un método que se ve así:
try {
doStuff();
} catch (Exception ex) {
logger.error(ex);
}
(Realmente no uso nombres de métodos como doStuff, esto es solo para facilitar las cosas)
En doStuff hago una variedad de cosas, entre ellas se encuentra un método de acceso a datos (por lo tanto, otro método dentro de doStuff) que termina con lo siguiente:
} catch (SQLException ex) {
logger.error(ex);
} finally {
try {
connection.close();
proc.close();
results.close();
} catch (Exception e) {
logger.error(e);
} //<--Exception thrown here. HUH?
}
return stuff;
Cuando paso por este código, llego a la penúltima llave (marcada con un comentario) y luego salta a la captura en el primer bloque de código con una excepción NullPointer. El results.close()
es lo que se está ejecutando justo antes (los resultados no son nulos). Mi IDE (NetBeans) no proporciona un seguimiento de la pila (muestra que el seguimiento de la pila es nulo) o cualquier otra información que no sea el nombre de la excepción (por lo que puedo decir).
Este código estaba funcionando bien previamente. De hecho, mientras se estaba ejecutando, cambié el procedimiento almacenado que estaba llamando el método de acceso a datos (donde recibo esta excepción), y luego este error comenzó a ocurrir (sin que la aplicación se haya detenido en absoluto). Desde entonces he intentado reconstruir y reiniciar, pero fue en vano. Podría cambiar el sproc, pero realmente quiero averiguar de qué se trata este error, ya que no tiene sentido que el sproc sea parte de esto, considerando en qué parte del código se está produciendo la excepción.
Bien podría ser que el registrador es nulo.
A menudo, se lanzan excepciones difíciles de identificar en el manejador de excepciones.
su método doStuff () arroja algo más que una excepción SQLException y no está siendo atrapada. agregue un bloque catch (Exception e) y registre esa excepción y vea qué sucede.
este ejemplo de código exhibe el mismo comportamiento que está describiendo:
public class TryCatchTest {
public static void main(String[] args) {
try {
System.out.println("foo");
throw new NullPointerException();
} finally {
try {
System.out.println("bar");
} catch (Exception e) {
e.printStackTrace();
}
} // exception thrown here
}
}
Cierre los recursos en el orden inverso en el que se obtuvieron:
try
{
results.close();
proc.close();
connection.close();
}
catch (Exception e)
{
logger.error(e);
} //<--Exception thrown here. HUH?
También recomendaría métodos como estos:
public class DatabaseUtils
{
// similar for ResultSet and Statement
public static void close(Connection c)
{
try
{
if (c != null)
{
c.close();
}
}
catch (SQLException e)
{
// log or print.
}
}
}
Como dije en un comentario, nunca captures una excepción con la que no quieras lidiar. En su código, suponiendo que está completo, no está haciendo nada interesante con la excepción, y le causa confusión sobre dónde y por qué está ocurriendo la excepción. Si realmente desea hacer algo más que registrar o printStackTrace()
, como envolverlo con una excepción específica de dominio (como su.package.DataAccessException o algo así), entonces genial.
Haz algo más como esto:
ResultSet results = null;
CallableStatement proc = null;
Connection connection = null;
try {
connection = >
proc = connection.createCallableStatement(..);
results = proc.execute(..);
>
} finally {
try {
if ( results != null ) {
results.close();
}
} catch (Exception e) {
logger.error(e);
}
try {
if ( proc != null ) {
proc.close();
}
} catch (Exception e) {
logger.error(e);
}
try {
if ( connection != null ) {
connection.close();
}
} catch (Exception e) {
logger.error(e);
}
}
Y luego en la persona que llama:
try {
doStuff();
} catch ( SQLException e ) {
throw new your.package.DataAccessException(e);
// or just let the SQLException propagate upward
} catch ( Exception e ) {
throw new your.package.AppException("omg, crazy pills!", e);
// or, once again, just let the exception
// propagate and don''t catch anything
}
Entonces, para llevar:
- no registre la excepción donde suceden, solo páselos anidados en otra excepción. No desea que su proceso no sepa si la acción SQL tuvo éxito o no. Prefieres detenerte y hacer otra cosa.
- Nest excepciones hasta el llegar al final de la línea, de esa manera, siempre tiene el rastro completo en el lugar que quería tratar con la excepción, no en cinco lugares dispersos en todo el registro del servidor.
- Excepciones de nido (¡sí, lo dije dos veces!) Para que no le importe dónde la JVM realmente arroja la excepción, tiene la siguiente excepción a seguir, diciéndole que en realidad fue una declaración invocable o cierre incorrecto de sus recursos , etc.
- No anide y arroje excepciones de los errores detectados en su código
finally
, que interferirán con la excepción original y que serán más interesantes que la falta de cierre y la declaración que no se abrió en primer lugar. - Establezca las variables en
null
antes de usarlas, y luego verifique null antes declose()
. - Capture cada problema en el bloque
finally
individual, ya que es posible que no pueda cerrar suResultSet
(debido a que algunos errores de ejecución provocaron que no se abra en primer lugar), pero igual debería intentar cerrarCallableStatement
andConnection
, ya que probablemente no se vea afectado y aún hará que pierda recursos.
Espero que ayude.
Estoy 99% seguro de que esto está sucediendo en el controlador JDBC. Para empezar, tus declaraciones cercanas están al revés. Debe cerrar el conjunto de resultados, la declaración y la conexión, en ese orden.
Si se está ejecutando en un servidor de aplicaciones que administra las transacciones, el intento de confirmar la transacción puede desencadenar la excepción dentro del controlador JDBC.
También podría ser algo acerca de cómo se generan los conjuntos de resultados en el procedimiento almacenado, como el acceso a uno, luego el acceso a otro, y luego refiriéndose a la primera.
NullPointerException no se puede lanzar en una línea sin una declaración.
Compruebe que el archivo de clase que está ejecutando es de la misma versión que la fuente que ve (tuve problemas similares cuando una classpath configurada incorrectamente contenía una clase dos veces y la versión anterior se encontraba primero en classpath, o una clase recompilada para no se copió correctamente en el contenedor web que utilicé para la prueba).
Editar: Como señala emh, también podría ser que haya ocurrido una excepción antes de ingresar al bloque finally.
NUNCA debes usar la captura (Excepción e) y siempre atrapar una subclase de Excepción particular, de esta forma sabes qué está pasando en dónde.