Java Null Reference Best Practice
在Java中,下面哪一个是处理可能的空引用的更"被接受"的方式?请注意,空引用并不总是指示错误…
1 2 3 4 5 6 | if (reference == null) { //create new reference or whatever } else { //do stuff here } |
或
1 2 3 4 5 6 |
已经给出的答案非常好(不要将异常用于控制流;异常的抛出和处理成本很高)。还有另外一个重要的原因,特别是没有抓到
考虑执行以下操作的代码块:
1 2 3 4 5 6 7 | try { reference.someMethod(); // Some other code } catch (NullPointerException e) { // 'reference' was null, right? Not so fast... } |
这似乎是处理
捕获异常是相对昂贵的。通常情况下,最好是检测情况,而不是对其作出反应。
当然是这个
1 2 3 4 5 6 | if (reference == null) { //create new reference or whatever } else { //do stuff here } |
我们不应该依赖例外来做决定,因为这根本不是为了这个目的,而且它们也很昂贵。
如果你不做决定,只是验证初始化变量,那么
1 2 3 4 | if (reference == null) { //create new reference or whatever } //use this variable now safely |
我见过一些自动代码生成器用accessors/getter方法包装这件事。
从答案中可以清楚地看出,捕获异常是不好的。:)例外绝对不是免费的。这可能有助于你深入理解它。.
我还想提到另一种做法,同时比较你的对象和已知的值。这是做这项工作的传统方法:(检查对象是否为空,然后比较)
1 2 3 4 | Object obj = ??? //We dont know whether its null or not. if(obj!=null && obj.equals(Constants.SOME_CONSTANT)){ //your logic } |
但是这样,你就不必为你的目标烦恼了:
1 2 3 4 | Object obj = ??? if(Constants.SOME_CONSTANT.equals(obj)){ //this will never throw //nullpointer as constant can not be null. } |
我认为一般情况下,应该为异常情况保留一个异常——如果有时需要空引用,则应该检查并显式处理它。
第一种形式:
1 2 3 4 5 6 7 8 | if (reference == null) { //create new reference or whatever } else { //do stuff here } |
不应对控制流使用异常。
例外情况是处理在正常操作条件下通常不会发生的例外情况。
第一,抛出异常是一个代价高昂的操作。
既然您要求最佳实践,我想指出MartinFowler建议将空引用的子类作为最佳实践引入。
1 | public class NullCustomer extends Customer {} |
因此,您可以避免处理nullPointerException的麻烦,这是未经检查的。方法可能返回客户值为空,然后将返回空客户而不是空客户。
您的支票如下:
1 2 3 4 5 6 7 | final Customer c = findCustomerById( id ); if ( c instanceof NullCustomer ) { // customer not found, do something ... } else { // normal customer treatment printCustomer( c ); } |
在我看来,在某些情况下,可以捕获NullPointerException,以避免对空引用进行复杂的检查,并增强代码的可读性,例如。
1 2 3 4 5 6 | private void printCustomer( final Customer c ) { try { System.out.println("Customer" + c.getSurname() +"" + c.getName() +"living in" + c.getAddress().getCity() +"," + c.getAddress().getStreet() ); } catch ( NullPointerException ex ) { System.err.println("Unable to print out customer information.", ex ); } |
反对它的一个论点是,通过检查单个成员是否为空,您可以编写更详细的错误消息,但这通常不是必需的。
这与您的开发风格有关,如果您使用"安全"风格开发代码,则必须使用
1 2 3 4 5 | if(null == myInstance){ // some code }else{ // some code } |
但是,如果您不使用这种样式,那么至少应该捕获异常,但在这种情况下,它是nullpointerException,我认为最好检查输入参数是否为空,而不是等待抛出异常。
在这种情况下,当我们可以开始做的时候,尝试捕捉方法可能会变得有意义。
1 2 3 4 5 6 7 | try { //do stuff here } catch (NullPointerException e) { //create new reference or whatever retry; } |
您应该在不希望出现错误的地方使用异常捕获。如果某个值可以为空,那么您应该检查它。