Несколько операторов возврата без ошибки компилятора
это был вопрос для интервью:
public class Demo {
public static void main(String[] args) {
System.out.println(foo());
}
static String foo() {
try {
return "try ...";
} catch (Exception e) {
return "catch ...";
} finally {
return "finally ..."; //got as result
}
}
}
мой вопрос почему нет ошибки времени компиляции. Когда у меня есть оператор return в моем finally блок, он обязательно вернется из finally вместо try и catch блок. Я попытался скомпилировать этот код с помощью -Xlint опция, она дает предупреждение как.
warning: [finally] finally clause cannot complete normally
8 ответов:
это не дает ошибку компиляции, потому что это разрешено спецификацией языка Java. Однако он дает предупреждающее сообщение, потому что в том числе
returnзаявление вfinallyблок-это обычно плохая идея.в вашем примере происходит следующее. Элемент
returnзаявление вtryблок выполняется. Тем не менее,finallyблок всегда должен быть выполнен, поэтому он выполняется послеcatchблок заканчивается. Элементreturnзаявление происходящих там перезаписывает результат предыдущегоreturnзаявление, и поэтому метод возвращает второй результат.аналогично a
finallyблок обычно не должен вызывать исключение. Вот почему в предупреждении говорится, чтоfinallyблок должен завершаться нормально, то есть безreturnили бросать исключение.
это описано в спецификации языка Java:
резкое завершение a
finallyпредложение может нарушить передачу контроль инициируемыхreturnзаявление.если исполнение
tryблок завершается нормально, затемfinallyблок выполняется, и тогда есть выбор:
- если элемент
finallyблок завершается нормально, тоtryоператор обычно завершается.- если
finallyблок завершается резко по причине S, тоtryоператор завершается резко по причине С.если исполнение
tryблок завершается резко по любой другой причине R, тогдаfinallyблок выполняется, и тогда есть выбор:
- если
finallyблок завершается нормально, тоtryоператор завершается резко по причине Р.- если
finallyблок завершается резко по причине S, тоtryоператор завершается резко по причине S (и причина R отбрасывается).
нет ошибки времени компиляции, так как только 1 и ровно 1 из
returnоператор фактически вернет элемент управления обратно в вызывающий код.как объяснил @Hoopje,
returnвнутриtryилиcatchбудет выполняться первым, их соответствующий оператор возврата также будет выполняться. Но непосредственно перед возвратом элемента управления обратно в вызывающий код, он будет выполнятьfinallyблок. Так вот, этоblockиreturns что-то, так что это возвращение переопределяет предыдущее.
это по существу то же самое, что и это:
public boolean someMethod(){ if(1 == 1){ return true; } return false; }это не даст ошибку компиляции, хотя это даст предупреждение. Компилятор будет выдавать ошибку только тогда, когда есть шанс нет выполняется оператор return.
Гениальный Вопрос.. Согласно моим знаниям, оператор возврата блока try and catch передается в finally, если вы добавили finally block в свой код. Вот как это работает.
в этом случае все строки кода выполняются и вы можете попробовать выполнить отладку. Все три блока я попробовал ниже кода.
public class Main { public static void main(String[] args) { System.out.println(foo()); } static String foo() { try { throw new Exception(); } catch (Exception e) { return "catch ..."; } finally { return "finally ..."; //got as result } } }вы можете получить идею из ссылки ниже. несколько возвратов: какой из них устанавливает окончательное возвращаемое значение?
ваш код работает хорошо, потому что есть только один оператор return в try, catch и finally. Ошибка компиляции произойдет, если вы попытаетесь написать два оператора return внутри одного из блоков try, catch или finally, говоря, что есть недостижимый оператор return.
(для краткого ответа-прочитайте полужирные и курсивные части ответ)
поток выполнения согласно Java 8 docs. Он предоставляет вам подробную информацию. Вы можете сделать вывод о выполнении операторов return на основе следующего.
оператор try с блоком finally выполняется путем первого выполнения блока try.
тогда есть выбор:
• Если выполнение блока try завершается нормально, то блок finally есть выполнили, и тогда есть выбор:
– Если блок finally завершается нормально, то оператор try завершается обычно.
– Если блок finally завершается внезапно по причине S, то оператор try завершается резко по причине С.
• Если выполнение блока try завершается внезапно из-за броска значения V, тогда есть выбор:
- Если тип времени выполнения V является назначением, совместимым с уловимым исключение класс любого предложения catch оператора try, затем первый (самый левый) такой выбрано предложение catch. Значение V присваивается параметру выбранное предложение catch, и блок этого предложения catch выполняется.
тогда есть выбор:
" Если блок catch завершается нормально, то выполняется блок finally. Тогда есть выбор:
" Если блок finally завершается нормально, то оператор try завершает обычно.
" Если блок finally завершается внезапно по какой-либо причине, то попробуйте оператор завершается резко по той же причине.
"Если блок catch завершается внезапно по причине R, то блок finally выполняемый. Тогда есть выбор:
" Если блок finally завершается нормально, то оператор try завершается резко по причине Р.
"Если блок finally завершается резко по причине S, то попробуйте оператор завершается резко по причине S (и причина R отбрасывается).
- Если тип времени выполнения V не является назначением, совместимым с уловимым класс исключения любого предложения catch оператора try, затем finally блок выполнен.
тогда есть выбор:
" Если блок finally завершается нормально, то оператор try завершается резко из-за броска значения В.
" Если блок finally завершается внезапно по причине S, то оператор try завершается резко по причине S (и бросок значения V отбрасывается и забытый.)
• Если выполнение блока try завершается внезапно по любой другой причине R, то finally блок выполняется, и тогда есть выбор:
– Если блок finally завершается нормально, то оператор try завершается резко по причине Р.
– Если finally блок завершается резко по причине S, затем оператор try завершается резко по причине S (и причина R отбрасывается).
объяснение понятно в этой ссылке- документация
попробуй:
он будет печатать: 1, 2, 3 и деление на ноль исключение
public class Demo { public static void main(String[] args) { System.out.println(foo()); } public static String print(int a){ System.out.println(a); return String.valueOf(a/0); } static String foo() { try { return print(1); } catch (Exception e) { return print(2); } finally { return print(3); } } }
Comments