Недостижимый код работает нормально - как?



из моего понимания следующий код, который я написал, не должен компилироваться как оператор "Я недоступен" после return.



однако, это компиляция абсолютно нормально.



также из JLS:Недостижимых Операторов он не должен компилироваться.




из спецификации, в 14.21 недостижимые утверждения:



оператор try может завершиться нормально, если выполняются оба из следующих условий:




  • блок try может завершиться нормально или любой блок catch может обычно завершаться.


  • Если оператор try имеет блок finally, то блок finally может завершиться нормально.





здесь блок try не может завершиться нормально, но блок catch может так же, как и блок finally, поэтому я запутался здесь



    public class Test1 {
public static void main(String[] args) {
try {
return;

} catch (Exception e) {
System.out.println("catch");

} finally {
System.out.println("finally");
}
System.out.println("I am unreachable??!!!");
}
}


кто-нибудь может помочь мне понять это поведение?

662   4  

4 ответов:

я считаю, что это соответствующие цитаты из JLS 14.21:

  • пустой блок, который не является блоком коммутатора, может завершиться нормально, если он доступен.

    непустой блок, который не является блоком коммутатора, может нормально завершиться, если последний оператор в нем может завершиться нормально.

    первый оператор в непустом блоке, который не является блоком коммутатора, доступен, если блок достижимый.

    любой другой оператор S в непустом блоке, который не является блоком коммутатора, достижим, если оператор, предшествующий S, может завершиться нормально.

так что ваши

System.out.println("I am unreachable??!!!");

оператор достижим iff (что означает "если и только если") оператор try может завершиться нормально, что приводит к следующей цитате:

  • оператор try может завершиться нормально iff оба из следующих условий:

    • блок try может завершиться нормально или любой блок catch может обычно завершаться.

    • если оператор try имеет блок finally, то блок finally может завершиться нормально.

поскольку catch блок может завершить нормально и у вас finally блок, который может завершить нормально,try оператор может обычно завершаться. Отсюда и System.out.println("I am unreachable??!!!"); оператор после него считается достижимым, независимо от return; инструкция try заблокировать.

Примечание or на

блок try может завершиться нормально или любой блок catch может обычно завершаться.

для этого требуется либо try блок или по крайней мере один из catch блоки для завершения нормально. Это не требует как try и блок catch блок обычно завершается.

наконец, логика этого поведения:

компилятор не должен анализировать, может ли блок try или не может бросить Exception. Причина в том, что Exception иерархия классов включает как проверенные, так и непроверенные исключения, и непроверенные исключения не объявляются в throws предложения (если вы заменили Exception С некоторые проверенные исключения, такие как IOException, компилятор будет жаловаться, что ваш блок try никогда не бросает исключение, которое сделало бы catch блок недоступен).

поэтому, так как у вас есть catch (Exception e) блок, который может завершиться нормально, компилятор предполагает, что этот блок catch он достижим, и поэтому весь оператор try может завершиться нормально, даже если try блок не может завершиться нормально.

блок finally, если он присутствует, должен также быть в состоянии завершить нормально, так как finally блок также выполняется, поэтому, если он не может завершить нормально, весь оператор try не может завершить нормально.

вы должны вернуться в попробовать.

Что делать, если есть исключение, и он непосредственно идет, чтобы поймать. Следовательно, он не является недостижимым с точки зрения компилятора и успешно компилируется.

компиляция не удастся, если вы будете иметь возврат в catch, а также

кроме того, согласно JLS 14.21:

оператор достижимого разрыва выходит из оператора, если в пределах разрыва target, либо нет операторов try, чьи блоки try содержат оператор break, или есть операторы try, чьи блоки try содержат оператор break и все предложения finally тех, кто пытается заявления могут завершаться нормально.

см выход ниже, когда у вас есть возврат в обоих try и catch:

jshell>  public class Test1 {
   ...>     public static void main(String[] args) {
   ...>         try {
   ...>             return;
   ...>
   ...>         } catch (Exception e) {
   ...>             return;
   ...>
   ...>         }
   ...>
   ...>         System.out.println("I am unreachable??!!!");
   ...>     }
   ...> }
|  Error:
|  unreachable statement
|          System.out.println("I am unreachable??!!!");
|          ^------------------------------------------^

подобным будет случай, когда у вас есть return в вашем конечном заявлении, и компиляция завершится неудачей.

оператор post try будет считаться доступным, если:

1) Try has a return statement with catch and finally not having return statement
2) Try does not have a return statement with catch having or not having return statement and finally not having return statement
3) Try, catch and finally not having return statement

пытаясь дать более упрощенную причину проблемы, код доступен, в случае возникновения исключения в блоке try. В этом случае элемент управления далее переходит к блоку catch, а затем к блоку finally. После окончательного блокирования будет выполнен конкретный оператор.

try {
            return;                                 //line 1

        } catch (Exception e) {
            System.out.println("catch");            //line 2

        } finally {
            System.out.println("finally");          //line 3
        }
        System.out.println("I am unreachable??!!"); //line 4

это означает, что есть 2 случая, следовательно, 2 потока:

  1. строка 1 - > строка 3 - > возврат (в случае отсутствия исключения)
  2. строка 1 (исключение происходит) - > строка 2 - > строка 3 - > строка 4 (в случае, если try получает исключение)

линия станет недостижимой, только если мы не оставим никакой возможности, в которой контроль идет туда. Есть 2 способа для этого:

  1. возврат из блока catch
  2. возвращение из блока finally.

в обоих случаях, управление никогда не может течь к этой линии.

try {
            return;                                 //line 1

        } catch (Exception e) {
            System.out.println("catch");            //line 2
            return;                                 //return control
        } finally {
            System.out.println("finally");          //line 3
            return;                                 //or return from here
        }
        System.out.println("I am unreachable??!!"); //line 4    

Я надеюсь, что теперь это дает четкое представление о фактической причине проблемы.

когда вы смотрите на "недостижимые операторы" в программе Java, важно то, что говорит определение на языке, а не то, что может узнать умный компилятор.

согласно языку Java, последний println не является недостижимым оператором. Хотя, глядя на код, легко (для умного человека) понять, что он никогда не может быть выполнен.

язык программирования должен полагаться на фиксированные правила, которым легко следовать компилятору именно так. Компилятор не может полагаться на сообразительность, потому что разные компиляторы будут иметь разную степень сообразительности, поэтому, если они не будут следовать простым, фиксированным правилам, то некоторые компиляторы найдут оператор недостижимым, а некоторые-нет.

Comments

    Ничего не найдено.