简体   繁体   English

Java中的子类化异常:何时不是自定义消息“足够好”?

[英]Subclassing Exception in Java: when isn't a custom message “good enough”?

This is more of best practice question. 这是最佳实践问题。

I'm working with old Java code at the moment. 我目前正在使用旧的Java代码。 I'm seeing a lot of subclasses of Exception only overwrite the constructors. 我看到很多Exception的子类只覆盖了构造函数。 I'm not sure if there is any practical use of subclassing Exception like this. 我不确定是否有任何像这样的子类化Exception的实际用法。 I think just calling the Exception constructor and pass in a message would be just as effective, and there wouldn't be many subclasses around. 我认为只是调用Exception构造函数并传入消息将同样有效,并且不会有很多子类。 Code is liability. 守则是责任。

The point of subclassing is that your code can distinguish different types of failure and treat them differently. 子类化的关键在于您的代码可以区分不同类型的故障并以不同方式对待它们。 If you just change the message, then a human can distinguish them in the logs, but that's all. 如果您只是更改消息,那么人类可以在日志中区分它们,但这就是全部。

If the exceptions you are seeing are not actually handled differently, but just caught in a catch-all catch(Exception e) then perhaps someone was being over-enthusiastic with the subclasses, but it is often useful for cleanly separating layers of code and working out which classes should handle which kinds of problem. 如果您看到的异常实际上并没有被区别对待,但只是陷入了一个全能的catch(Exception e)那么也许有人对子类过于热心,但它通常对于清晰地分离代码层和工作有用哪些类应该处理哪种问题。

For example, one type of exception may indicate a timeout, and it may be appropriate to retry after a short delay, whereas another type of exception indicates an unrecoverable failure (an invalid query, perhaps) which must be thrown up to a higher level or perhaps indicated to the user. 例如,一种类型的异常可能表示超时,并且可能适合在短暂延迟后重试,而另一种类型的异常表示不可恢复的故障(可能是无效的查询),必须将其提升到更高级别或或许向用户表明。

To add to the other answers: 要添加到其他答案:

If you extend Exception and throw it, you're declaring a new checked exception. 如果你扩展Exception并抛出它,你就会声明一个新的已检查异常。 It will have to be declared on the throws clause of your method. 它必须在您的方法的throws子句中声明。 You are saying to the caller: "Here is a unusual case which you must code for". 你是对来电者说:“这是一个不寻常的案例,你必须编码”。

I think checked exceptions are over-used. 我认为已检查的异常被过度使用。 They are only really useful in situations where the caller can expect to recover from the problem. 它们仅在调用者可以从问题中恢复的情况下才真正有用。 The vast majority of exceptions I have seen are the kind that the caller cannot reasonably expect to recover from. 我见过的绝大多数例外情况都是调用者无法合理期望从中恢复的类型。 In this case you should use a RuntimeException descendant such as IllegalStateException or IllegalArgumentException and let top-level error handling take care of it. 在这种情况下,您应该使用RuntimeException后代,例如IllegalStateExceptionIllegalArgumentException并让顶级错误处理来处理它。

  1. When you have a subclass, you can catch it. 当你有一个子类时,你可以捕获它。 You can't catch an exception selectively depending on its message. 您无法根据其消息选择性地捕获异常。

  2. Subclasses are more descriptive and easier to use: 子类更具描述性且更易于使用:

     throw new Exception("User does not exist " + userName); 

    compared to: 相比:

     throw new UserNotExistsException(userName); 

    also the latter exception can have getUserName() method and field accordingly to extract important information when caught. 后一个异常也可以有getUserName()方法和字段,以便在捕获时提取重要信息。 You don't want to parse exception message, don't you? 你不想解析异常消息,不是吗?

This is done to allow more cleaner and more precise catching of exceptions. 这样做是为了更清晰,更准确地捕获异常。 If all of your code just throws Exception , your exception-handling code will have to look like this: 如果您的所有代码都抛出Exception ,那么您的异常处理代码必须如下所示:

try {
   // ...
   throw new Exception("configuration error");
   // ...
   throw new Exception("missing value error");
   // etc.
} catch (Exception e) {
   // do something
}

And it will be awkward at the least to handle different kinds of errors in different ways. 至少以不同方式处理不同类型的错误将是尴尬的。 More importantly, this code will swallow all exceptions, even ones you weren't expecting and for which you haven't written specific error-handling logic. 更重要的是,这段代码将吞没所有异常,甚至是您没有预料到的异常,并且您没有编写特定的错误处理逻辑。 On the other hand, if you write 另一方面,如果你写

try {
   // ...
   throw new ConfigurationException();
   // ...
   throw new MissingValueException();
   // etc.
} catch (ConfigurationException e) {
   System.err.println("error: bad configuration");
   System.exit(1);
} catch (MissingValueException e) {
   return DEFAULT_VALUE;
}

you'll be able to easily and cleanly handle different kinds of errors, and won't have to worry that your error handling code will be run in situations that you didn't expect it to. 您将能够轻松,干净地处理各种错误,并且不必担心您的错误处理代码将在您不期望的情况下运行。

Subclassing is the way to go. 子类化是要走的路。 later in the lifetime of the application you may have to change the exception message. 稍后在应用程序的生命周期中,您可能需要更改异常消息。 Who knows it may be displayed on a page and the wording needs to be adjusted. 谁知道它可能会显示在页面上,并且需要调整措辞。

Wrapping the error message in its own Exception subclass helps maintain a clean code and easily test against a given error category. 将错误消息包装在自己的Exception子类中有助于维护干净的代码并轻松地针对给定的错误类别进行测试。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM