是否确实需要自定义例外

时间:2020-03-04 18:18:50

标签: java spring-boot exception java-8

我对异常处理有一些基本的了解,但是我仍然不明白何时真正需要创建自定义异常。

好吧,我知道如果自定义例外提供了一些额外的字段,那么自定义例外确实很有帮助,否则我们可以使用标准例外。

但是我的问题是:

  1. 如果我们寻求标准异常,那么,如果我在多个微服务中使用throw new RuntimeException("blah blah"),那么我将如何快速确定哪个微服务引发了此异常?当然,我可以通过查看日志来识别它,但是,抛出标准异常而不是使用自定义异常是一种好习惯吗?
  2. 在我的项目中,在每个微服务中,我都看到正在创建自定义异常,它们只是扩展了RuntimeException而在这些自定义异常中没有任何额外的信息。您会认为这是好事还是坏事?
  3. 如果我在Google上搜索此主题,则使用的常见代码段是:

NameNotFoundException:

public class NameNotFoundException extends Exception {    
    public NameNotFoundException(String message) {
        super(message);
    }    
}

您认为应该使用这样的基本自定义异常吗?

5 个答案:

答案 0 :(得分:1)

我们处理很多REST调用 (以至于我们围绕JDK的HTTP客户端编写了自己的包装器);多次不仅呼叫我们的端点。与这些端点进行对话时,我们定义了一个自定义Exception,例如:

class OurCustom extends ... {

       int httpCode;
       String receivedMessage;
       OffSetDateTime receivedAt;

}

我的意思是,这可以解决两个问题。

  • 意图

当我看到某个服务抛出了这个OurCustom时,我立即知道它的意图,我知道我应该采取什么行动以及采取什么方法。如果那将是一个普通的RuntimeException,那将更加困难。

  • 其他调试信息

您可以向自定义异常中添加更多内容,而不仅仅是消息本身,例如httpCodemessage。这简化了必须与该异常交互的人员的生活。但是,简单地扩展它而不添加任何其他信息也可能有价值,这取决于。

是的,在某些情况下,我觉得这很有用。

答案 1 :(得分:1)

在错误情况下,JVM本身也会引发RuntimeException。因此,如果要对catch块中的异常进行处理,就无法轻松区分。

如果我们寻求标准异常,可以说,如果我在多个微服务中使用throw new RuntTimeException(“ blah blah”),那么我们如何轻松快速地识别出该异常显示在哪个微服务上? (假设我们有30个微服务)。当然,通过查看日志,我们可以确定从哪个异常中获取信息。但是,这是抛出标准异常而不是自定义异常的好习惯吗?

我猜想微服务具有某种Web API(即HTTP),因此调用者一定不能看到“裸露的” RuntimeExceptions-否则您的API取决于您的编程语言,并且您只能使用Java。 如果您是说要基于RuntimeExceptions进行异常映射,则可能不够精确-如果您使用的某些库抛出RuntimeException怎么办? 最好使用您自己的Exception类。

最小映射是将异常映射到HTTP错误代码恕我直言,即200 / OK,400 /错误请求或403 /禁止。

2)在我的项目中,在每个微服务中,我都看到了自定义异常 创建后,它们只是扩展了RuntimeException而没有其他信息 在任何这些自定义例外中。你说我们做错了吗?

这没有错。错误代码或消息在那里处理和/或显示它们。您可以看看Jersey JAX-RS服务here的一些异常映射技术。

您认为上面的“自定义例外”根本不应该创建吗?

我认为您需要在每个微服务中使用定义好的简单方法来产生错误消息。一种非常简单的方法是将异常映射到HTTP状态代码(上面的示例)。另一种方法是显式发送HTTP状态而不使用异常。对于非常简单的代码,传递状态代码是可以的:

return Response
  .status(Response.Status.OK)
  .build();

我的建议:从最简单的方法(直接状态代码)开始,如果需要的话,改为使用更多抽象(例如异常映射器)(KISS-保持声音简洁)。

答案 2 :(得分:1)

我在项目中始终使用自定义异常:

public class BaseAppException extends RuntimeException {

    public BaseAppException(String message) {
        super(message);
    }

    @Override
    public synchronized Throwable fillInStackTrace() {
        // disable Stacktrace per default
        return this;
    }

    public ResponseEntity<ErrorResponse> toResponseEntity(){
        return [...]
    }
}

public UserNotFoundException extends BaseAppAxception {

    public UserNotFoundException(String idUsed){
        super("No User found for ID:" + idUsed);
    }
    [...]
}

所以我可以用相同的方式(伪代码)处理所有异常:

@ExceptionHandler(BaseAppException.class)
public final ResponseEntity<ErrorResponse> handleAppException(BaseAppException ex) {
    return ex.toResponseEntity();
}

@ExceptionHandler(Exception.class)
public final ResponseEntity<ErrorResponse> handleAppException(Exception ex) {
    ErrorResponse error = new ErrorResponse(ApplicationConstants.SERVER_ERROR, ex.getMessage());
    return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR);
}

这只是一个例子,但我希望我能展示这个想法。 您还应该使用自定义异常来隐藏错误消息。见我的UserNotFoundException

答案 3 :(得分:1)

通常,在以下情况下需要自定义例外:

  1. 标记不符合标准异常的错误/异常情况。
  2. 要将其与标准例外区分开来。
  3. 添加其他信息,这些信息对于日志记录/调试等非常有用。

在我的项目中,在每个微服务中,我都看到了自定义异常 创建后,它们只是扩展了RuntimeException而没有其他信息 在任何这些自定义例外中。你说我们做错了吗?

这没什么错,但是如果它与上述任何情况都不匹配,那就没有必要了。

答案 4 :(得分:0)

除了输出消息以外,您还可以对异常做更多的事情。即使您的自定义异常仅是基类的包装,它也为您提供了如何最好地处理各种异常的选项。有时您只需要更新UI组件。有时您需要记录错误以进行进一步检查。也许您需要强制关闭应用程序或窗口。例如,如果您有一种验证某些数据的方法,则可能有一个无效数据的例外,该例外仅将UI元素更改为错误样式。如果验证器本身抛出异常怎么办?然后,您需要对其进行记录并通知用户某些严重错误。