Ответ 1
В байт-коде Java (по крайней мере, с Java 1.6) нет специальной конструкции для блока finally
, поэтому она фактически дублируется много раз. Например, рассмотрим следующий метод:
public static void main(String[] args) {
try {
System.out.println("In try");
if(args.length > 0)
return;
System.out.println("No args");
}
catch(RuntimeException ex) {
System.out.println("In catch");
}
finally {
System.out.println("In finally");
}
}
Этот код эффективно скомпилирован примерно так:
public static void main(String[] args) {
try {
System.out.println("In try");
if(args.length > 0) {
System.out.println("In finally");
return;
}
System.out.println("No args");
}
catch(RuntimeException ex) {
System.out.println("In catch");
System.out.println("In finally");
}
catch(<any exception> t) {
System.out.println("In finally");
throw t;
}
System.out.println("In finally");
}
Это не полностью эквивалентный код, потому что если во время System.out.println("In finally");
(перед возвратом) возникает новое исключение, то оно не будет выхвачено. Однако он показывает грубую идею о том, что блок finally
дублируется здесь четыре раза. Его можно дублировать гораздо чаще, если у вас есть несколько способов выйти из блока try, и особенно если у вас есть вложенные блоки try-finally. Также обратите внимание на добавленный специальный урок <any exception>
. Он появится в байт-коде, даже если вы явно пишете catch(Throwable t)
.
Поскольку инструменты покрытия кода, такие как Emma или JaCoCo, работают на уровне байтового кода, они не знают, что эти четыре "In finally"
printlns на самом деле являются тем же самым выражением в исходном коде. Можно выполнить анализ байт-кода и достаточно точно определить, какие части байт-кода соответствуют единому блоку окончательного блока (я на самом деле написал такой анализатор один раз), но это не очень простая проблема и имеет некоторые нетривиальные оговорки. Вы также должны учитывать, что разные компиляторы (например, javac и ecj) создают несколько разный макет блоков finally. Похоже, что эта работа не была выполнена в популярных инструментах охвата, и они просто рассматривают разные окончательные копии блоков как разные коды.
В вашем конкретном случае кажется, что @bobbel прав: вы не тестировали случай исключенного исключения (этот <any exception>
catch).