Question 1: Why does the following code compile without having a return statement? public int a() { while(true); }

This is covered by JLS§8.4.7:

If a method is declared to have a return type (§8.4.5), then a compile-time error occurs if the body of the method can complete normally (§14.1). In other words, a method with a return type must return only by using a return statement that provides a value return; the method is not allowed to "drop off the end of its body". See §14.17 for the precise rules about return statements in a method body. It is possible for a method to have a return type and yet contain no return statements. Here is one example: class DizzyDean { int pitch() { throw new RuntimeException("90 mph?!"); } }

Since the compiler knows that the loop will never terminate ( true is always true, of course), it knows the function cannot "return normally" (drop off the end of its body), and thus it's okay that there's no return .

Question 2: On the other hand, why does the following code compile, public int a() { while(0 == 0); } even though the following does not. public int a(int b) { while(b == b); }

In the 0 == 0 case, the compiler knows that the loop will never terminate (that 0 == 0 will always be true). But it doesn't know that for b == b .

Why not?

The compiler understands constant expressions (§15.28). Quoting §15.2 - Forms of Expressions (because oddly this sentence isn't in §15.28):

Some expressions have a value that can be determined at compile time. These are constant expressions (§15.28).

In your b == b example, because there is a variable involved, it isn't a constant expression and isn't specified to be determined at compilation time. We can see that it's always going to be true in this case (although if b were a double , as QBrute pointed out, we could easily be fooled by Double.NaN , which is not == itself), but the JLS only specifies that constant expressions are determined at compile time, it doesn't allow the compiler to try to evaluate non-constant expressions. bayou.io raised a good point for why not: If you start going down the road of trying to determine expressions involving variables at compilation time, where do you stop? b == b is obvious (er, for non- NaN values), but what about a + b == b + a ? Or (a + b) * 2 == a * 2 + b * 2 ? Drawing the line at constants makes sense.