Java - 处理方法中的多个异常

时间:2014-10-03 12:39:35

标签: java exception-handling

我正在开发一个公共API供人们在他们的应用程序中使用。我目前正试图找出处理异常的最佳方法。例如,以下代码段会抛出四种不同的异常:

Signature s = Signature.getInstance("SHA1withRSA"); //NoSuchAlgorithmException
s.initSign(keyChain.getPrivateKey());               //InvalidKeyException
s.update(plainText.getBytes("UTF-8"));              //UnsupportedEncodingException
byte[] signature = s.sign();                        //SignatureException
String signedData = base64Encoder.encode(signature);

我的问题是,我该如何以最佳方式处理这些问题?

我提出的一种方法是捕获异常并抛出自定义异常:

public void signRequest(Request request) throws APISignatureException {
    try {
        ...
        Signature s = Signature.getInstance("SHA1withRSA"); //NoSuchAlgorithmException
        s.initSign(keyChain.getPrivateKey());               //InvalidKeyException
        s.update(plainText.getBytes("UTF-8"));              //UnsupportedEncodingException
        byte[] signature = s.sign();                        //SignatureException
        String signedData = base64Encoder.encode(signature);
        ...
    }
    catch (Exception e) {
        throw new APISignatureException("Failed to create signature", e);
    }
}

这是处理开放API异常的好方法吗?

8 个答案:

答案 0 :(得分:3)

这几乎是合理的方式!我要说的是,如果您将catch替换为特定例外列表,而不是一揽子Exception,那么它将是完全可以防御的。

让所有四种类型向上传播也是合理的。这取决于你想要什么。如果用户想要立即访问失败的原因,您可以保留未更改和未捕获的类型。如果你想要这个抽象层,那么用户只会得到一个"签名出现问题"类型,但仍然可以深入细节,然后你得到的结构是理想的。

重点是你没有隐藏任何东西:原始异常仍然埋没在新异常中,并且可供调用者使用。

答案 1 :(得分:2)

抓住一般例外通常是一个坏主意。

你可以这样做(Java 7):

public void signRequest(Request request) throws APISignatureException {
    try {
        Signature s = Signature.getInstance("SHA1withRSA"); //NoSuchAlgorithmException
        s.initSign(keyChain.getPrivateKey());               //InvalidKeyException
        s.update(plainText.getBytes("UTF-8"));              //UnsupportedEncodingException
        byte[] signature = s.sign();                        //SignatureException
        String signedData = base64Encoder.encode(signature);
    }
    catch (NoSuchAlgorithmException | InvalidKeyException | UnsupportedEncodingException | SignatureException e) {
        throw new APISignatureException("Failed to create signature", e);
    }
}

但问问自己客户将要做些什么,因为你迫使他仍然抓住你的例外。

如果客户不应该担心,因为一般情况下这不会出错,你可以抛出一个未经检查的例外:

public void signRequest(Request request) {
    try {
        Signature s = Signature.getInstance("SHA1withRSA"); //NoSuchAlgorithmException
        s.initSign(keyChain.getPrivateKey());               //InvalidKeyException
        s.update(plainText.getBytes("UTF-8"));              //UnsupportedEncodingException
        byte[] signature = s.sign();                        //SignatureException
        String signedData = base64Encoder.encode(signature);
    }
    catch (NoSuchAlgorithmException | InvalidKeyException | UnsupportedEncodingException | SignatureException e) {
        throw new RuntimeException("Failed to create signature", e); // This doesn't need to be explicitly caught
    }
}

我的意思是,如果签名出错,那么用户可能不需要继续他的应用程序,就像通​​过捕获自己的异常一样没有发生任何事情。他需要更改一些配置并再次运行他的应用程序。 RuntimeException只会传播,直到更普通的捕手捕捉它为止。

答案 2 :(得分:1)

