Java try with resources中出现死代码警告,但在翻译后的try catch finally中没有
下面的代码使用Java8中引入的构造。occasionalythrow()方法声明抛出一个OccasionalException,资源的close()方法抛出一个CloseException。Eclipse(版本:Neon Release(4.6.0),构建id:20160613-1800)在标有//dead code的行上添加了一条警告,指出分支是死代码。Eclipse隐式地确认标有//alive code的行不是死代码Java try with resources中出现死代码警告,但在翻译后的try catch finally中没有,java,eclipse,try-with-resources,Java,Eclipse,Try With Resources,下面的代码使用Java8中引入的构造。occasionalythrow()方法声明抛出一个OccasionalException,资源的close()方法抛出一个CloseException。Eclipse(版本:Neon Release(4.6.0),构建id:20160613-1800)在标有//dead code的行上添加了一条警告,指出分支是死代码。Eclipse隐式地确认标有//alive code的行不是死代码 Object tryWithResources() throws Occ
Object tryWithResources() throws OccasionalException {
Object value = null;
try (Resource resource = new Resource()) {
occasionallyThrow();
value = new Object();
}
catch (CloseException e) {
if (value == null) {
// alive code
}
else {
// dead code
}
}
return value;
}
我对此感到困惑。如果occasionallyThrow()抛出其OccasionalException,则带有资源的try
-应将其捕获为主要异常,然后尝试关闭资源。如果关闭资源会抛出一个CloseException,那么它将在OccasionalException下被抑制,因此不会有要捕获的CloseException。因此,只有当try中的块成功完成时,才应该有CloseException进行捕获,这意味着value不为空。所以看起来“死代码”实际上是活的,“活代码”实际上是死的。我不确定编译器在这里应该识别什么,但至少,这里的“死代码”不应该被称为死代码
更复杂的是,未使用try with resources表单的翻译表单根本不会标记任何死代码警告。(我相当有信心,我得到了正确的翻译,基于,但我不会完全感到惊讶,如果有错误在这里…)
我是否遗漏了一些东西,使if-else中的任何一个分支在其中一个分支中死亡,而在另一个分支中不死亡
完整代码
下面是完整的代码,其中包含辅助异常类型、资源类和顶级类的定义
public class TestTryWithResources {
/** Exception thrown by Resource's close() method */
@SuppressWarnings("serial")
static class CloseException extends Exception {}
/** AutoCloseable declared to throw a CloseException */
static class Resource implements AutoCloseable {
@Override
public void close() throws CloseException {}
}
/** An occasionally thrown exception */
@SuppressWarnings("serial")
static class OccasionalException extends Exception {}
/** Method declared to throw an occasional exception */
void occasionallyThrow() throws OccasionalException {}
/*
* Method using try-with-resources. Eclipse warns that the
* portion marked with "// dead code" is Dead code.
*/
Object tryWithResources() throws OccasionalException {
Object value = null;
try (Resource resource = new Resource()) {
occasionallyThrow();
value = new Object();
}
catch (CloseException e) {
if (value == null) {
// alive code
}
else {
// dead code
}
}
return value;
}
/*
* Method not using try-with-resources. This is the translation
* of the try-with-resources in tryWithResources, according to
* [14.20.3 try-with-resources][1]. Eclipse does not warn about
* any of the code being Dead code.
*
* [1]: https://docs.oracle.com/javase/specs/jls/se7/html/jls-14.html#jls-14.20.3
*/
Object expandedTry() throws OccasionalException {
Object value = null;
try {
Resource resource = new Resource();
Throwable $primary = null;
try {
occasionallyThrow();
value = new Object();
}
catch (Throwable t) {
$primary = t;
throw t;
}
finally {
if (resource != null) {
if ($primary != null) {
try {
resource.close();
}
catch (Throwable $suppressed) {
$primary.addSuppressed($suppressed);
}
}
else {
resource.close();
}
}
}
}
catch (CloseException e) {
if (value == null) {
// alive
}
else {
// alive
}
}
return value;
}
}
对评论的答复
建议在设置值以更改Eclipse的代码分析后使用资源的解决方法。但这不起作用。使用资源后(例如,通过打印),Luna和Neon中仍然存在死代码警告:
由于某种原因,静态代码分析器认为资源将在try声明之后立即关闭,而根据教程,资源将在语句之后关闭 try with resources语句确保在语句末尾关闭每个资源 因此,例如,如果您在值为(下面的代码)之后更改代码以使用资源,它不会警告您死代码(但是在EclipseLuna上测试) 更新 这是我在设置值后使用resource(在本例中为reader)测试的实际代码
Object val = null;
try (BufferedReader reader = new BufferedReader(new FileReader("C:\\file.txt"))) {
val = new Object();
System.out.println("got here");
reader.readLine();
}
catch(IOException e){
System.out.println("io ex");
if ( val == null){
}
else{
}
}
这并不能回答为什么Eclipse会生成警告,或者是否应该生成警告的问题,但这是一种解决方法,至少暂时消除了警告。您可以调用另一个方法,使用被测试的值以及异常,从该方法测试对象是否为null,然后执行任何需要执行的操作,而不是将条件放入catch块中:
Object tryWithResources() throws OccasionalException {
Object value = null;
try (Resource resource = new Resource()) {
occasionallyThrow();
value = new Object();
System.out.println(resource.toString());
}
catch (CloseException e) {
catchBlock(value, e); // call auxiliary method
}
return value;
}
void catchBlock(Object value, CloseException e) {
if (value == null) {
// then
}
else {
// else
}
}
也许是这样,尽管现在已经5年了……我不确定您是否能够捕获在关闭过程中抛出的异常,该异常是由try使用属于try块的catch块中的资源完成的。如果将CloseException更改为选中异常,会发生什么情况?如果您将捕获的内容另外移动到周围的尝试,会发生什么?@mm759首先回答中间的问题:CloseException是一个选中的异常。通过在这里将其定义为Exception的子类(而不是RuntimeException的子类),我确保了这一点。@mm759对于第一个问题,try with resources with a catch的行为由描述
try ResourceSpecification Block catch Finally
(这是我正在使用的(没有可选的Finally),被翻译为try{try ResourceSpecification Block}catch Finally
。因此,当主体没有引发异常时,您可以捕捉隐式close引发的异常,所以(第二个问题)翻译已经“将捕获移动到周围的try[。]”可能还没有“确认”,但我个人可以确认它仍然发生在Eclipse4.5.2上。特别是标记为“死代码”的代码显然,当测试用例运行时会生成输出。同样,只有Eclipse生成警告-而不是JavaCus在设置值后使用资源并不会消除Eclipse中的死代码警告。我已经更新了问题,以显示警告仍然存在。那么它可能是特定于Eclipse Neon的。我在Eclipse Luna中尝试过它。不,我没有Luna和Eclipse中都出现了ied。警告都出现在这两个版本中。我再次更新了我的问题以显示这两个版本。很有趣。我还尝试了Neon。Neon中也出现了ied。我更新了答案以包含实际代码(我正在尝试使用BufferedReader,因为我没有您的代码)。好的,我想我知道这是什么。readLine()方法还抛出IOException,这可能就是为什么eclipse现在确信可以在设置值之后抛出异常。
Object val = null;
try (BufferedReader reader = new BufferedReader(new FileReader("C:\\file.txt"))) {
val = new Object();
System.out.println("got here");
reader.readLine();
}
catch(IOException e){
System.out.println("io ex");
if ( val == null){
}
else{
}
}
Object tryWithResources() throws OccasionalException {
Object value = null;
try (Resource resource = new Resource()) {
occasionallyThrow();
value = new Object();
System.out.println(resource.toString());
}
catch (CloseException e) {
catchBlock(value, e); // call auxiliary method
}
return value;
}
void catchBlock(Object value, CloseException e) {
if (value == null) {
// then
}
else {
// else
}
}