【问题标题】:What exceptions I should mention at method declaration, and which exception I should catch in my catch block?我应该在方法声明中提及哪些异常,以及我应该在我的 catch 块中捕获哪些异常?
【发布时间】:2012-07-17 19:32:08
【问题描述】:

假设我们有如下条件。

一)

public void method() throws ... {

      XXXXXXXXXXXXXXXXXXXXXXX;
}

或

B)

public void method(){

  try{

      XXXXXXXXXXXXXXXXXXXXXXX;
   }catch(...){

      //doing something here
   }

}

假设标有"XXXX" 的行是可能引发异常的一行代码(假设这一行不会引发错误)。

所以我的问题是,我应该在第一种情况下(在方法声明中)提到哪些异常以及我应该在我的 catch 块中捕获哪个异常??

* 我知道仅仅抛出和捕获 Exception 异常就足够了,但我认为这不是一个好的设计。 *

【问题讨论】:

  • 这就是我要问的。我应该在 catch 块或 throws 处写什么???
  • 您应该编写您的方法能够抛出的异常...如果您有一个像 eclipse 这样的 IDE,它会显示您需要包含的内容,或者您​​可以查看它的 javadoc。
  • 一般经验法则:只捕获您的方法能够从中恢复的异常。
  • @Alex,我并不是真的在问这里的概念。在“...”的地方写什么非常简单:)
  • @JaikratSingh 在 A) 中 ... 的位置,写下可能发生但您无法处理的异常。在B)中...的地方,写下可能发生并且可以处理的异常类型。 (如果有更多没有理智的公共超类的人,请使用更多 catch 块。Exception 不理智,除非您只是将虚假的已检查异常(例如反射 API 抛出的异常)包装在未检查的异常中.)

标签: java exception exception-handling core


【解决方案1】:

您似乎在问如何判断给定方法将或可能抛出哪些异常。这很难回答,因为您没有告诉我们您要运行什么方法。但 Java 的部分要点在于它是静态类型的,而且您实际上确实知道任何方法都可以抛出哪些异常。不显式捕获您调用的任何异常方法可能会触发是编译时错误,因此您会立即知道您是否应该捕获某些东西。 RuntimeException 是个例外,它是孩子,故意不属于编译时契约的一部分。

一般来说,RuntimeExceptions 不应该被捕获,它们表示某种你不应该让你的程序首先进入的状态(比如不检查 null 触发 NullPointerException)但是您可以查看文档以了解您正在使用的方法,看看它们可能会抛出什么。例如,String.substring() 表示它可能会抛出 IndexOutOfBoundsException。通常,您应该提前进行必要的索引检查,但如果您不能提前这样做,您可以抓住它,如下所示:

int userInputWeCantTrust = -4;
try {
  System.out.println("foo".substring(userInputWeCantTrust));
} catch (IndexOutOfBoundsException e) {
  System.err.println("Looks like I can't trust you, user.");
}

执行此操作时,您希望尽可能明确地处理异常类型(例如,捕获 IndexOutOfBoundsException,而不是 RuntimeException),并在 try 块中放置尽可能少的代码。否则,您可能会意外捕获本应允许继续传播的异常。


决定接球还是扔球是一个设计决策。如果您能够处理给定的异常,则将其包装在 try-catch 中,如果不能,则不要。

示例一,解析整数,失败时默认为default:

public static int parse(String s, int default) {
  try {
    return Integer.parseInt(s);
  } catch (NumberFormatException e) {
    return default;
  }
}

示例二,解析用户输入,让main方法处理报错:

// the throws note here isn't actually necessary, since NFE is a RuntimeException
public static int parse(String s) throws NumberFormatException {
  return Integer.parseInt(s);
}

public static void main(String[] args) {
  try {
    for(String s : args){
      System.out.println(parse(s));
    }
  } catch (NumberFormatException e) {
    System.err.println("You entered an invalid number.");
  }
}

这真的取决于你的用例。

【讨论】:

  • "这真的取决于你的用例。" 如果你一开始就写了这行代码,那么就没有必要解释这么大了。开个玩笑,很好的解释。感谢回复
  • 那是我首先写的,但是你的 cmets 对其他人暗示你不想听到什么时候捕捉和抛出,而是你可能会捕捉到什么异常。如果您发现有人回答了您没有提出的问题,请再看一遍您的问题,您可能会重新审视它并使其更清晰。
【解决方案2】:

编译器将为您回答这些问题:您需要捕获您的代码可以生成的Exceptions,或将它们声明为由您的方法抛出。如果您遗漏了任何内容,编译器会抱怨。 RuntimeExceptions 是个例外。

您唯一的选择是捕获这些特定异常或使用throws 传播它们。这个选择 - Exceptions 被抛出和被捕获,取决于你的特定目标。

您需要熟悉您正在使用的 API,其中一部分 API 是 API 方法抛出的 Exceptions,但如果您错过了一个,那么您的代码将无法编译,从而为您提供有机会解决它。

【讨论】:

  • 这没什么意义。编译器会在这方面帮助我。
【解决方案3】:

简单地说:

  1. (a) 所有检查的异常
  2. (b) 所有处理的异常

如果您没有像become part of the documentation for that method 那样处理它们,最好将异常标记为已抛出(例如JavaDocs):

任何可以被方法抛出的异常都是该方法的一部分 公共编程接口。调用方法的人一定知道 方法可以抛出的异常,以便它们可以决定要做什么 做他们。这些异常也是该方法的一部分 编程接口作为它的参数和返回值。

对于您的catch 块,主要是确保您正在处理您捕获的任何异常(至少,记录异常消息)。您可能想尝试从异常中恢复,抛出不同类型的异常或只记录输出:

例如好:

catch(NullPointerException e) {
    variable = "default-value";
}

catch(NullPointerException e) {
    throw new OhNoesException();
}

catch(NullPointerException e) {
    log.warn(e.getMessage());
}

如果您所做的只是丢弃异常,最好还是抛出它。 E,g, Bad(作为一般经验法则):

catch(NullPointerException e) {}

【讨论】:

    【解决方案4】:

    试着想想调用者对你的方法有什么期望。想想这是你的方法给调用者的“承诺”。

    现在,假设您正在调用某个东西,并且您可能会遇到异常。您可能会问自己的问题是:我是否仍然可以通过处理该异常来履行我所做的承诺并继续前进?如果你不能:抛出异常(或者,或者,抛出一个不同的异常——通过将它包装在 MyApplicationException 或其他东西中)。

    如前所述:这可能是一个设计问题——整数解析方法的“承诺”可能是“以最佳方式将字符串转换为数字”,在这种情况下,您不需要在任何情况下都抛出异常,或者它可能是“解析一个应该是正确编码整数的字符串”;在这种情况下,抛出异常会是一个更好的主意。

    【讨论】:

      猜你喜欢
      • 2012-04-16
      • 2014-04-19
      • 2017-12-11
      • 1970-01-01
      • 1970-01-01
      • 2020-04-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多