处理异常取决于您想要做什么。大多数情况下,您无法在当前方法中执行任何操作,并且只能将错误传递给调用方法,然后您可以包装并重新抛出(甚至在您自己的签名中声明异常)。但有一段时间你可以处理它。例如,如果找不到并打开属性文件,则可以使用默认值。

答案 3 :(得分:1)

这是我的个人意见

我会说你对用户的例外越多,他可以发展的错误越详细。由于这是一个开放的API,意味着每个人都可以使用它,我会考虑粒度并提供错误,以帮助用户找出问题所在。

如果您针对每个例外提供一个特定错误,则用户也可以作为开发人员向您提供反馈。他正在尝试你的api并得到一个错误,他会告诉你git你提供给他的一个例外,然后你必须找出错误。

Gief all the info

答案 4 :(得分:1)

如果您使用Java 7,那么您可以在同一个catch子句中捕获多个异常,

 catch (APISignatureException|SignatureException e) {
    throw e;
 }

否则你需要单独捕捉它们

catch (APISignatureException e) {
    throw e;
}
catch (SignatureException e) {
    throw e;
}

你不应该使用Exception的超级类型,这样你就不会捕捉到你不想处理的异常

答案 5 :(得分:1)

现在所有异常都被 catch(异常e){捕获,然后它们都抛出 APISignatureException

你真正想做的是捕捉你的特定异常,如下:

public void signRequest(Request request) throws APISignatureException {
try {
    ...
    Signature s = Signature.getInstance("SHA1withRSA"); //NoSuchAlgorithmException
    s.initSign(keyChain.getPrivateKey());               //InvalidKeyException
    s.update(plainText.getBytes("UTF-8"));              //UnsupportedEncodingException
    byte[] signature = s.sign();                        //SignatureException
    String signedData = base64Encoder.encode(signature);
    ...
}
catch (APISignatureException e) {
     //Handle exception
}
catch (InvalidKeyException e) {
     //Handle exception
}

此外,如果您发现特定的例外,则无需再抛出另一个例外。

您还可以组合捕获多个例外:

catch (APISignatureException|InvalidKeyException e) {
    // Handle exception

}

您可以通过扩展例外类来创建自定义例外:

class APISignatureException extends Exception {
  // empty constructor
  public APISignatureException () {}

  //constructor that takes a string message
  public APISignatureException (String message)
  {
      super(message);
  }

}

有关详细信息,请查看Exception

答案 6 :(得分:1)

您需要了解this,请仔细研究。

基本理解是

try { 
   //Something that can throw an exception.
} catch (Exception e) {
  // To do whatever when the exception is caught.
} 

还有一个finally块,即使出现错误也始终执行。它像这样使用

try { 
   //Something that can throw an exception.
} catch (Exception e) {
  // To do whatever when the exception is caught & the returned.
} finally {
  // This will always execute if there is an exception or no exception.
}

在扫描仪的特定情况下,您可以有以下例外情况(link)。

InputMismatchException - 如果下一个标记与整数正则表达式不匹配,或者超出范围
NoSuchElementException - 如果输入用尽了 IllegalStateException - 如果此扫描程序已关闭

所以你需要捕捉像

这样的例外
try { 
   rows=scan.nextInt();
} catch (InputMismatchException e) {
  // When the InputMismatchException is caught.
  System.out.println("The next token does not match the Integer regular expression, or is out of range");
} catch (NoSuchElementException e) {
  // When the NoSuchElementException is caught.
  System.out.println("Input is exhausted");
} catch (IllegalStateException e) {
  // When the IllegalStateException is caught.
  System.out.println("Scanner is close");
} 

答案 7 :(得分:1)

当我编写API时,我会捕获较低级别的异常并抛出相关的API异常。这样您就不会隐藏任何内容,并允许API用户捕获一个相关的异常。

如果API很大,您可能需要几个API异常,它们都是常见API异常的子类。例如:

public class APIException { ...
}

public class APISignatureException extends APIException { ...
}

public class APISomeException extends APIException { ...
}