I was caught in interesting trap in Eclipse today. It was my mistake in the beginning, however I suppose Eclipse could have better handled this situation.
Look at methods
m1()
and m2()
in following minimalistic example. What's the difference between them?public class StrangeBreakpoint { public static void main(String[] args) { m1(); m2(); } private static void m1() { // line 8 int x = 0; while (true) { // line 10 System.out.println(x++); if (x == 2) break; int dummy = 0; // line 13 } } private static void m2() { // line 17 int x = 0; while (true) { // line 19 System.out.println(x++); if (x == 2) break; } } }
Certainly none in output. But try to enable breakpoints at lines 10 and 19. Method
m1()
runs loop once before stopping at breakpoint, method m2()
never stops at breakpoint at all.I guess the reason of
m1()
's behavior is the additional code after break which results in additional bytecode delimited with jumps. Eclipse debugger treats breakpoint as stopping point on first instruction after break (see instruction offset 20 paired with line 13). In m2()
case, the debugger has no instruction to stop at, so it silently ignores breakpoint.>javap -private -c -l StrangeBreakpoint Compiled from "StrangeBreakpoint.java" public class StrangeBreakpoint extends java.lang.Object{ ... private static void m1(); Code: 0: iconst_0 1: istore_0 2: getstatic #24; //Field java/lang/System.out:Ljava/io/PrintStream; 5: iload_0 6: iinc 0, 1 9: invokevirtual #30; //Method java/io/PrintStream.println:(I)V 12: iload_0 13: iconst_2 14: if_icmpne 20 17: goto 25 20: iconst_0 21: istore_1 22: goto 2 25: return LineNumberTable: line 9: 0 line 11: 2 line 12: 12 line 13: 20 line 10: 22 line 15: 25 ... private static void m2(); Code: 0: iconst_0 1: istore_0 2: getstatic #24; //Field java/lang/System.out:Ljava/io/PrintStream; 5: iload_0 6: iinc 0, 1 9: invokevirtual #30; //Method java/io/PrintStream.println:(I)V 12: iload_0 13: iconst_2 14: if_icmpne 2 17: return LineNumberTable: line 18: 0 line 20: 2 line 21: 12 line 23: 17 ... }
I ran into this issue debugging real application, not noticing first loop run and wondering why the value of x seems different than the one just assigned.
This behaviour was reproduced in Eclipse Juno, JDT 3.7.101.v20120725. Intellij Idea disallowed breakpoint in both cases, which I consider more fair and less surprising.
Moral: If you must use breakpoints at all, be aware of bytecode in the background. Avoid usage in places where semantic gap between high-level language and bytecode is not apparent.