The variable message is effectively final. Quoting from language reference
If a variable is effectively final, adding the final modifier to its
declaration will not introduce any compile-time errors.
Hence, because message reference is not changed anywhere within you inner class, the compiler treats it as effectively final.
This would have thrown error:
new Runnable() {
@Override
public void run() {
message = "hey";
System.out.println(message);
}
}.run();
The reason, java7 compiler throws error is because of a spec change for lambdas.
Any local variable, formal parameter, or exception parameter used but
not Any local variable, formal parameter, or exception parameter used
but not declared in a lambda expression must either be declared final
or be effectively final (§4.12.4), or a compile-time error occurs
where the use is attempted.
Anonymous Inner classes and lambdas share the same rules.