Why does Java have an “unreachable statement” comp

2019-01-01 16:18发布

I often find when debugging a program it is convenient, (although arguably bad practice) to insert a return statement inside a block of code. I might try something like this in 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");
        }
}

of course, this would yield the compiler error.

Test.java:7: unreachable statement

I could understand why a warning might be justified as having unused code is bad practice. But I don't understand why this needs to generate an error.

Is this just Java trying to be a Nanny, or is there a good reason to make this a compiler error?

8条回答
时光乱了年华
2楼-- · 2019-01-01 16:42

While I think this compiler error is a good thing, there is a way you can work around it. Use a condition you know will be true:

public void myMethod(){

    someCodeHere();

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

    moreCodeHere();

}

The compiler is not smart enough to complain about that.

查看更多
谁念西风独自凉
3楼-- · 2019-01-01 16:46

I only just noticed this question, and wanted to add my $.02 to this.

In case of Java, this is not actually an option. The "unreachable code" error doesn't come from the fact that JVM developers thought to protect developers from anything, or be extra vigilant, but from the requirements of the JVM specification.

Both Java compiler, and JVM, use what is called "stack maps" - a definite information about all of the items on the stack, as allocated for the current method. The type of each and every slot of the stack must be known, so that a JVM instruction doesn't mistreat item of one type for another type. This is mostly important for preventing having a numeric value ever being used as a pointer. It's possible, using Java assembly, to try to push/store a number, but then pop/load an object reference. However, JVM will reject this code during class validation,- that is when stack maps are being created and tested for consistency.

To verify the stack maps, the VM has to walk through all the code paths that exist in a method, and make sure that no matter which code path will ever be executed, the stack data for every instruction agrees with what any previous code has pushed/stored in the stack. So, in simple case of:

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

at line 3, JVM will check that both branches of 'if' have only stored into a (which is just local var#0) something that is compatible with Object (since that's how code from line 3 and on will treat local var#0).

When compiler gets to an unreachable code, it doesn't quite know what state the stack might be at that point, so it can't verify its state. It can't quite compile the code anymore at that point, as it can't keep track of local variables either, so instead of leaving this ambiguity in the class file, it produces a fatal error.

Of course a simple condition like if (1<2) will fool it, but it's not really fooling - it's giving it a potential branch that can lead to the code, and at least both the compiler and the VM can determine, how the stack items can be used from there on.

P.S. I don't know what .NET does in this case, but I believe it will fail compilation as well. This normally will not be a problem for any machine code compilers (C, C++, Obj-C, etc.)

查看更多
登录 后发表回答