在Java中,从调用者或调用的方法中进行所有必要的检查是否更好?

LaR*_*RRy 21 java validation exception

我们来看看这两个例子.

第一:

try {
    execute(testObj);
} catch(Exception e) {
    //do somethingwith that
}

public void execute(TestObj testObj) throws Exception {
    if (testObj == null){
        throw new Exception("No such object");
    }
    //do something with object
}
Run Code Online (Sandbox Code Playgroud)

第二:

if (testObj != null){
    execute(testObj);
} else {
    //handle this differently
}

public void execute(TestObj testObj) {
    //do something with object
}
Run Code Online (Sandbox Code Playgroud)

如果我们需要检查"is null"或其他任何东西,现在不是重点.我想知道哪种做法总体上更好 - " 检查,然后做 "或" 做,然后处理异常,如果发生 "?

Lie*_*yan 29

也不应该只检查系统之间边界.

系统之间的界限是什么?

  1. 当您收到用户的输入时,
  2. 当您读取文件,网络或套接字时,
  3. 当您进行系统调用或进程间通信时,
  4. 在库代码中,在所有面向公众的API中.
  5. 等等

在库代码中,由于公共API可能由外部代码调用,因此您应该始终检查可由外部代码调用的任何内容.无需检查仅限内部的方法(即使其访问修饰符是公共的).然后,异常或返回代码可以根据个人喜好来发出参数错误信号,但是不能忽略已检查的异常,因此通常是向外部代码发送错误信号的首选方法.

在应用程序代码(而不是库)中,只应在接收来自用户的输入,加载URL,读取文件等时进行检查.不需要在公共方法中进行输入检查,因为它们只是由您自己的应用程序代码调用.

在您自己的代码中,您应该避免首先需要检查的情况.例如,null您可以使用"null object pattern"代替检查.如果你仍然需要做一个检查,尽早做,这通常意味着在外面做,但试图找到更早的点.

即使没有正式记录,即使没有强制执行,所有方法,无论是内部还是面向公众,都应该有合同.不同之处在于,在面向外部的代码中,您应该将合同强制执行作为错误检查的一部分,而在仅限内部的代码中,您可以并且应该依赖于调用者知道要传递什么和不传递什么.

简而言之,由于只在系统边界上进行检查,如果您实际上可以选择是在方法内部还是外部检查,那么您可能不应该检查那里,因为那不是系统边界.

在系统边界中,双方总是必须检查.调用者必须检查外部调用是否成功,并且被调用者必须检查调用者是否提供了合理的输入/参数.忽略调用者中的错误几乎总是一个错误.坚固原则适用,始终检查从外部系统收到的所有内容,但只发送您知道外部系统可以接受的内容.

但是,在非常大的项目中,通常需要将项目划分为小模块.在这种情况下,项目中的其他模块可以视为外部系统,因此您应该在API中进行检查,这些API将暴露给项目中的其他模块.

TLDR; 检查很难.


Pab*_*afi 8

正如@LieRyan所说,你应该只检查系统之间的界限.但是一旦你进入你自己的代码,你仍然需要能够发现意外的问题,主要是因为:

  • 你(和你的同事)并不完美,可能会将null传递给无法处理它的方法.
  • 如果一行使用两个对象而一个为null,则NPE不会告诉您哪一个是怪(System.out.println("a.getName()"+"b.getName()")抛出NPE ...是null或b null还是两者都有?)

清楚地记录哪些方法接受null作为参数,或者可以返回null.
一个很好的工具,可以帮助你,如果你使用Eclipse Juno,(我认为IntelliJ-Idea有类似的东西)是启用空检查分析.它允许您编写一些注释以使编译时空检查.真的很棒.你可以写类似的东西

public @NonNull String method(@Nullable String a){
//since a may be null, you need to make the check or code will not compile
    if(a != null){
        return a.toUppercase();        
    }
    return ""; //if you write return null it won't compile, 
     //because method is marked NonNull 
}
Run Code Online (Sandbox Code Playgroud)

它还有一个很好的@NonNullByDefault,基本上说"没有方法接受或返回null,除非标记为@Nullable"这是一个很好的默认值,保持你的代码干净和安全.

有关更多信息,请查看Eclipse帮助


dav*_*rld 2

第二个比第一个更好,任何异常都可能引发,并且您会认为这是预期的。

请记住,使用异常来控制程序流在计算上也很昂贵,因为构建异常会降低性能。例如,在 hibernate 中,最好执行 a 来SELECT COUNT(*)检查行是否存在,而不是查看 recordNotFoundException 是否触发并将应用程序逻辑基于该异常触发。