Java 如何获得由函数返回null引起的NPE警告? 背景

Java 如何获得由函数返回null引起的NPE警告? 背景,java,eclipse,nullpointerexception,eclipse-jdt,static-code-analysis,Java,Eclipse,Nullpointerexception,Eclipse Jdt,Static Code Analysis,有时,函数在某些情况下返回null,但使用它们的人并不知道,因此NPE是不可避免的 例如(它是一个例子来说明我在说什么): 问题 Eclipse没有警告这样的事情,甚至在设置中也没有 它只能在没有涉及任何函数的情况下检测此类问题(请参见下面的编辑) 不仅如此,我还找不到表示返回值可以为null的注释。但我认为情况恰恰相反 我试过的 所以我认为,由于Eclipse没有一些检查(这很好),我可以使用其他静态代码分析工具,如和。两人都没有发现这样的错误 我试图联系这两个项目,但还没有得到任何答复。对于

有时,函数在某些情况下返回null,但使用它们的人并不知道,因此NPE是不可避免的

例如(它是一个例子来说明我在说什么):

问题 Eclipse没有警告这样的事情,甚至在设置中也没有

它只能在没有涉及任何函数的情况下检测此类问题(请参见下面的编辑)

不仅如此,我还找不到表示返回值可以为null的注释。但我认为情况恰恰相反

我试过的 所以我认为,由于Eclipse没有一些检查(这很好),我可以使用其他静态代码分析工具,如和。两人都没有发现这样的错误

我试图联系这两个项目,但还没有得到任何答复。对于CodePro,我甚至不确定我是否做对了。。。事实上,我认为这个项目已经停止了(2010年的最新更新…)

问题 是否有任何工具可以帮助避免此类错误


编辑:因为很多人认为这是可以通过改变代码来解决的,考虑在一个巨大的团队中工作,在那里一些人可能忘记了(每个人都会犯错)。或者,您甚至正在处理一个使用SDK(甚至可以是封闭源代码)的项目,该SDK在某些情况下可以返回null,但由于SDK的创建者忘记了它,所以没有记录在案

无论你是一个多么优秀的程序员,这样的事情都可能发生

我要求的是通过让eclipse提供帮助来克服这一问题。它应该能够警告我,至少在我写的基本例子上是这样

Eclipse应该能够进行这样的检查,就像它可以警告我这个例子一样:

int t=0;
--t;
String s="s";
if(t<0)
  s=null;
System.out.println(s.toString()); // here you will get a warning
我喜欢Eclipse,因为它有很多很酷的警告和错误,可以帮助避免bug,但我上面写的东西是无法被它检测到的,甚至我提到的工具也无法检测到


很多bug很难找到,没有人是一个不犯错误的完美程序员。即使你知道很多,你也不会被其他人的错误所保护。人们甚至可能找不到基本代码的错误(请参阅,或者只是看看您自己能找到多好的bug)。这就是为什么有工具可以帮助您。

方法有两种方式来表示这种“失败”。返回null或引发异常,这通常在javadoc中指示。返回null本身并不是一个错误,因为例如
HashMap.get(key)
将在没有与键关联的值的情况下返回null。让
HashMap
抛出异常将是一个错误的选择。另一方面,如果找不到实体,一些JPA方法将抛出异常(例如,请求预期存在的唯一实体)

想象一下,如果每次使用
HashMap
,eclipse都会说“小心,它可能返回null”,那么会有多少警告


总而言之:在现实生活中,警告这一点并没有多大用处,因为你会因为混乱而忽略警告。

考虑在代码中使用
@Nullable
@NonNull
注释。它可以部分地解决你的问题

更新:复制自的使用示例

更新:我的环境中空分析的设置:

来自Eclipse的实际错误消息:

更新:您需要在构建路径中包含带有Eclipse注释的JAR。将鼠标指针移到无法编译的
@NonNull
@Nullable
批注上(如图所示),然后选择“复制带有默认空批注的库”以生成路径-


新的JAR应该出现在PackageExplorer中,编译器应该能够看到它。然后将光标移动到注释并按Ctrl+Space-Eclipse应该找到正确的导入(注意,您可能会在列表上看到两个不同的包-从JDT中选择一个),然后选择它。它应该可以工作。

为代码编写单元测试:

@Test
public void testFooWithZero() {
    try{
        Test tester = new Test();
        assertEquals("Expect string returned", "positive", tester.foo(0));
    catch(NullPointerException npe) {
        fail("Threw NPE");
    }
}
它们不仅描述了您的预期行为(通常比懒散编写的Javadoc更好),还保证了您的代码实现了您的预期

为积极和消极的情景编写测试,你就成功了

静态代码分析当然有它的好处,但也有它的局限性——常见的情况是如何防止
get(Object)
从HashMap或类似集合返回null。SCA无法在运行时知道集合中有哪些数据。您也无法对来自核心Java包或第三方的代码进行注释

单元测试应该以互补的方式使用,并将提高代码的质量。查看此问题,了解您应该考虑它的几个好处和原因:


首先,您应该考虑返回
null
是否是一种好的做法:考虑使用风格结构来表示意图;即使在我添加javadocs时,它也不会强迫人们阅读它。此外,我可能也会因为忘记添加JavaDocs而犯错误,我甚至可能使用没有说明获取空值可能性的SDK。我试图说明我所写的只是一个例子,但要想得到这样一个东西的所有可能的选择——它是可能发生的,无论你是一个多么优秀的程序员。@McDowell你并不总是有机会编写你正在使用的代码。有时你会使用SDK或在一个庞大的团队中工作。FWIW Netbeans也会这样做——方法没有警告,但内联时会警告。你没有领会我的意思。如果对返回值调用函数,并且在某些情况下函数可能为null,则应得到警告。你是如何得到这个值的并不重要。Eclipse甚至可以用一种基本的方式检查代码,并在这种情况下向您发出警告。您能举个例子吗?还有,h
Java-> Compiler-> Errors/Warning-> Potential null pointer access
@NonNull String getString(String maybeString) {
    if (maybeString != null)
        return maybeString;                         // the above null check is required
    else
        return "<n/a>";
}
void caller(String s) {
    System.out.println(getString(s).toUpperCase()); // no null check required
}
public @Nullable String getMessage() {
    return System.currentTimeMillis() % 2 != 0
        ? "That's odd..."
        : null;
}

public void showCase() {
    String msg = getMessage();
    if (msg.isEmpty()) { //- Here it yields about possible null access
        //...
    }
}
@Test
public void testFooWithZero() {
    try{
        Test tester = new Test();
        assertEquals("Expect string returned", "positive", tester.foo(0));
    catch(NullPointerException npe) {
        fail("Threw NPE");
    }
}