无法确定什么是抛出NullPointerexception

时间:2010-02-18 18:33:56

标签: java exception exception-handling nullpointerexception

我有一个看起来像这样的方法:

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

(我真的不使用像doStuff这样的方法名称 - 这只是为了让事情变得简单)

在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;

当单步执行此代码时,我会使用倒数第二个大括号(标记注释),然后使用NullPointer异常跳转到第一个代码块中的catch。 results.close()就在它之前运行(结果不为空)。我的IDE(NetBeans)不提供堆栈跟踪(它显示堆栈跟踪为空)或除异常名称之外的任何其他信息(据我所知)。

此代码以前运行正常。事实上,当它运行时,我改变了存储过程,数据访问方法(我得到这个例外)正在调用,然后这个错误开始发生(没有应用程序完全停止)。我已经尝试重建和重新启动但无济于事。我可以改回sproc,但我真的想知道这个错误来自什么,因为考虑到异常发生的代码在哪里,sproc甚至不会成为其中的一部分。

6 个答案:

答案 0 :(得分:3)

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

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

我还推荐这样的方法:

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

答案 1 :(得分:3)

你的doStuff()方法抛出SQLException之外的其他东西并且它没有被捕获。添加一个catch(异常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
    }
}

答案 2 :(得分:2)

记录器可能是空的。

异常处理程序本身经常抛出难以查明的异常。

答案 3 :(得分:2)

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

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

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

答案 4 :(得分:0)

我99%肯定会在JDBC驱动程序中发生这种情况。对于初学者来说,你的密切陈述是倒退的。您应该按顺序关闭结果集,语句和连接。

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

它也可以是关于如何在存储的进程中生成结果集的东西,例如访问一个,然后访问另一个,然后返回第一个。

答案 5 :(得分:0)

正如我在评论中所说,永远不要抓住你不想处理的例外。在你的代码中,假设它是完整的,你没有对异常做任何有趣的事情,它会让你混淆异常发生的地点和原因。如果你真的想做更多的事情而不是log或printStackTrace(),就像用特定于域的异常(比如your.package.DataAccessException或其他东西)包装它那么好。

做更多这样的事情:


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
    }

所以,外卖:

  1. 不要在异常发生的地方记录异常,只需将它们传递,嵌套在另一个异常中。您不希望您的进程不知道SQL操作是否成功。你宁愿停下来做别的事。
  2. 嵌套异常直到到达行尾,这样,您总是在要处理异常的位置拥有完整的跟踪,而不是分散在整个服务器日志中的五个位置。
  3. 嵌套异常(是的,我说过两次!)所以你不关心JVM实际抛出异常的地方,你有下一个要遵循的异常,告诉你它实际上是一个可调用的语句,或者是不正确的关闭你的资源等。
  4. 不要嵌套并抛出finally代码中捕获的错误的异常,这些错误会干扰原始异常,并且会比关闭失败和未在其中打开的语句更有趣。第一名。
  5. 在使用之前将变量设置为null,然后在close()之前检查空值。
  6. 单独捕获finally块中的每个问题,因为您可能无法关闭ResultSet(因为某些执行错误导致它无法首先打开),但您仍然应该尝试关闭CallableStatementConnection,因为它可能不受影响,但仍会导致资源泄漏。
  7. 希望有所帮助。