[java] Java에 “도달 할 수없는 문”컴파일러 오류가있는 이유는 무엇입니까?

나는 종종 프로그램을 디버깅 할 때 코드 블록 안에 return 문을 삽입하는 것이 편리하다는 것을 알게됩니다. Java에서 이와 같은 것을 시도해 볼 수 있습니다 ….

class Test {
        public static void main(String args[]) {
                System.out.println("hello world");
                return;
                System.out.println("i think this line might cause a problem");
        }
}

물론 이것은 컴파일러 오류를 생성합니다.

Test.java:7 : 연결할 수없는 문

사용하지 않는 코드가 나쁜 습관으로 경고가 정당화되는 이유를 이해할 수 있습니다. 그러나 왜 이것이 오류를 생성 해야하는지 이해하지 못합니다.

이것은 단지 Java가 Nanny가 되려고하는 것입니까, 아니면 이것을 컴파일러 오류로 만드는 좋은 이유가 있습니까?



답변

도달 할 수없는 코드는 컴파일러에게 의미가 없기 때문입니다. 사람들에게 의미있는 코드를 만드는 것이 컴파일러에게 의미있는 코드를 만드는 것보다 가장 중요하고 어렵지만 컴파일러는 코드의 필수 소비자입니다. 자바 설계자들은 컴파일러에게 의미가없는 코드는 오류라는 관점을 가지고 있습니다. 접근 할 수없는 코드가 있으면 수정해야 할 실수를 저질렀다는 입장입니다.

여기에 비슷한 질문이 있습니다. 연결할 수없는 코드 : 오류 또는 경고? 저자는 “개인적으로는 이것이 오류라고 생각합니다. 프로그래머가 코드를 작성하는 경우 항상 일부 시나리오에서 실제로 실행할 의도가 있어야합니다.”라고 말합니다. 분명히 Java의 언어 디자이너는 동의합니다.

도달 할 수없는 코드가 컴파일을 방해해야하는지 여부는 합의가 이루어지지 않는 문제입니다. 그러나 이것이 자바 디자이너가 한 이유입니다.


댓글에있는 많은 사람들은 자바가 컴파일을 방해하지 않는 도달 할 수없는 코드 클래스가 많다고 지적합니다. Gödel의 결과를 올바르게 이해하면 어떤 컴파일러도 도달 할 수없는 코드의 모든 클래스를 포착 할 수 없습니다.

단위 테스트는 모든 단일 버그를 포착 할 수 없습니다. 우리는 이것을 그들의 가치에 대한 논쟁으로 사용하지 않습니다. 마찬가지로 컴파일러는 문제가있는 모든 코드를 잡을 수는 없지만 가능한 경우 잘못된 코드의 컴파일을 방지하는 것이 여전히 중요합니다.

Java 언어 디자이너는 연결할 수없는 코드를 오류로 간주합니다. 따라서 가능한 경우 컴파일을 방지하는 것이 합리적입니다.


(당신이 반대하기 전에 : 질문은 Java에 도달 할 수없는 명령문 컴파일러 오류가 있어야하는지 여부가 아닙니다. 문제는 Java에 도달 할 수없는 명령문 컴파일러 오류가있는 이유입니다. Java가 잘못된 설계 결정을 내렸다고 생각한다고해서 나를 반대하지 마십시오.)


답변

도달 할 수없는 명령문이 허용되지 않아야하는 명확한 이유는 없습니다. 다른 언어는 문제없이 그들을 허용합니다. 특정 요구에 대해 다음은 일반적인 트릭입니다.

if (true) return;

무의미 ​​해 보이며, 코드를 읽는 사람은 나머지 문장을 접근 할 수없는 상태로 두는 부주의 한 실수가 아니라 의도적으로 수행 된 것이 틀림 없다고 추측 할 것입니다.

Java는 “조건부 컴파일”을 약간 지원합니다.

http://java.sun.com/docs/books/jls/third_edition/html/statements.html#14.21

if (false) { x=3; }

컴파일 타임 오류가 발생하지 않습니다. 최적화 컴파일러는 x = 3; 실행되지 않으며 생성 된 클래스 파일에서 해당 명령문에 대한 코드를 생략하도록 선택할 수 있지만 x = 3; 여기에 지정된 기술적 의미에서 “도달 할 수없는”것으로 간주되지 않습니다.

이 다른 처리의 근거는 프로그래머가 다음과 같은 “플래그 변수”를 정의 할 수 있도록하는 것입니다.

static final boolean DEBUG = false;

그런 다음 다음과 같은 코드를 작성하십시오.

if (DEBUG) { x=3; }

아이디어는 DEBUG의 값을 false에서 true로 또는 true에서 false로 변경 한 다음 프로그램 텍스트에 대한 다른 변경없이 코드를 올바르게 컴파일 할 수 있어야한다는 것입니다.


답변

