我使用x!=null以避免NullPointerException。还有其他选择吗?
if (x != null) {
// ...
}
我使用x!=null以避免NullPointerException。还有其他选择吗?
if (x != 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
其他回答
您可以考虑空对象是bug的情况,而不是空对象模式(有其用途)。
当抛出异常时,检查堆栈跟踪并解决错误。
最终,彻底解决这个问题的唯一方法是使用不同的编程语言:
在Objective-C中,你可以在nil上调用一个方法,而绝对不会发生任何事情。这使大多数空检查变得不必要,但会使错误更难诊断。在Nice这一Java派生语言中,所有类型都有两个版本:可能为空的版本和非空的版本。只能对非空类型调用方法。通过显式检查null,可以将可能为null的类型转换为非null类型。这使得更容易知道哪些地方需要空检查,哪些地方不需要空检查。
另一个建议是防御性地编程——类/函数提供已知且安全的默认值,并且为真正的错误/异常保留null。
例如,如果函数在出现问题时(例如将数字转换为字符串)返回空字符串,请让它们返回空字符串(“”)。在继续之前,您仍然必须测试返回值,但对于异常没有特殊情况。这种编程风格的另一个好处是,您的程序能够区分正常操作和异常,并做出相应的响应。
我们一直在使用Apache库(Apache Commons)解决这个问题。
ObjectUtils.equals(object, null)
or
CollectionUtils.isEmpty(myCollection);
or
StringUtils.isEmpty("string");
作为一种实践,我喜欢前面的回答,即为集合提供初始默认值或空集,以最小化需要。
这些可以是防止出现NullPointerException或使用空集合的简单用法。这并不能回答如何处理空对象的问题,但它们为对象或集合的基本验证提供了一些检查。
希望这有帮助。
根据所检查的对象类型,您可以使用apachecommons中的一些类,例如:apachecommons-lang和apachecommons集合
例子:
String foo;
...
if( StringUtils.isBlank( foo ) ) {
///do something
}
或(取决于您需要检查的内容):
String foo;
...
if( StringUtils.isEmpty( foo ) ) {
///do something
}
StringUtils类只是众多类中的一个;在commons中有相当多的好类可以进行空安全操作。
下面是一个示例,说明当您包含apache库(commons-lang-2.4.jar)时,如何在JAVA中使用空值验证
public DOCUMENT read(String xml, ValidationEventHandler validationEventHandler) {
Validate.notNull(validationEventHandler,"ValidationHandler not Injected");
return read(new StringReader(xml), true, validationEventHandler);
}
如果您使用的是Spring,Spring的包中也有相同的功能,请参见库(Spring-2.46.jar)
关于如何使用spring中的静态类f的示例(org.springframework.util.Assert)
Assert.notNull(validationEventHandler,"ValidationHandler not Injected");