0

假设我们有如下条件。

一个)

public void method() throws ... {

      XXXXXXXXXXXXXXXXXXXXXXX;
}

或者

二)

public void method(){

  try{

      XXXXXXXXXXXXXXXXXXXXXXX;
   }catch(...){

      //doing something here
   }

}

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

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

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

4

4 回答 4

3

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

通常,RuntimeExceptions 不应该被捕获,它们表示您不应该让程序首先进入的某种状态(例如不检查null触发 a 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.");
}

当您这样做时,您希望尽可能明确地使用异常类型(例如 catch IndexOutOfBoundsException, not RuntimeException),并在块中放置尽可能少的代码try。否则,您可能会意外捕获本应允许继续传播的异常。


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

示例一,解析整数,默认为defaulton failure:

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.");
  }
}

这实际上取决于您的用例。

于 2012-07-17T19:39:35.690 回答
1

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

您唯一的选择是捕获这些特定异常或使用throws. 这种选择 - 哪些Exceptions被抛出,哪些被捕获,取决于您的特定目标。

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

于 2012-07-17T19:40:06.047 回答
0

简单地说:

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

如果您不处理异常,最好将它们标记为抛出,因为它们成为该方法文档的一部分(例如 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) {}
于 2012-07-17T19:39:57.453 回答
0

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

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

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

于 2012-07-17T19:49:12.897 回答