抛出异常和抛出特定异常(如NullPointerException)之间的区别

4

我想知道抛出Exception和抛出具体的异常如NullPointer Exception之间的区别。

以我目前的了解,Exception应该能够捕获任何类型的异常,而使用特定的异常则期望只会抛出该特定类型的异常。

例子:

void test(String testString) throws Exception;

vs

void test(String testString) throws NullPointerException;

如果这是正确的,那么对我来说总是抛出异常并且不命名特定的异常是有意义的。我在这里是否遗漏了什么重要的东西?这是否至少会影响性能?很多人都在考虑抛出和捕获异常之间的区别,但没有人问这个非常基本的问题。
我认为除了Exception之外,抛出任何异常都没有好处。

1
你需要为特定情况抛出特定的异常。你希望抛出特定的异常来表明发生了具体的事情,而不仅仅是说“嘿,有些东西没能正常工作,应用程序崩溃了,但我不知道为什么!” :) - Seth
如果你的代码可能以几种不同的方式失败,其中一些可以由调用代码处理,而另一些则不能呢?如果你只抛出“异常”,那么调用代码该如何区分它们呢? - azurefrog
3
可能是[在Java中,捕获泛型异常和特定异常(例如IOException)有什么区别?]的重复问题。 - azurefrog
4个回答

5

首先,Exception是每个异常的基本类型,就像object是万物的基础一样。

通过抛出特定的Exception,您为使用者提供了更多关于发生情况的信息。想象一下,如果您得到一个没有消息的普通Exception,那么使用者会感到迷惑。当例如框架抛出NullReferenceException时,您就知道您的对象之一没有它试图访问的引用。

这是如何链接异常并利用它们的类型:

try
{
   throw new NotImplementedException();
}
catch(NullReferenceException ex)
{
   // Logic for NullReference exception if needed.
}
catch(NotImplementedException ex)
{
   // This will be executed.
}
catch(Exception ex)
{
   // Will catch every exception.
}

1
很棒的例子,我看到了抛出特定异常的重要性。非常感谢。如果您认为这篇文章可以帮助其他初学者抛出异常,请投票支持此文章。如果您认为我还可以改进这篇文章,请让我知道。 - L1ghtk3ira

4

至少有两个原因你想要抛出一种特定的异常:

  1. 如果程序因为异常而失败,你将有更多信息来确定出错原因。比较看到 ExceptionFileNotFoundException,后者显然给了你更多信息。
  2. 在某些情况下,代码会想要捕获特定类型的异常。例如,在使用串口时,你可能希望以不同的方式捕获和处理 TimeoutExceptionNullReferenceException

谢谢,我选择了@Carl的答案,因为他提供了出色的示例。你的信息也很棒,所以我还是给你点了赞。如果你认为这篇帖子对其他初学者抛出异常有帮助,请点赞。 - L1ghtk3ira
如果您认为我还能改进这篇文章,请告诉我。 - L1ghtk3ira

1
你提到的 NullPointerException 是常规 Exception 的一个很好的例子,因为它是 RuntimeException 的子类。抛出 (子类的) RuntimeException 不需要被捕获或声明。
任何其他(不是 RuntimeException 的子类)异常都必须通过 try/catch 块或 throws 声明在代码中处理。否则,你的代码甚至无法编译! 这迫使你作为开发人员处理可能出现的错误。
至于为什么使用不同的异常类型是有用的,请考虑以下简单示例,其中使用了多个 catch 语句:
void doDBStuff(){
  try {
    performStatement(someStatement);
  } catch(SQLException e){
    //invalid SQL syntax, something is broken
  } catch(AuthenticationException e){
    //invalid user credentials for the db, inform the user to change these values
  }

在这个例子中,两个不同的异常最终进入了两个不同的catch块,这使得你可以以不同的方式处理这些错误。

否则,你的代码甚至无法编译!这是Java吗? - user585968
是的。如果你抛出了一个“IOException”,但是既没有使用“throws”声明,也没有捕获它,那么你会得到一个编译错误,错误信息为“Unhandled exception type IOException”。 - f1sh
太好了。谢谢。+1 - user585968
谢谢,我选择了@Carl的答案,因为他提供了出色的示例。你的信息也很棒,所以我还是给你点了赞。如果你认为这篇帖子对其他初学者抛出异常有帮助,请点赞。 - L1ghtk3ira
如果您认为我可以改进这篇文章,请告诉我。 - L1ghtk3ira

0
抛出特定的异常而不是通用的异常是最佳实践。这是因为调用者可能希望以不同的方式处理异常,例如在WebApi中,您可能希望针对ArgumentNullException返回一个错误请求响应(400),但您可能希望针对其他类型的异常返回不同的结果。例如,您可能实际上会抛出自定义的NotFoundException,然后控制器会捕获它并返回未找到响应(404)。 基本上,如果您抛出特定的异常,您就允许使用方代码按照他们想要的方式处理不同的异常情况。

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