문제

Does anyone know why:

public void foo()
{
    System.out.println("Hello");
    return;
    System.out.println("World!");
}

Would be reported as an "unreachable error" under Eclipse, but

public void foo()
{
    System.out.println("Hello");
    if(true) return;
    System.out.println("World!");
}

Only triggers a "Dead code" warning?

The only explanation I can think of is that the Java compiler only flags the first, and that some extra analysis in Eclipse figures out the second. However, if that is the case, why can't the Java compiler figure out this case at compile time?

Wouldn't the Java compiler figure out at compile time that the if(true) has no effect, thus yielding bytecode that is essentially identical? At what point is the reachable code analysis applied?

I guess a more general way to think of this question is: "when is the reachable code analysis applied"? In the transformation of the second Java code fragment to the final bytecode, I am sure that at some point the "if(true)" runtime equivalent is removed, and the representations of the two programs become identical. Wouldn't the Java compiler then apply its reachable code analysis again?

도움이 되었습니까?

해결책

The first does not compile (you got an error), the second compiles (you just got a warning). That's the difference.

As to why Eclipse detects dead code, well, that's just the convenience of an integrated development tool with a built-in compiler which can be finetuned more as opposed to JDK to detect this kind of code.

Update: the JDK actually eliminates dead code.

public class Test {
    public void foo() {
        System.out.println("foo");
        if(true)return;
        System.out.println("foo");
    }
    public void bar() {
        System.out.println("bar");
        if(false)return;
        System.out.println("bar");
    }
}

javap -c says:

public class Test extends java.lang.Object{
public Test();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."":()V
   4:   return

public void foo();
  Code:
   0:   getstatic       #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   3:   ldc             #3; //String foo
   5:   invokevirtual   #4; //Method java/io/PrintStream.println:(Ljava/lang/StrV
   8:   return

public void bar();
  Code:
   0:   getstatic       #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   3:   ldc             #5; //String bar
   5:   invokevirtual   #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   8:   getstatic       #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   11:  ldc             #5; //String bar
   13:  invokevirtual   #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   16:  return

}

As to why it (Sun) doesn't give a warning about that, I have no idea :) At least the JDK compiler has actually DCE (Dead Code Elimination) builtin.

다른 팁

Unreachable code is an error according to the Java Language Spec.

To quote from the JLS:

The idea is that there must be some possible execution path from the beginning of the constructor, method, instance initializer or static initializer that contains the statement to the statement itself. The analysis takes into account the structure of statements. Except for the special treatment of while, do, and for statements whose condition expression has the constant value true, the values of expressions are not taken into account in the flow analysis.

What that means, is that the if block is not taken into account, since if you go through one of the paths of the if statement, you could reach final print statement. If you changed your code to be:

public void foo() {
    System.out.println("Hello");
    if (true)
        return;
    else
        return;
    System.out.println("World!");
}

then suddenly it wouldn't compile anymore, since there is no path through the if statement that would allow the last line to be reached.

That is, a Java compliant compiler is not allowed to compile your first code fragment. To further quote the JLS:

As an example, the following statement results in a compile-time error:

while (false) { x=3; }

because the statement x=3; is not reachable; but the superficially similar case:

if (false) { x=3; }

does not result in a compile-time error. An optimizing compiler may realize that the statement x=3; will never be executed and may choose to omit the code for that statement from the generated class file, but the statement x=3; is not regarded as "unreachable" in the technical sense specified here.

The second warning that Eclipse gives, about dead code, is a warning generated by the compiler, that is not "unreachable", according to the JLS, but in practice is. This is an additional lint style check that Eclipse provides. This is entirely optional, and, by using the Eclipse configuration, can be disabled, or turned into a compiler error instead of a warning.

This second block is a "code smell", if (false) blocks are normally put in to disable code for debugging purposes, having it left behind is typically accidental, and hence the warning.

In fact, Eclipse does even more advanced tests to determine the possible values for an if statement to determine whether or not it is possible to take both paths. For example, Eclipse would also complain about dead code in the following method:

public void foo() {
    System.out.println("Hello");
    boolean bool = Random.nextBoolean();
    if (bool)
        return;
    if (bool || Random.nextBoolean())
      System.out.println("World!");
}

