此问题与this one类似,但重点有所不同
我有一个功能,可以在try catch块中将文件加载到磁盘上。由于该文件对于程序至关重要,因此如果无法加载该文件,它将终止:
String loadSuperImportantFile() {
try {
// ... file loading code ...
assert fileContent != null;
return fileContent;
} catch(IOException ex) {
System.err.println("Failed to load super important file. Please check path.");
System.exit(Codes.FAIL); // terminate the program
}
return null; // statement is unreachable
}
IntelliJ IDEA无法识别此函数不可能返回null。因此,每当我使用返回字符串时,我都会收到警告:
foo(loadSuperImportantFile()); // WARNING: Argument "loadSuperImportantFile()" might be null.
通过阅读我上面链接的问题,我相信可以使用方法合同来告诉IntelliJ,该方法不能返回null。我尝试使用@Contract("null -> fail")
装饰器,但警告并没有消失。
有人使用方法合同或类似方法,而不是从外部进行空检查,对如何使警告在方法本身中消失没有任何想法吗?
答案 0 :(得分:4)
System.exit(Codes.FAIL);
不是Java中的终止语句(例如return
或throw
)。
在某些有线情况下,您可以想象,可以覆盖exit
方法(或模拟它),而不会终止应用程序。然后将返回此null
。
对于简洁且健壮的应用程序,如果要终止该应用程序,则引发将传播的异常。特别是,如果要因为终止应用程序,则会发生错误(无效路径)。让应用程序自行死亡将更加实用。为什么必须致电System.exit();
?
PS:您还可以看到@Stephen C或@ user31601的答案,这肯定会解决方法返回null
的问题(因为它使用流控制语句-throw
),但是我不建议那种选择。我认为,最好设计一个更好的结构,即简洁的结构,不要让这种情况发生-相反,允许它发生,然后抛出{{1} }。
PS2:您也可以像建议@yole一样添加AssertionException
,但是同样-代替反应来处理不应该发生的事情-只是不要不要让它发生。并抛出(例如)@NotNull
。
我的建议:
throw new InvalidPathException();
答案 1 :(得分:1)
IntelliJ IDEA无法识别此函数无法返回
null
。
IntelliJ仅遵循标准Java可达性规则。他们说return null;
语句是可到达的。
有人对如何使警告在方法本身中消失没有任何想法。
您可以将以下语句替换为:
throw new AssertionError("unreachable statement executed");
或者更好的是,将其放在System.exit(...)
调用之后。
任何不受检查的异常都可以,但是在我看来AssertionError
是发生完全错误的最有力的指示。请注意,您需要显式引发异常。使用assert
不足以避免需要return
...,因为可以关闭断言检查。
从未执行的throw
语句的运行时开销最小为零。
另一个想法是返回一个虚拟的非null值。在此示例中,将使用空字符串。
将方法注释为@NotNull
的问题是静态代码分析器(使用与IntelliJ相同的不完全逻辑)可能会标记方法确实返回null
。如果您可以抑制该警告,则还有可能某些框架可能会插入null
的运行时检查... 1)没有用,2)可能无法优化。
不幸的是,没有一种实用的方法可以使用注释“此语句永不返回”的注释来标记System.exit
。为什么?因为它是一种标准方法,所以您不能更改它,而...除非对类库进行黑客攻击并(可能)破坏其可移植性。
(我认为)解决该问题的最佳办法是开发补丁并将其提交给Intellij维护人员。 “了解” System.exit
特殊行为的人。
最后,对于库方法来说,以您示例中的方法调用System.exit
通常是个坏主意。更好的方法是在应用程序的控制线程上引发一个自定义异常,该异常会在调用堆栈的底部/附近捕获。这样,您可以将所有用于控制(受控)应用程序出口的代码和逻辑都放在同一位置。
辅助方法不应决定整个应用程序的“命运”。
答案 2 :(得分:0)
为什么不只是在catch块的末尾添加终止语句?它永远不会实现,因此它所要做的就是帮助编译器推断出最终的return语句是不必要的。
例如:
String loadSuperImportantFile() {
try {
// ... file loading code ...
assert fileContent != null;
return fileContent;
} catch(IOException ex) {
System.err.println("Failed to load super important file. Please check path.");
System.exit(Codes.FAIL); // terminate the program
throw new AssertionError("Unreachable");
}
}
答案 3 :(得分:0)
只需将方法注释为@NotNull
。您尝试应用的@Contract
注释表示,如果您将null
作为参数传递给该方法,则该方法将失败,这是没有意义的,因为它没有任何参数。
答案 4 :(得分:0)
您还可以返回Optional<String>
而不是String
。
这样,您可以避免返回null
并返回Optional.empty()
,以避免空检查和可能的NullPointerException
。
请参阅:https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html