Java Can';t确定引发NullPointer异常的内容

Java Can';t确定引发NullPointer异常的内容,java,exception,exception-handling,nullpointerexception,Java,Exception,Exception Handling,Nullpointerexception,我有一个方法如下所示: try { doStuff(); } catch (Exception ex) { logger.error(ex); } ResultSet results = null; CallableStatement proc = null; Connection connection = null; try { connection = > proc = connection.createCallableStatement(..); results =

我有一个方法如下所示:

try {
  doStuff();
} catch (Exception ex) {
  logger.error(ex);
}

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);
  }
}
(我并不真正使用dostaff这样的方法名——这只是为了让事情变得简单)

在doStuff中,我做了很多事情,其中包括调用一个数据访问方法(doStuff中的另一个方法),该方法以以下内容结束:

} 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;
}catch(SQLException-ex){
记录器错误(ex);
}最后{
试一试{
connection.close();
过程关闭();
结果:关闭();
}捕获(例外e){
错误(e);

}//很可能是记录器为空


难以精确定位的异常通常会在异常处理程序本身中抛出。

按获取资源的相反顺序关闭资源:

try 
{ 
    results.close(); 
    proc.close(); 
    connection.close(); 
} 
catch (Exception e) 
{ 
    logger.error(e); 
} //<--Exception thrown here. HUH? 

在没有语句的行中不能抛出NullPointerException

检查您正在执行的类文件是否与您查看的源文件的版本相同(当错误配置的类路径两次包含一个类,并且在类路径中首先找到了旧版本,或者由于未正确复制到用于测试的web容器而重新编译的类文件时,我遇到了类似的问题)

编辑:正如emh所指出的,也可能是在进入finally块之前发生了异常。

您的doStuff()方法正在抛出SQLException以外的内容,因此未捕获该异常。添加一个catch(exception e)块并记录该异常,然后查看发生了什么

此代码示例显示与您描述的行为相同的行为:

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
    }
}

我99%确定这是在JDBC驱动程序中发生的。对于初学者,您的close语句是向后的。您应该按顺序关闭resultset、语句和连接

如果您在管理事务的应用程序服务器中运行,那么提交事务的尝试可能会触发JDBC驱动程序中的异常


也可能是关于如何在存储过程中生成结果集的问题,例如访问一个结果集,然后访问另一个结果集,然后再引用第一个结果集。

正如我在评论中所说的,永远不要捕获您不想处理的异常。在您的代码中,假设它是完整的,您没有做任何感兴趣的事情如果你真的想做的不仅仅是记录或
printStackTrace()
,比如用特定于域的异常(比如你的.package.DataAccessException或其他东西)包装它,那就太好了

做一些更像这样的事情:

try {
  doStuff();
} catch (Exception ex) {
  logger.error(ex);
}

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);
  }
}
然后在调用者中:


    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
    }
因此,请注意:

  • 不要将异常记录在发生的位置,只需将它们传递到另一个异常中即可。您不希望流程不知道SQL操作是否成功。您宁愿停止并执行其他操作
  • 嵌套异常直到到达行的末尾,这样,您总是在您想要处理异常的地方拥有完整的跟踪,而不是分散在服务器日志中的五个地方
  • 嵌套异常(是的,我说过两次!),这样您就不必关心JVM实际从何处抛出异常,接下来就是下一个异常,告诉您它实际上是一个可调用语句,或者不正确地关闭了资源,等等
  • 不要嵌套和抛出在
    最终
    代码中捕获的错误的异常,这将干扰原始异常,这将比关闭失败和一开始没有打开的语句更有趣
  • 在使用变量之前,将变量设置为
    null
    ,然后在
    close()之前检查是否为null
  • 单独捕获
    finally
    块中的每个问题,因为您可能无法关闭
    结果集
    (因为某些执行错误导致它最初无法打开),但仍应尝试关闭
    CallableStatement
    连接,因为它可能不会受到影响,并且仍会导致资源泄漏

  • 希望有帮助。

    ex.printStackTrace()显示了什么?愚蠢的问题,但是
    logger
    null吗?我会尝试一下,但是变量浏览器显示stackTrace为null。另外@Matt-logger确实在上述两种方法中都进行了初始化。在第二种方法中,它甚至没有尝试输入异常块(通常,当单步执行时,它会命中捕获,然后进入-从结果到大括号再到第一个方法的捕获).logger是否为null?它对e的假设是什么?当然,正如SB所说,堆栈跟踪应该会有所帮助。我的直觉是,代码抛出一个未捕获的异常。然后执行进入finally块。该块完成。然后允许异常传播。这也是我的第一个想法,但事实并非如此。事实上logger实际上是在第二个块中的代码之前在同一个方法中使用的。感谢提示,我将这样做。您永远不应该捕获(异常e)并且总是捕获子类。不明白为什么对此投反对票。可能有什么错?不完全正确。在他的情况下,如果在doStuff()中抛出异常如果没有catch块来捕获它,那么在异常被抛出给调用方之前,执行路径仍然必须执行finally块。这就是为什么异常看起来像是从右括号中抛出的-这是finally block.catching的最后一行(异常e)如果是不好的做法,请抓住个人期望的子类