Unavailable code error or dead code warning in Java under Eclipse?

Does anyone know why:

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

Reported as an "unreachable error" in Eclipse, but

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

Just triggering a dead code warning?

The only explanation I can think of is that the Java compiler only flag the first, and that some additional analysis in Eclipse shows the second. However, if this is the case, why cannot the Java compiler detect this case at compile time?

Didn't the Java compiler find out at compile time that if (true) has no effect, giving a bytecode that is essentially identical? At what point is reachable code analytic applied?

I think a more general way to think about this question is “when is reachable code analyst applied?” When converting the second fragment of Java code to the final bytecode, I am sure that at some point the equivalent of “if (true)” is deleted, and the representations of the two programs become identical. Wouldn't the Java compiler repeat the analysis of its reachable code?

+51
java eclipse dead-code unreachable-code
Jan 26 '10 at 17:01
source share
8 answers

The first command does not compile (you received an error message), the second compilation (you received a warning). This is the difference.

As to why Eclipse detects dead code, well, it's just the convenience of an integrated development tool with an integrated compiler that can be configured, unlike the JDK, to detect such code.

Update : JDK actually destroys 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 for why he (Sun) does not give a warning about this, I have no idea :) At least the JDK compiler has DCE (Dead Code Elimination).

+33
Jan 26 '10 at 17:04
source share

Inaccessible code is a bug according to the Java Language Spec .

Quote from JLS:

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

What this means is that the if block if not taken into account, because if you go through one of the paths of the if , you can get the final print statement. If you changed your code:

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

then all of a sudden it will no longer compile, because there is no path in the if to reach the last line.

That is, a Java-compatible compiler cannot compile your first piece of code. To optionally specify JLS:

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

 while (false) { x=3; } 

because the statement x = 3; not available; but an outwardly similar case:

 if (false) { x=3; } 

does not result in a compile-time error. The optimizing compiler can understand that the operator x = 3; will never be executed and may omit the code for this statement from the file of the generated class, but statement x = 3; not considered as “unreachable” in the technical sense indicated here.

The second warning that Eclipse gives, about dead code, is a warning generated by the compiler that is not "inaccessible" according to JLS, but in practice it is. This is an additional lint check that Eclipse provides. This is completely optional, and using the Eclipse configuration, you can disable or turn it into a compiler error instead of a warning.

This second block is a "code smell", usually block if (false) blocks to disable the code for debugging purposes, leaving it, as a rule, random and, therefore, a warning.

In fact, Eclipse performs even more complex tests to determine the possible values ​​for the if statement, to determine if both paths can be taken. For example, Eclipse will also complain about dead code in the following way:

 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 unreachable code for the second if statement, since it can justify that bool should only be false at this point in the code. In such a short piece of code, it is obvious that two if statements test the same thing, however, if there are 10-15 lines of code in the middle, this may not be so obvious.

Thus, the difference between the two: one is prohibited by JLS and the other is not, but Eclipse is detected as a service for the programmer.

+25
Jan 26
source share

This means that conditional compilation exists. This is not an error with if , but the compiler will flag an error for while , do-while and for .
This is normal:

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

These are mistakes

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



Explained at the end of JLS 14.21: Unreachable statements :

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

  static final boolean DEBUG = false; 

and then write the code, for example:

  if (DEBUG) { x=3; } 

The idea is that it should be possible to change the DEBUG value from false to true or from true to false, and then compile the code correctly without any changes to the program text.

+13
Jan 26 '10 at 18:15
source share

if (true) slightly more subtle than "unreachable"; because this hard-coded return will always make the following code unreachable, but changing the condition in if can make the next statement available.

The presence of a conditional means that there is a random condition. There are times when there is something more complex than true in parentheses and it is not obvious to the reader that the following code is “cluttered”, but the compiler notices, so it can warn you about this.

Eclipse is mentioned here, and it makes things a little more difficult for the user; but in fact, under Eclipse it is just a (very complex) Java compiler that has a lot of switches for alerts, etc. that Eclipse can turn on and off. In other words, you are not getting enough width of various warnings / errors from javac direct compilation, and you do not have convenient means to enable or disable all of these options. But this is the same deal, only with a lot of calls and whistles.

+2
Jan 26 '10 at 17:05
source share

I think one way to understand that unreachable code is most likely an error, and JLS is trying to protect you from such errors.

Resolution if (true) return; is a good way to get around the JLS restriction if you really want to do this on purpose. If JLS stops this, it will get in the way. In addition, he must also stop:

  public static boolean DEBUG = true; //In some global class somewhere else ... if (DEBUG) return; //in a completely unrelated class. ... 

Because the DEBUG constant is fully aligned and functionally equivalent to a simple set of truth in the if condition. From a JLS perspective, the two cases are very similar.

+2
Jan 26 '10 at 17:47
source share

The difference lies in the semantics between runtime and compilation time. In the second example, the code is compiled into an if-else branch in the bytecode, and eclipse is just smart enough to tell you that the else part will never be reached at runtime. Eclipse warns you only because it is still legal code.

In the first example, this is an error because the code is illegal by java definition. The compiler does not allow the creation of bytecode with unreachable operators.

0
Jan 26 '10 at 17:08
source share

I tried to outshine and thought that there are 3 types of dead JDK code processing: 1) no warning, 2) warning and 3) error.

For typical IF conditional compilation code, the JDK detects this and does not report it as dead code. For dead code caused by a constant Boolean flag, the JDK detects this and reports this at the warning level. For dead code caused by the program control thread, the JDK detects it as an error.

Below is my attempt:

  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 control flow return null; System.out.println("am i dead"); } 
0
Feb 12 '14 at 2:59
source share

If you want to ignore the warning "warning about dead code in Java under Eclipse", do the following inside eclipse *:

  • Click Window-Preferences-Java-Compiler-Errors / Warnings
  • Click "Potential Programming Issues"
  • Select Ignore Dead Code, for example, if (false)
  • Click Apply
  • Click OK

Save and close the eclipse environment. When you open eclipse again, these specific warnings should no longer be displayed.

* For this example, I use the Eclipse IDE for Java Developers - Version: Mars.2 Release (4.5.2)

0
Mar 29 '16 at 11:00
source share



All Articles