请参阅以下两个示例。假设两个类都包含属于广泛使用的API库的公共方法。
AClass.java
更容易编写(由于噪音更少,可能更容易阅读),但是当检测到错误时,堆栈跟踪中的第一个方法是内部方法(nullCheck(...)
)和异常消息不是指那种方法。这会对用户造成不必要的混淆吗?我的意思是在用户思考的意义上:“它是一个抛出异常的内部方法,必须是库中的错误,而不是我的程序中的错误。什么是 * *无用的库。 ..“
BClass.java
更难以编写(使用其所有if语句),但是当检测到错误时,堆栈跟踪的第一行会确定首先检测到错误的API方法(由用户调用)。这更有可能让用户思考:“我从我的代码中调用该方法,我传入的参数一定是错误的。”
在公共API中检查参数的有效性时,哪种方法是抛出异常?或者这两个例子是否相同?
public class AClass {
public void publicApiMethod1(String a){
nullCheck(a, "a");
// do something...
}
public void publicApiMethod2(String a, String b, String c){
nullCheck(a, "a");
nullCheck(b, "b");
nullCheck(c, "c");
// do something...
}
private void nullCheck(Object a, String argName) {
if(a == null){
throw new NullPointerException("Null argument: " + argName);
}
}
}
public class BClass {
public void publicApiMethod1(String a){
if(a == null){
throw new NullPointerException("Null argument: 'a'");
}
// do something...
}
public void publicApiMethod2(String a, String b, String c){
if(a == null){
throw new NullPointerException("Null argument: 'a'");
}
if(b == null){
throw new NullPointerException("Null argument: 'b'");
}
if(c == null){
throw new NullPointerException("Null argument: 'c'");
}
// do something...
}
}
答案 0 :(得分:5)
如果您的错误消息是描述性的(并且它是),则没有人会费心去查看堆栈跟踪。因此,第一种形式更好,因为它封装了验证逻辑。
请注意,各种库中都有大量的断言方法可供使用,请参阅:Objects.requireNonNull
和Validate.notNull
)。
答案 1 :(得分:2)
我会这样做,基本上是基于你的AClass
:
public void publicApiMethod2(String a, String b, String c){
try {
nullCheck(a, "a");
nullCheck(b, "b");
nullCheck(c, "c");
}
// catch the NullPointerException,
// and any other Exception explicitly thrown by your validation methods
catch (NullPointerException e) {
throw new IllegalArgumentException(e.getMessage());
}
// do something...
}
这样,用户就会收到一条明确的消息和指向公共方法的堆栈跟踪。
答案 2 :(得分:1)
在你的b级中为什么不使用
if( (c == null)|| (b == null)|| (a == null) ){
//thrown my red ball
}
不那么烦人,更具可读性
答案 3 :(得分:1)
我认为A级是好的,只要你用@throws
清楚地记录它。我已经看到很多库会在堆栈中更深入。重要的是让用户理解为什么抛出错误以及他们可以做些什么来避免错误。