真的需要自定义异常吗[重复]

Posted

技术标签:

【中文标题】真的需要自定义异常吗[重复]【英文标题】:Are Custom Exceptions really needed [duplicate] 【发布时间】:2020-06-17 07:39:57 【问题描述】:

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

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

但我的问题是:

    如果我们选择标准异常,假设我在多个微服务中使用throw new RuntimeException("blah blah"),那么我如何能够快速识别哪个微服务抛出了这个异常?当然,我可以通过查看日志来识别它,但是,抛出标准异常而不是使用自定义异常是一种好习惯吗? 在我的项目中,在每个微服务中,我都看到正在创建自定义异常,它们只是扩展 RuntimeException 并且在任何这些自定义异常中都没有额外的信息。您认为这种做法是好是坏? 如果我在 google 上搜索这个主题,常用的 sn-p 代码是这样的:

NameNotFoundException:

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

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

【问题讨论】:

When should we create our own Java exception classes? john - 如果其中一个答案解决了您的问题,您可以通过将其标记为已接受来帮助社区。接受的答案有助于未来的访问者自信地使用该解决方案。查看meta.stackexchange.com/questions/5234/… 了解如何操作。 【参考方案1】:

我们处理 REST 调用,很多(以至于我们编写了自己的 JDK 的 HTTP 客户端包装器);多次调用不仅是我们的端点。在与这些端点通信时,我们定义了一个自定义异常,例如:

class OurCustom extends ... 

       int httpCode;
       String receivedMessage;
       OffSetDateTime receivedAt;


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

意图

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

其他调试信息

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

所以是的,在某些情况下我觉得这非常有用。

【讨论】:

【参考方案2】:

在错误情况下,JVM 本身也会抛出 RuntimeException。因此,如果您想在 catch-blocks 中处理您的异常,您将无法轻松区分。

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

我猜微服务有某种 Web API(即 HTTP),所以调用者不能看到“裸”的 RuntimeExceptions - 否则你的 API 取决于你的编程语言,而你被困在 Java 上。 如果您的意思是您正在基于 RuntimeExceptions 进行异常映射,那么您可能不够精确 - 如果您使用的某个库抛出 RuntimeException 怎么办? 最好使用你自己的异常类。

最小的映射是将异常映射到 HTTP 错误代码恕我直言,即 200/OK、400/Bad Request 或 403/Forbidden。

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

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

您是否认为根本不应该创建上述自定义异常?

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

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

我的建议:从最简单的方法(直接状态代码)开始,如果需要,改用异常映射器等更抽象的方法(KISS - 保持健全和简单)。

【讨论】:

【参考方案3】:

我在我的项目中总是使用自定义异常:

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

【讨论】:

【参考方案4】:

一般情况下,以下情况需要自定义异常:

    标记不符合标准异常的错误/异常情况。 将其与标准异常区分开来。 添加对日志记录/调试等有用的附加信息。

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

没有错,但如果不符合上述任何一种情况,则没有必要。

【讨论】:

【参考方案5】:

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

【讨论】:

以上是关于真的需要自定义异常吗[重复]的主要内容,如果未能解决你的问题,请参考以下文章

在 Spring Boot 中自定义异常返回空消息 [重复]

在 C# 中使用自定义构造函数创建异常 [重复]

Java——你真的了解Java异常处理机制吗?

自定义异常类型

自定义异常

自定义异常