code

연결할 수없는 코드가 잘 작동합니다.-어떻게?

codestyles 2020. 12. 24. 23:46
반응형

연결할 수없는 코드가 잘 작동합니다.-어떻게?


내가 작성한 다음 코드는 "I am unreachable"return.

그러나 그것은 절대적으로 잘 컴파일됩니다.

또한 JLS : Unreachable Statements에서 컴파일해서는 안됩니다.

사양에서 14.21 Unreachable Statements :

다음 두 가지 모두에 해당하면 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??!!!");
    }
}

누군가가이 행동을 이해하도록 도울 수 있습니까?


다음은 JLS 14.21 의 관련 인용문입니다 .

  • 스위치 블록이 아닌 빈 블록은 도달 가능한 경우 정상적으로 완료 할 수 있습니다.

    스위치 블록이 아닌 비어 있지 않은 블록은 마지막 명령문이 정상적으로 완료 될 수있는 경우 정상적으로 완료 될 수 있습니다.

    스위치 블록이 아닌 비어 있지 않은 블록의 첫 번째 명령문은 블록에 도달 할 수있는 경우 도달 할 수 있습니다.

    스위치 블록이 아닌 비어 있지 않은 블록의 다른 모든 명령문 S는 S 앞의 명령문이 정상적으로 완료 될 수있는 경우 도달 할 수 있습니다 .

그래서 당신의

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

다음 따옴표로 이어지는 try 문이 정상적으로 완료 될 수있는 경우 (즉, "만약"을 의미) 문에 도달 할 수 있습니다.

  • 다음 두 가지가 모두 참인 경우 try 문은 정상적으로 완료 될 수 있습니다 .

    • 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 블록이 해당 예외를 throw하지 않는다고 불평합니다. catch블록 도달).

따라서 catch (Exception e)정상적으로 완료 할 수 있는 블록이 있으므로 컴파일러는이 catch 블록에 도달 할 수 있다고 가정하므로 try블록이 정상적으로 완료 될 수없는 경우에도 전체 try 문이 정상적으로 완료 될 수 있습니다.

finally 블록이있는 경우 finally블록도 실행되므로 정상적으로 완료 할 수 있어야합니다 . 따라서 정상적으로 완료 할 수 없으면 전체 try 문이 정상적으로 완료 될 수 없습니다.


당신은 시도에 복귀했습니다.

예외가 있고 직접 잡으러 가면 어떨까요? 따라서 컴파일러 측면에서 도달 할 수 없으며 성공적으로 컴파일됩니다.

캐치에서도 리턴을 받으면 컴파일이 실패합니다.

또한 JLS 14.21에 따라 :

A reachable break statement exits a statement if, within the break target, either there are no try statements whose try blocks contain the break statement, or there are try statements whose try blocks contain the break statement and all finally clauses of those try statements can complete normally.

See output below when you have return in both try and 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??!!!");
|          ^------------------------------------------^

Similar will be the case when you have return in your finally statement and compilation will fail.

A statement post try will be considered as reachable if :

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

Trying to give a more simplified reason for the problem, the code is reachable, in case an exception occurs in the try block. In that case, the control further goes to catch block and then the finally block. After finally block, the particular statement will be executed.

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

That means, there are 2 case, hence 2 flows:

  1. line 1 -> line 3 -> return (In case there is no exception)
  2. line 1 (exception occurs) -> line 2 -> line 3 -> line 4 (In case try gets an exception)

The line will become unreachable, only if we do not leave any possibility in which the control goes there. There are 2 ways for that:

  1. return from catch block
  2. return from finally block.

In both the cases, the control can never flow to that line.

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    

I hope now it gives a clear picture of the actual reason of the issue.


When you look at "unreachable statements" in a Java program, what counts is what the definition in the language says, not what a clever compiler could find out.

According to the Java Language, the last println is not an unreachable statement. Even though by looking at the code it is easy (for a clever human) to figure out that it can never be executed.

A programming language needs to rely on fixed rules that are easy for the compiler to follow exactly. A compiler cannot rely on cleverness, because different compilers would have different amounts of cleverness, so if they didn't follow the simple, fixed rules, then some compilers would find the statement unreachable, and some wouldn't.

ReferenceURL : https://stackoverflow.com/questions/51511249/unreachable-code-working-fine-how

반응형