我使用x!=null以避免NullPointerException。还有其他选择吗?

if (x != null) {
    // ...
}

当前回答

仅适用于这种情况-

在调用equals方法之前不检查变量是否为空(下面的字符串比较示例):

if ( foo.equals("bar") ) {
 // ...
}

如果foo不存在,将导致NullPointerException。

如果这样比较字符串,可以避免这种情况:

if ( "bar".equals(foo) ) {
 // ...
}

其他回答

我可以更笼统地回答吗!

当方法以我们不期望的方式获取参数时,我们通常会遇到这个问题(错误的方法调用是程序员的错误)。例如:您希望得到一个对象,而得到一个null。您希望得到一个至少包含一个字符的字符串,而得到一个空字符串。。。

因此:

if(object == null){
   //you called my method badly!

}

or

if(str.length() == 0){
   //you called my method badly again!
}

他们都希望在执行任何其他函数之前确保我们收到了有效的参数。

如其他一些答案中所述,为了避免上述问题,您可以遵循契约设计模式。请参见http://en.wikipedia.org/wiki/Design_by_contract.

要在java中实现这种模式,可以使用javax.annotation.NotNull等核心java注释,或者使用Hibernate Validator等更复杂的库。

只是一个示例:

getCustomerAccounts(@NotEmpty String customerId,@Size(min = 1) String accountType)

现在,您可以安全地开发方法的核心函数,而无需检查输入参数,它们可以保护您的方法不受意外参数的影响。

您可以更进一步,确保在应用程序中只能创建有效的pojo。(来自hibernate验证器站点的示例)

public class Car {

   @NotNull
   private String manufacturer;

   @NotNull
   @Size(min = 2, max = 14)
   private String licensePlate;

   @Min(2)
   private int seatCount;

   // ...
}

您可以使用类似JUnit的框架将类与单元测试相结合。这样,您的代码将是干净的(没有无用的检查),并且您将确保您的实例不会为空。

这是使用单元测试的一个很好的理由。

Null不是“问题”。它是完整建模工具集的一个组成部分。软件旨在模拟世界的复杂性,零承担其负担。Null表示Java等中的“无数据”或“未知”。因此,为这些目的使用null是合适的。我不喜欢“空对象”模式;我想谁来守护监护人的问题。如果你问我女朋友的名字,我会告诉你我没有女朋友。在Java语言中,我将返回null。另一种方法是抛出有意义的异常,以指示一些无法(或不希望)立即解决的问题,并将其委派到堆栈中较高的位置,以重试或向用户报告数据访问错误。

