В следующем коде используется try
Конструкция -with-resources появилась в Java 8. Метод occasionallyThrow() объявляется для создания OccasionalException, Resource' s метод close() для создания CloseException. Eclipse (версия: Neon Release (4.6.0), идентификатор сборки: 20160613-1800) добавляет в строку, отмеченную // мертвый код, предупреждение о том, что ветка является мертвым кодом. Неявно Eclipse подтверждает, что строка, отмеченная // действующим кодом, не мертвый код.
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 не будет перехватываться. Таким образом, CloseException должно быть перехвачено только тогда, когда блок внутри try успешно завершен, что означает, что value не равно нулю. Таким образом, кажется, что «мертвый код» на самом деле жив, а «живой код» на самом деле мертв. Я не уверен, что компилятор на самом деле должен распознать здесь, но, по крайней мере, кажется, что "мертвый код" здесь не следует называть мертвым.
Что делает это более сложным, так это то, что переведенная форма без использования формы try-with-resources вообще не помечается никакими предупреждениями о мертвом коде. (Я вполне уверен, что правильно понял этот перевод, основываясь на 14.20.3.2. Расширенная попытка с ресурсами, но я не удивлюсь, если здесь есть ошибка)
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 (not dead!)
}
else {
// alive
}
}
return value;
}
Я упустил что-то, что сделало бы любую ветвь в if-else мертвой в одном из них, но не в другом?
Полный код
Вот полный код с определениями вспомогательных типов исключений, класса Resource и класса верхнего уровня.
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;
}
}
Ответы на комментарии
В Amin J предложен обходной путь использования ресурса после установки value для изменения анализа кода Eclipse. Однако это не работает. После использования ресурса, например, распечатав его, предупреждение о мертвом коде все еще присутствует как в Luna, так и в Neon:
try ResourceSpecification Block Catches Finally
(это то, что я использую (без необязательного finally), переводится какtry { try ResourceSpecification Block } Catches Finally
. Таким образом, вы можете перехватить исключение, вызванное неявным закрытием, когда тело не выдало исключение, поэтому (второй вопрос) перевод уже переместил [s] улов в окружающий try [.] - person Joshua Taylor   schedule 20.09.2016throws OccasionalException
. Но я пробовал оба способа (всегда бросал и никогда не бросал) с теми же результатами. - person Joshua Taylor   schedule 20.09.2016