我正在开发一个公共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异常的好方法吗?
答案 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你提供给他的一个例外,然后你必须找出错误。
答案 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 { ...
}