It will generate an unreachable code for the second if statement, since it can reason that bool must only be false at this point in the code. In such a short code fragment it is obvious that the two if statements are testing the same thing, however if there are 10-15 code lines in the middle it might not be so obvious anymore.

So in summary, the difference between the two: one is forbidden by the JLS, and one is not, but is detected by Eclipse as a service to the programmer.

This is to allow a kind of conditionally compilation.
It is not an error with if, but the compiler will flag an error for while, do-while and for.
This is OK:

if (true) return;    // or false
System.out.println("doing something");

This are errors

while (true) {
}
System.out.println("unreachable");

while (false) {
    System.out.println("unreachable");
}

do {
} while (true);
System.out.println("unreachable");

for(;;) {
}
System.out.println("unreachable");

It is explained at the end of JLS 14.21: Unreachable Statements:

The rationale for this differing treatment is to allow programmers to define "flag variables" such as:

 static final boolean DEBUG = false;

and then write code such as:

   if (DEBUG) { x=3; }

The idea is that it should be possible to change the value of DEBUG from false to true or from true to false and then compile the code correctly with no other changes to the program text.

목록 웹 파트에 연결할 수있는 필터 웹 파트를 사용하여 열 필터로 사용할 수 있습니다.텍스트 필터 웹 파트를 먼저 사용 하여이 개념을 사용하여 모든 웹 파트 연결이 있는지 파악하십시오.

웹 파트를 필터링하려면

  • 편집 페이지

  • 웹 파트 추가

  • 필터 카테고리

  • 텍스트 필터를 선택

    상담 링크 연결 구성

워크 플로우의 승인 부분에 대한 전체 태스크 프로세스에서 모든 내 알림 논리를 모두 이동하여 올바르게 작동 할 수있었습니다.의미있는 영역은 "이 작업 프로세스의 완료 조건을 변경 ", " 단일 작업 "또는 "의 동작을 변경할 수 있습니다.전체 작업 프로세스 ".

승인 시작이 포함 된 단계에서 자신의 단계로 이동 한 후에는 키의 절반이었습니다.그런 다음 그룹을 다시 시작할 수있었습니다.나는 그것을 Semi-Colon으로 구분 된 로그인 이름으로 되돌아 가기 위해 그것을 전환했습니다.

그 후에 이메일이 벌금을 통과하기 시작했습니다.나는 그룹 변수를 당기는 논리가 워크 플로우의 해당 부분에 있으면 SharePoint의 투쟁이 그룹을 가져 오는 것을 확고히 믿습니다.이메일 주소 대신 로그인 이름을 사용하거나 문자열로 로그인 이름을 사용해야했지만 지금은 작동하지만 이제는 작동합니다.

감사합니다.

The difference is in the semantics between run-time and compile-time. In your second example, the code compiles to an if-else branch in the bytecode, and eclipse is simply smart enough to tell you that the else portion will never be reached in runtime. Eclipse only warns you, because it is still legal code.

In your first example, it is an error because the code is illegal by the definition of java. The compiler doesn't allow you to create byte code with unreachable statements.

I made some try on eclipse and think there are 3 kinds of dead code handling of JDK: 1) no warn, 2) warn and 3) error.

For a typical "IF" conditional compilataion code, JDK detect this and didnt report it as dead code. For a dead code that is caused by a constant boolean flag, JDK detect this and report it at warning level. For dead code that is cause by the program's control flow, JDK detect it as error.

Below is my try:

    public class Setting {
        public static final boolean FianlDebugFlag = false;
    }


    class B {
    .....

    // no warn, it is typical "IF" conditional compilataion code
    if(Setting.FianlDebugFlag) 
        System.out.println("am i dead?");   
    if(false) 
        System.out.println("am i dead?");   


    // warn, as the dead code is caused by a constant boolean flag
    if(ret!=null && Setting.FianlDebugFlag) 
        System.out.println("am i dead?");   

    if(Setting.FinalDebug)                  
        return null;                                                            
    System.out.println("am i dea?");        

    // error, as the dead code is due to the program's control flow
    return null;
    System.out.println("am i dead");        
    }

SQL을 다시 시작한 후 IIS는 도움이되지 않는 것처럼 보이지 않습니다.그래서 나는 상자와 빙고를 다시 시작했다.
PowerShell은 내 템플릿을 찾고 있습니다.

SharePoint Love!

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top