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

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

当前回答

在Java8中,如果局部变量/字段/方法参数/方法返回类型从未赋值为null(并且不检查null),则可以使用类型T;如果可以为null,则可以键入Optional<T>。然后使用方法map处理T->,使用方法flatMap处理T->可选<R>:

class SomeService {
    @Inject
    private CompanyDao companyDao;

    // return Optional<String>
    public Optional<String> selectCeoCityByCompanyId0(int companyId) {
        return companyDao.selectById(companyId)
                .map(Company::getCeo)
                .flatMap(Person::getHomeAddress)
                .flatMap(Address::getCity);
    }

    // return String + default value
    public String selectCeoCityByCompanyId1(int companyId) {
        return companyDao.selectById(companyId)
                .map(Company::getCeo)
                .flatMap(Person::getHomeAddress)
                .flatMap(Address::getCity)
                .orElse("UNKNOWN");
    }

    // return String + exception
    public String selectCeoCityByCompanyId2(int companyId) throws NoSuchElementException {
        return companyDao.selectById(companyId)
                .map(Company::getCeo)
                .flatMap(Person::getHomeAddress)
                .flatMap(Address::getCity)
                .orElseThrow(NoSuchElementException::new);
    }
}

interface CompanyDao {
    // real situation: no company for such id -> use Optional<Company> 
    Optional<Company> selectById(int id);
}

class Company {
    // company always has ceo -> use Person 
    Person ceo;
    public Person getCeo() {return ceo;}
}

class Person {
    // person always has name -> use String
    String firstName;
    // person can be without address -> use Optional<Address>
    Optional<Address> homeAddress = Optional.empty();

    public String getFirstName() {return firstName;}   
    public Optional<Address> getHomeAddress() {return homeAddress;}
}

class Address {
    //  address always contains country -> use String
    String country;
    //  city field is optional -> use Optional<String>
    Optional<String> city = Optional.empty();

    String getCountry() {return country;}    
    Optional<String> getCity() {return city;}
}

其他回答

我高度无视建议在任何情况下使用空对象的答案。这种模式可能会破坏合同,将问题埋得越来越深,而不是解决问题,更不用说使用不当会产生另一堆需要未来维护的样板代码。

实际上,如果从方法返回的某个值可以为空,并且调用代码必须对此做出决定,那么应该有一个更早的调用来确保状态。

还请记住,如果不小心使用,空对象模式将占用内存。为此,NullObject的实例应该在所有者之间共享,而不是每个所有者的unigue实例。

此外,我不建议在类型是原始类型表示的情况下使用这种模式,比如数学实体,它们不是标量:向量、矩阵、复数和POD(普通旧数据)对象,它们是用来以Java内置类型的形式保存状态的。在后一种情况下,您将以任意结果调用getter方法。例如,NullPerson.getName()方法应该返回什么?

为了避免荒谬的结果,值得考虑这样的案例。

Java8现在有一个可选类,该类包装考虑中的对象,如果存在值,isPresent()将返回true,而get()则返回值。

http://www.oracle.com/technetwork/articles/java/java8-optional-2175753.html

无论您在何处传递数组或向量,请将它们初始化为空值,而不是空值。-这样可以避免大量检查null,一切都很好:)

public class NonNullThing {

   Vector vectorField = new Vector();

   int[] arrayField = new int[0];

   public NonNullThing() {

      // etc

   }

}

如果不允许空值

如果从外部调用方法,请从以下内容开始:

public void method(Object object) {
  if (object == null) {
    throw new IllegalArgumentException("...");
  }

然后,在该方法的其余部分中,您将知道该对象不为空。

如果它是一个内部方法(不是API的一部分),只需记录它不能为空,就可以了。

例子:

public String getFirst3Chars(String text) {
  return text.subString(0, 3);
}

但是,如果您的方法只是传递值,而下一个方法传递值等,则可能会出现问题。在这种情况下,您可能需要检查上述参数。

如果允许为空

这真的取决于。如果发现我经常这样做:

if (object == null) {
  // something
} else {
  // something else
}

所以我分支,做两件完全不同的事情。没有难看的代码片段,因为我确实需要根据数据做两件不同的事情。例如,我应该处理输入,还是应该计算一个好的默认值?


实际上,我很少使用“if(object!=null&&…”这个成语。

如果你展示了你通常使用这个习语的例子,那么给你举例可能会更容易。

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