对于“未知问题”,给出“未知答案”。(如果从业务角度来看,这是正确的,请确保null安全)在使用前检查方法内的null参数一次,可以避免多个调用方在调用前检查它们。公共照片getPhotoOfThePerson(个人){if(person==null)返回null;//占用一些资源或密集计算//无论如何使用person对象。}前一条导致了正常的逻辑流程,无法从我的照片库中获取不存在的女友的照片。获取人物照片(me.getGirlfriend())它与即将推出的新Java API相匹配(展望未来)getPhotoByName(me.getGirlfriend()?。getName())虽然找不到存储在数据库中的照片是相当“正常的业务流程”,但我过去在一些其他情况下会使用下面这样的配对公共静态MyEnum parseMyEnum(字符串值);//抛出IllegalArgumentException公共静态MyEnum parseMyEnumOrNull(字符串值);不要讨厌键入<alt>+<shift>+<j>(在Eclipse中生成javadoc)并为公共API编写三个额外的单词。除了那些不阅读文档的人,这对所有人来说都绰绰有余。/***@return photo或null*/或/***@return photo,从不为空*/这是一种理论上的情况,在大多数情况下,您应该更喜欢java空安全API(以防它在10年后发布),但NullPointerException是Exception的子类。因此,它是Throwable的一种形式,表示合理的应用程序可能想要捕获的条件(javadoc)!要使用异常的第一个最大优点,并将错误处理代码与“常规”代码分开(根据Java的创建者),对我来说,捕捉NullPointerException是合适的。公共照片getGirlfriendPhoto(){尝试{return appContext.getPhotoDataSource().getPhotoByName(me.getGirlfriend().get-Name());}catch(NullPointerException e){返回null;}}可能会出现以下问题:问:如果getPhotoDataSource()返回null怎么办?答:这取决于业务逻辑。如果我找不到相册,我就不给你看照片。如果appContext未初始化怎么办?该方法的业务逻辑可以满足这一点。如果相同的逻辑应该更严格,那么抛出异常是业务逻辑的一部分,应该使用显式检查null(情况3)。新的Java Null安全API在这里更适合于有选择地指定哪些内容意味着,哪些内容不意味着在发生程序员错误时被初始化为快速失败。Q.可以执行冗余代码,并且可以获取不必要的资源。答:如果getPhotoByName()尝试打开一个数据库连接,创建PreparedStatement,最后将人名用作SQL参数,则可能会发生这种情况。未知问题的方法给出了未知答案(案例1)。在获取资源之前,该方法应检查参数,并在需要时返回“未知”结果。问:由于尝试关闭,这种方法会导致性能损失。A.软件应易于理解和修改。只有在这之后,人们才能考虑性能,而且只有在需要的时候!以及需要的地方!(来源)和许多其他)。PS.这种方法将是合理的,因为单独的错误处理代码和“常规”代码原则在某些地方是合理的。考虑下一个示例:public SomeValue calculateSomeValueUsingSophisticatedLogic(谓词谓词){尝试{Result1 Result1=performSomeCalculation(谓词);Result2 Result2=performSomeOtherCalculation(result1.getSomeProperty());Result3 Result3=performThirdCalculation(result2.getSomeProperty());Result4 Result4=performLastCalculation(result3.getSomeProperty());return result4.getSomeProperty();}catch(NullPointerException e){返回null;}}public SomeValue calculateSomeValueUsingSophisticatedLogic(谓词谓词){SomeValue结果=空;if(谓词!=null){Result1 Result1=performSomeCalculation(谓词);如果(result1!=null&&result1.getSomeProperty()!=空){Result2 Result2=performSomeOtherCalculation(result1.getSomeProperty());如果(result2!=null&&result2.getSomeProperty()!=空){Result3 Result3=performThirdCalculation(result2.getSomeProperty());如果(result3!=null&&result3.getSomeProperty()!=空){Result4 Result4=performLastCalculation(result3.getSomeProperty());if(result4!=null){result=result4.getSomeProperty();}}}}}返回结果;}PPS。对于那些快速向下投票(而且阅读文档的速度不太快)的人,我想说,我一生中从未遇到过空指针异常(NPE)。但这种可能性是Java创建者故意设计的,因为NPE是Exception的子类。我们在Java历史上有过这样一个先例:ThreadDeath是一个错误,不是因为它实际上是一个应用程序错误,而是因为它不打算被捕获!NPE比ThreadDeath更适合作为错误!但事实并非如此。仅当业务逻辑暗示时,才检查“无数据”。public void updatePersonPhoneNumber(长personId,字符串phoneNumber){如果(personId==空)回来DataSource DataSource=appContext.getStuffDataSource();个人=dataSource.getPersonById(personId);if(person!=null){person.setPhoneNumber(电话号码);dataSource.updatePerson(人);}其他{人员=新人员(personId);person.setPhoneNumber(电话号码);dataSource.insertPerson(个人);}}和public void updatePersonPhoneNumber(长personId,字符串phoneNumber){如果(personId==空)回来DataSource DataSource=appContext.getStuffDataSource();个人=dataSource.g

只是永远不要使用null。不要允许。

在我的类中,大多数字段和局部变量都有非空的默认值,我在代码中的任何地方都添加了契约语句(总是在断言上),以确保这是强制执行的(因为它比让它作为NPE出现然后必须解析行号等更简洁、更具表达力)。

一旦我采用了这种做法,我注意到问题似乎会自行解决。你会在开发过程中很早就发现事情,只是偶然发现自己有一个弱点。。更重要的是。。它有助于封装不同模块的关注点,不同模块可以相互“信任”,不再在代码中添加if=nullelse结构!

这是一种防御性编程,从长远来看,代码会更加干净。始终对数据进行净化,例如在这里通过强制执行严格的标准,问题就会消失。

class C {
    private final MyType mustBeSet;
    public C(MyType mything) {
       mustBeSet=Contract.notNull(mything);
    }
   private String name = "<unknown>";
   public void setName(String s) {
      name = Contract.notNull(s);
   }
}


class Contract {
    public static <T> T notNull(T t) { if (t == null) { throw new ContractException("argument must be non-null"); return t; }
}

合同就像是小型单元测试,即使在生产中也始终在运行,当事情失败时,你知道原因,而不是随机的NPE,你必须设法弄清楚。

有一种很好的方法来检查JDK中的空值。Optional.java有大量解决这些问题的方法。例如:

    /**
     * Returns an {@code Optional} describing the specified value, if non-null,
     * otherwise returns an empty {@code Optional}.
     *
     * @param <T> the class of the value
     * @param value the possibly-null value to describe
     * @return an {@code Optional} with a present value if the specified value
     * is non-null, otherwise an empty {@code Optional}
     */
    public static <T> Optional<T> ofNullable(T value) {
        return value == null ? empty() : of(value);
    }
    /**
     * Return {@code true} if there is a value present, otherwise {@code false}.
     *
     * @return {@code true} if there is a value present, otherwise {@code false}
     */
    public boolean isPresent() {
        return value != null;
    }
    /**
     * If a value is present, invoke the specified consumer with the value,
     * otherwise do nothing.
     *
     * @param consumer block to be executed if a value is present
     * @throws NullPointerException if value is present and {@code consumer} is
     * null
     */
    public void ifPresent(Consumer<? super T> consumer) {
        if (value != null)
            consumer.accept(value);
    }

帮助标枪真的非常非常有用。