Java - 方法中处理多个异常

4

我正在开发一个公共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异常的好方法吗?

只要它们不高于继承层次结构中的下一个,您可以按调用顺序逐个捕获每个。 - shinjw
8个回答

3
这是一个非常合理的做法!如果你将catch替换为特定异常的列表,而不是一个通用的Exception,那么这样做就完全可以被证明是正确的。
让所有四种类型向上传播也是相当合理的。这取决于你想要什么。如果用户想要立即访问失败原因,你可能会保留类型不变且未捕获异常。如果你想要这个抽象层,其中用户只能得到“签名出了问题”的类型,但仍然可以深入细节,那么你现有的结构就是理想的。
重点是你没有隐藏任何内容:原始异常仍然包含在新异常中,并可供调用者使用。

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 将一直传播,直到一个更普通的 catcher 捕获它。


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

1
我个人认为,对于用户而言,你提供的例外越多,他就会出现越多的详细错误。由于这是一个开放的API,意味着每个人都可以使用它,因此我会提供能够帮助用户找出问题的错误信息。如果你在每个例外中提供一个具体的错误,用户也可以向你作为开发者提供反馈。当他尝试使用你的API时遇到错误,他将向你提供该异常,然后你需要找出问题所在。

Gief all the info


1
如果您使用Java 7,则可以在同一个catch子句中捕获多个异常。
 catch (APISignatureException|SignatureException e) {
    throw e;
 }

否则,您需要单独捕获它们。
catch (APISignatureException e) {
    throw e;
}
catch (SignatureException e) {
    throw e;
}

你不应该使用超类Exception,这样你就不会捕获你不想处理的异常。

最后一句话是不正确的。抛出新异常会重置调用堆栈,而不是使用“Exception”。 - Nathan Merrill
@NathanMerrill 你说得对,我现在会进行编辑。谢谢。 - Sleiman Jneidi

1

现在你的所有异常都被 catch (Exception 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

}

你可以通过扩展 Exception 类来创建自定义异常:
class APISignatureException extends Exception {
  // empty constructor
  public APISignatureException () {}

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

}

更多细节请查看 异常


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

1
当我编写API时,我捕获低级别的异常并抛出相关的API异常。这样你不会隐藏任何东西,并且允许API用户捕获一个相关的异常。
如果API很大,您可能需要几个API异常,它们都是公共API异常的子类。例如:
public class APIException { ...
}

public class APISignatureException extends APIException { ...
}

public class APISomeException extends APIException { ...
}

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