【问题标题】:Try/Catch inside or outside functionsTry/Catch 内部或外部函数
【发布时间】:2012-12-22 17:27:05
【问题描述】:

我有一个关于使用try/catch 的最佳实践的非常基本的问题。

我有一个像这样的简单函数 (DAO):

public void addVehicle(Vehicle vehicle) {

    em.getTransaction().begin();
    em.persist(vehicle);
    em.getTransaction().commit();
}

并在 Web 服务中使用 DAO 函数:

@WebMethod(operationName = "addVehicle")
public void addVehicle(Vehicle vehicle) {

    try {
        vehicleDAO.addVehicle(vehicle);
        System.out.print("Vehicle added");
    } catch (Exception e) {
        e.printStackTrace();
    }
}

在 DAO 函数中使用try/catch 更好,如下所示:

public void addVehicle(Vehicle vehicle) {

    try {
        em.getTransaction().begin();
        em.persist(vehicle);
        em.getTransaction().commit();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

【问题讨论】:

  • 不可能在不知道的情况下说出来。可能是第二个版本。
  • 捕获Exception 不好,您应该捕获您期望从代码中获得的特定检查异常。
  • 我知道捕获特定异常更好。但这现在无关紧要:) 这只是测试示例
  • 你可以这样做:public void addVehicle(Vehicle vehicle) throws Exception{...}

标签: java exception try-catch jax-rs


【解决方案1】:

在决定在哪里处理特定类型的异常时,最好的经验法则是停止查看代码的微观细节,退一步思考程序逻辑并考虑以下事项:

  • 您的程序的当前操作是否无法从异常中恢复?如果是,则只有将异常放在该操作的最顶层才有意义,以确保它不会继续。李>
  • 如果您的程序可以解决该特定异常(也许在放弃之前尝试其他方法),请使用每一层嵌套函数(从最高层开始)并且每次都问自己:如果异常发生在在这个函数中执行某行代码,这个函数继续下去有意义吗?只要答案是“是”,就进入更深层次。一旦答案为“否”,这很可能是放置该异常处理程序的最佳位置。
  • 作为前一个的替代方案,您可以决定如果引发异常,您的程序的替代“攻击计划”将是什么。然后,转到会引发该异常的代码行并问自己:此函数是否有足够的上下文信息来执行我想到的解决方法?只要答案是“否”,移动到调用者函数。一旦答案变为“是”,请考虑将您的异常处理程序放在那里。

话虽如此,您应该只捕获合理专门的异常并将 catch(Exception ex) 构造仅作为最后手段仅保留在顶层,并且仅在所有其他可能的 catch 块之后之后,仅将其保留用于您在撰写本文时确实无法预测的各种异常。 (我知道你说过这不是示例的重点,但既然我们已经在讲了,我认为应该提到它以使这个答案更完整。)

【讨论】:

    【解决方案2】:

    同时使用,唯一的原因是使用 catch RuntimeException 甚至 Throwable。因为这种异常通常是由底层框架抛出的。如果您想在再次抛出异常之前进行一些操作,例如日志记录、打印堆栈跟踪等,您应该准确地捕获这种异常。如果你不这样做,你可能会失去异常的原因。

    @Transactional
    public void addVehicle(Vehicle vehicle) {
      try {
        //do whatever with session
      } catch (RuntimeException e) {
        e.printStackTrace();
        throw new Exception(e);
      }
    }
    

    【讨论】:

      【解决方案3】:

      没有完美的规则。

      如果在需要的时候尽早捕获异常,代码通常会更清晰、更简单。
      Exception 发生时,您应该考虑谁必须采取行动,这决定了您是在方法(addVehicle)内catch 它还是throw 它,这样调用者必须catch 它。

      例如:

       public void addVehicle(Vehicle vehicle) throws SQLException{
              em.getTransaction().begin();
              em.persist(vehicle);
              em.getTransaction().commit();
       }
      

      在此示例中,调用者必须捕获。
      此外,仅在少数情况下,您应该捕获 ExceptionRunTimeException,更好 捕获特定异常,例如 IOException 而不是 Exception

      在您的代码中的某处,您将需要一个“最后一道防线”,它对catch (Exception ex). 有意义,这是处理不应发生的错误所必需的。

      【讨论】:

        【解决方案4】:

        AFAIK 的最佳实践是这样的:

        public void addVehicle(Vehicle vehicle) {
                em.getTransaction().begin();
                try {
                    em.persist(vehicle);
                    em.getTransaction().commit();
                } catch (Exception e) {
                    if (em.getTransaction().isActive()) {
                        try {
                           em.getTransaction().rollback();
                        } catch (Exception e) {
                           // Log rollback failure or something
                        }
                    }
                    throw new RuntimeException(e);
                } 
        }
        

        【讨论】:

          【解决方案5】:

          您应该只捕获那些您想要处理的异常。您可以包含一个最顶层的异常处理程序,以将任何未处理的异常转换为对最终用户有用的东西。

          尝试返回正确的异常消息,而不是 e.printStackTrace();

          详细了解异常处理here

          这里是more discussion about exception handling

          【讨论】:

            猜你喜欢
            • 2021-11-02
            • 1970-01-01
            • 2016-01-25
            • 1970-01-01
            • 1970-01-01
            • 2011-01-08
            • 2017-09-30
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多