유모입니다. 나는 .Net이 이것을 맞았다 고 느낍니다. 도달 할 수없는 코드에 대한 경고를 일으키지 만 오류는 아닙니다. 경고를받는 것은 좋지만 컴파일을 막을 이유는 없습니다 (특히 코드를 우회하기 위해 리턴을 던지는 것이 좋은 디버깅 세션 동안).


답변

나는 방금이 질문을 알아 차렸고 여기에 $ .02를 더하고 싶었습니다.

Java의 경우 이것은 실제로 옵션이 아닙니다. “연결할 수없는 코드”오류는 JVM 개발자가 개발자를 모든 것으로부터 보호하거나 특별히 경계해야한다고 생각한 것이 아니라 JVM 사양의 요구 사항에서 비롯됩니다.

Java 컴파일러와 JVM은 모두 현재 메서드에 할당 된 스택의 모든 항목에 대한 명확한 정보 인 “스택 맵”을 사용합니다. JVM 명령이 한 유형의 항목을 다른 유형으로 잘못 처리하지 않도록 스택의 모든 슬롯 유형을 알아야합니다. 이것은 숫자 값이 포인터로 사용되는 것을 방지하는 데 가장 중요합니다. Java 어셈블리를 사용하여 숫자를 푸시 / 저장 한 다음 객체 참조를 팝 /로드 할 수 있습니다. 그러나 JVM은 클래스 유효성 검사 중에이 코드를 거부합니다. 즉, 스택 맵을 만들고 일관성을 테스트 할 때입니다.

스택 맵을 확인하기 위해 VM은 메서드에있는 모든 코드 경로를 살펴보고 실행될 코드 경로에 관계없이 모든 명령어의 스택 데이터가 이전 코드가 푸시 한 내용과 일치하는지 확인해야합니다. / 스택에 저장됩니다. 따라서 다음과 같은 간단한 경우 :

Object a;
if (something) { a = new Object(); } else { a = new String(); }
System.out.println(a);

3 행에서 JVM은 ‘if’의 두 분기가 Object와 호환되는 항목 (로컬 var # 0 일뿐)에만 저장되었는지 확인합니다 (3 행 이상의 코드가 로컬 var # 0을 처리하는 방식이기 때문에) ).

컴파일러가 도달 할 수없는 코드에 도달하면 해당 지점에서 스택이 어떤 상태인지 알 수 없으므로 상태를 확인할 수 없습니다. 그 시점에서 더 이상 코드를 컴파일 할 수 없습니다. 지역 변수도 추적 할 수 없기 때문에 클래스 파일에이 모호함을 남기는 대신 치명적인 오류가 발생합니다.

물론 이와 같은 간단한 조건 if (1<2)은 속일 수 있지만 실제로는 속이지는 않습니다. 코드로 이어질 수있는 잠재적 분기를 제공하고 적어도 컴파일러와 VM 모두에서 스택 항목을 사용할 수있는 방법을 결정할 수 있습니다. 의 위에.

추신 :이 경우 .NET이 무엇을하는지 모르겠지만 컴파일도 실패 할 것이라고 생각합니다. 이것은 일반적으로 모든 기계 코드 컴파일러 (C, C ++, Obj-C 등)에서 문제가되지 않습니다.


답변

컴파일러의 목표 중 하나는 오류 클래스를 배제하는 것입니다. 도달 할 수없는 코드가 우연히 존재합니다. javac가 컴파일 타임에 해당 오류 클래스를 배제하는 것이 좋습니다.

잘못된 코드를 포착하는 모든 규칙에 대해 누군가는 자신이하는 일을 알고 있기 때문에 컴파일러가이를 받아들이기를 원할 것입니다. 이것이 컴파일러 검사의 불이익이며 균형을 올바르게 잡는 것은 언어 설계의 까다로운 점 중 하나입니다. 가장 엄격한 검사를하더라도 작성할 수있는 프로그램의 수는 무한하기 때문에 그렇게 나쁠 수는 없습니다.


답변

이 컴파일러 오류는 좋은 것이라고 생각하지만 해결할 수있는 방법이 있습니다. 사실이라고 알고있는 조건을 사용하십시오.

public void myMethod(){

    someCodeHere();

    if(1 < 2) return; // compiler isn't smart enough to complain about this

    moreCodeHere();

}

컴파일러는 그것에 대해 불평 할만큼 똑똑하지 않습니다.


답변

필요한 작업을 수행 할 수있는 한 컴파일러가 더 엄격할수록 더 좋다고 불평하는 것은 확실히 좋은 일입니다. 일반적으로 지불해야 할 적은 비용은 코드를 주석 처리하는 것이며, 코드를 컴파일하면 작동한다는 이점이 있습니다. 일반적인 예는 테스트 / 디버깅이 메인 테스트이고 짧은 테스트라는 것을 깨닫기 전까지 사람들이 비명을 지르는 Haskell입니다. 개인적으로 Java에서는 (사실 의도적으로)주의를 기울이지 않는 동안 거의 디버깅을하지 않습니다.