异常中的错误代码与异常层次结构

15

你认为在异常中使用错误代码来指定错误类型是否可以接受?请看下面的代码:

public class MyException extends Exception {
    public static final String ERROR_CODE_INVALID_NAME = "";
    public static final String ERROR_CODE_INVALID_ID = "";
    ...

    private String errorCode;

    public MyException(String message, String errorCode) {
        super(message);
        this.errorCode = errorCode;
    }

    public String getErrorCode() {
        return errorCode;
    }
}

我知道在这个例子中使用枚举而不是字符串会更好,但我实际上关心的是错误代码的概念。你认为异常层次结构在这里更好吗?我找不到任何权威的来源说将错误代码放在异常中是反模式。


看起来是 https://dev59.com/SHRB5IYBdhLWcg3w-8Ho 的重复。 - Alexander Pavlov
谢谢,我看到了这个问题,但是没有讨论这种方法通常是错误的(除了最后一个意见)。我想要引发一场关于这种方法正确性的讨论。 - Darkoboar
5个回答

8
错误代码在以下情况下非常有用:
  • 无法显示完整的错误消息(例如洗碗机显示器)
  • 必须在内部处理代码(如果出现某个特定代码,则会触发某些逻辑或服务器向客户端发送错误代码,而客户端负责消息)
  • 我们拥有一份很好的手册,用户可以使用代码获取全面的信息
  • 用户不需要知道发生了什么,但必须联系供应商
因此,大部分时间我不认为错误代码会增加任何价值。我更喜欢异常层次结构或至少清晰的错误消息,这些消息在日志中发现时非常有用(即使程序员已经离开公司2年后)。
如果您对错误代码有要求-解决方案并不差。考虑将所有错误代码收集到一个中央存储库(属性文件)中,以便您可以轻松地交换整个集合:
myexception.ERROR_CODE_INVALID_NAME=text or number
myexception.ERROR_CODE_INVALID_ID=text or number

作为有用案例列表的补充:在移动网络操作期间可能出现相似错误情况的数量相对较大(在我的场景中可能会有50多种错误)。我认为提供50个不同的异常没有任何价值,但是特定的错误必须以某种方式从网络层传递到UI层。 - Jan Groth

4
根据我的经验,异常代码大多数情况下被用作向用户提供信息的消息。
我从来没有见过有人试图解析通用异常消息以便根据错误代码做出不同的反应,通常是通过异常层次结构来完成的。
另一方面,为每种特定情况创建新的异常子类可能很困难,这时就会使用异常代码。
例如,对于用户代码而言,事务失败的原因并不重要,它仍应该回滚,但对于最终用户而言,为什么发生失败很重要(错误的参数、数据库连接等)。
因此,总结而言,如果你希望处理不同情况的方式不同,最好使用不同的异常类型,但如果你只需要处理几个问题,并且只通知用户有关特定原因,那么使用异常代码更容易。

3

我通常同时使用两种方式。

你需要对异常进行分类,并做出设计决策。

例如,您可以使用源、类型、影响和处理等参数来对异常进行分类。如果异常属于相同类别,请在其中使用错误代码。对于属于不同类别的异常,请使用层次结构。

如果您选择异常处理作为重要参数,则可以根据您想要处理它们的方式选择以下两个选项之一:

  1. 如果您想捕获所有类型并以通用方式处理它们,请使用错误代码在一个catch块中捕获。
  2. 如果您想逐个捕获特定类型并相应地处理它们,请使用层次结构。

2

从内存和时间的角度来看,创建复杂异常层次结构的堆栈跟性能非常消耗,因此如果您为可以通过3-4个静态错误代码解决的问题创建了一个复杂的自定义异常层次结构...我更倾向于使用错误代码选项。总体而言,我更喜欢使用运行时异常(在方法签名中不进行检查),捕获已检查异常的防御性方法在我看来有点过时。


4
用错误代码创建异常并不比创建具有大型超类层次结构的异常更快,也不会减少内存使用量。虽然调用构造函数可能会提高几个纳秒的性能(因为你少调用了三个构造函数),但由于你还要存储一个 int(或 enum 或其他东西),所以需要更多的内存。大部分时间都花费在创建堆栈跟踪上,因此我的意思是:过早优化是万恶之源。除此之外,这主要是一个风格问题。 :) - Bombe
@Bombe,同意。创建堆栈跟踪将是额外的开销,而不是构造函数时间。 - aviad

1
如果您想根据异常的原因(无效名称或无效 ID)在代码中有不同的反应,那么我建议使用不同的异常。
如果不需要这样做,那么您甚至不需要 `getErrorCode()` 方法,您可以将错误代码添加到异常消息中,异常将为您提供所有调试所需的信息。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接