STEPPER_REGISTRY.register("java-17/switch", { label: 'Switch statements', panelConfig: { stack: true, heap: false, custom: false, legend: [ { color:'#1d5799', border:'#9dc0e8', label:'Currently running frame' }, { color:'#a0540a', border:'#e8c070', label:'Variable just assigned' }, { color:'#095e40', border:'#90d4b8', label:'Holding a value' }, { color:'#3d3490', border:'#b0a8e0', label:'Reference (object pointer)' }, ] }, scenarios: [ { label: "Colon syntax", lines: [ { code: [['tok-kw','static '],['tok-kw','void '],['tok-meth','main'],['tok-op','(String[] args) {']] }, { code: [['',' '],['tok-type','int '],['tok-op','day = '],['tok-num','2'],['tok-op',';']] }, { code: [['',' '],['tok-kw','switch '],['tok-op','(day) {']] }, { code: [['',' '],['tok-kw','case '],['tok-num','1'],['tok-op',':']] }, { code: [['',' '],['tok-op','System.out.'],['tok-meth','println'],['tok-op','('],['tok-str','"Monday"'],['tok-op',');']] }, { code: [['',' '],['tok-kw','break'],['tok-op',';']] }, { code: [['',' '],['tok-kw','case '],['tok-num','2'],['tok-op',':']] }, { code: [['',' '],['tok-op','System.out.'],['tok-meth','println'],['tok-op','('],['tok-str','"Tuesday"'],['tok-op',');']] }, { code: [['',' '],['tok-kw','break'],['tok-op',';']] }, { code: [['',' '],['tok-kw','default'],['tok-op',':']] }, { code: [['',' '],['tok-op','System.out.'],['tok-meth','println'],['tok-op','('],['tok-str','"Other"'],['tok-op',');']] }, { code: [['',' '],['tok-op','}']] }, { code: [['tok-op','}']] }, ], steps: [ { line:0, stack:[{name:'main()',vars:[],active:true}], expl:{label:'Program starts', text:'Java enters main(). A frame is pushed onto the call stack.'} }, { line:1, stack:[{name:'main()',vars:[{n:'day',v:'2',fresh:true,cls:false}],active:true}], expl:{label:'day = 2', text:'day is assigned 2. This is the value the switch will test.'} }, { line:2, stack:[{name:'main()',vars:[{n:'day',v:'2',fresh:false,cls:false}],active:true}], expl:{label:'switch evaluates', text:'switch (day) evaluates the expression. day is 2. Java looks for a matching case label.'} }, { line:3, stack:[{name:'main()',vars:[{n:'day',v:'2',fresh:false,cls:false}],active:true}], expl:{label:'case 1 -- no match', text:'case 1: does not match 2. Java skips this case and its body entirely.'} }, { line:6, stack:[{name:'main()',vars:[{n:'day',v:'2',fresh:false,cls:false}],active:true}], expl:{label:'case 2 -- match!', text:'case 2: matches day. Java jumps to this label and begins executing the body below it.'} }, { line:7, stack:[{name:'main()',vars:[{n:'day',v:'2',fresh:false,cls:false}],active:true}], expl:{label:'Body executes', text:'println("Tuesday") runs. The matched case body is now executing.'} }, { line:8, stack:[{name:'main()',vars:[{n:'day',v:'2',fresh:false,cls:false}],active:true}], expl:{label:'break exits switch', text:'break stops execution and jumps out of the entire switch block. Without it, execution would continue into the next case body.'} }, { line:12, stack:[{name:'main()',vars:[{n:'day',v:'2',fresh:false,cls:false}],active:true}], expl:{label:'Done', text:'main() ends. The colon syntax requires break in each case -- the next scenario shows what happens when you leave it out.'} }, ] }, { label: "Fall-through", lines: [ { code: [['tok-kw','static '],['tok-kw','void '],['tok-meth','main'],['tok-op','(String[] args) {']] }, { code: [['',' '],['tok-type','int '],['tok-op','level = '],['tok-num','1'],['tok-op',';']] }, { code: [['',' '],['tok-kw','switch '],['tok-op','(level) {']] }, { code: [['',' '],['tok-kw','case '],['tok-num','1'],['tok-op',':']] }, { code: [['',' '],['tok-op','System.out.'],['tok-meth','println'],['tok-op','('],['tok-str','"Beginner"'],['tok-op',');']] }, { code: [['',' '],['tok-kw','case '],['tok-num','2'],['tok-op',':']] }, { code: [['',' '],['tok-op','System.out.'],['tok-meth','println'],['tok-op','('],['tok-str','"Intermediate"'],['tok-op',');']] }, { code: [['',' '],['tok-kw','case '],['tok-num','3'],['tok-op',':']] }, { code: [['',' '],['tok-op','System.out.'],['tok-meth','println'],['tok-op','('],['tok-str','"Advanced"'],['tok-op',');']] }, { code: [['',' '],['tok-op','}']] }, { code: [['tok-op','}']] }, ], steps: [ { line:0, stack:[{name:'main()',vars:[],active:true}], expl:{label:'Program starts', text:'main() begins. This switch has no break statements -- watch what happens.'} }, { line:1, stack:[{name:'main()',vars:[{n:'level',v:'1',fresh:true,cls:false}],active:true}], expl:{label:'level = 1', text:'level is 1. We expect only "Beginner" to print -- but that is not what happens.'} }, { line:2, stack:[{name:'main()',vars:[{n:'level',v:'1',fresh:false,cls:false}],active:true}], expl:{label:'switch evaluates', text:'switch (level) sees 1 and jumps to case 1.'} }, { line:3, stack:[{name:'main()',vars:[{n:'level',v:'1',fresh:false,cls:false}],active:true}], expl:{label:'case 1 matches', text:'case 1: matches. Execution enters the body.'} }, { line:4, stack:[{name:'main()',vars:[{n:'level',v:'1',fresh:false,cls:false}],active:true}], expl:{label:'Prints "Beginner"', text:'println("Beginner") runs. So far so good -- but there is no break, so Java does not stop here.'} }, { line:5, stack:[{name:'main()',vars:[{n:'level',v:'1',fresh:false,cls:false}],active:true}], expl:{label:'Fall-through to case 2', text:'Without break, execution falls straight through to the next case body. The case 2: label is not re-tested -- it is just a marker that execution passes over.'} }, { line:6, stack:[{name:'main()',vars:[{n:'level',v:'1',fresh:false,cls:false}],active:true}], expl:{label:'Prints "Intermediate"', text:'println("Intermediate") runs even though level is not 2. Fall-through does not check the case value again.'} }, { line:7, stack:[{name:'main()',vars:[{n:'level',v:'1',fresh:false,cls:false}],active:true}], expl:{label:'Fall-through to case 3', text:'Still no break. Execution continues falling through.'} }, { line:8, stack:[{name:'main()',vars:[{n:'level',v:'1',fresh:false,cls:false}],active:true}], expl:{label:'Prints "Advanced"', text:'println("Advanced") also runs. All three cases printed because there were no break statements.'} }, { line:10, stack:[{name:'main()',vars:[{n:'level',v:'1',fresh:false,cls:false}],active:true}], expl:{label:'Summary', text:'Fall-through is almost always a bug in the colon syntax. The arrow syntax (next scenario) eliminates this problem entirely.'} }, ] }, { label: "Arrow syntax", lines: [ { code: [['tok-kw','static '],['tok-kw','void '],['tok-meth','main'],['tok-op','(String[] args) {']] }, { code: [['',' '],['tok-type','int '],['tok-op','day = '],['tok-num','2'],['tok-op',';']] }, { code: [['',' '],['tok-kw','switch '],['tok-op','(day) {']] }, { code: [['',' '],['tok-kw','case '],['tok-num','1'],['tok-op',' -> System.out.'],['tok-meth','println'],['tok-op','('],['tok-str','"Monday"'],['tok-op',');']] }, { code: [['',' '],['tok-kw','case '],['tok-num','2'],['tok-op',' -> System.out.'],['tok-meth','println'],['tok-op','('],['tok-str','"Tuesday"'],['tok-op',');']] }, { code: [['',' '],['tok-kw','default'],['tok-op',' -> System.out.'],['tok-meth','println'],['tok-op','('],['tok-str','"Other"'],['tok-op',');']] }, { code: [['',' '],['tok-op','}']] }, { code: [['tok-op','}']] }, ], steps: [ { line:0, stack:[{name:'main()',vars:[],active:true}], expl:{label:'Program starts', text:'main() begins. This time we use the arrow (->) syntax introduced in Java 14.'} }, { line:1, stack:[{name:'main()',vars:[{n:'day',v:'2',fresh:true,cls:false}],active:true}], expl:{label:'day = 2', text:'day is 2.'} }, { line:2, stack:[{name:'main()',vars:[{n:'day',v:'2',fresh:false,cls:false}],active:true}], expl:{label:'switch evaluates', text:'switch (day) evaluates the expression and looks for a matching case.'} }, { line:4, stack:[{name:'main()',vars:[{n:'day',v:'2',fresh:false,cls:false}],active:true}], expl:{label:'case 2 matches and runs', text:'case 2 -> matches. The arrow body runs immediately. When it finishes, the switch exits automatically -- no break needed, and fall-through is impossible by design.'} }, { line:7, stack:[{name:'main()',vars:[{n:'day',v:'2',fresh:false,cls:false}],active:true}], expl:{label:'Done', text:'main() ends. Arrow syntax is shorter, safer, and the preferred style in modern Java. Use the colon syntax only when you need intentional fall-through (which is rare).'} }, ] }, { label: "Menu with switch", lines: [ { code: [['tok-kw','static '],['tok-kw','void '],['tok-meth','main'],['tok-op','(String[] args) {']] }, { code: [['',' '],['tok-type','Scanner '],['tok-op','sc = '],['tok-kw','new '],['tok-cls','Scanner'],['tok-op','(System.in);']] }, { code: [['',' '],['tok-op','System.out.'],['tok-meth','println'],['tok-op','('],['tok-str','"1. New game"'],['tok-op',');']] }, { code: [['',' '],['tok-op','System.out.'],['tok-meth','println'],['tok-op','('],['tok-str','"2. Load game"'],['tok-op',');']] }, { code: [['',' '],['tok-op','System.out.'],['tok-meth','println'],['tok-op','('],['tok-str','"3. Quit"'],['tok-op',');']] }, { code: [['',' '],['tok-type','int '],['tok-op','choice = sc.'],['tok-meth','nextInt'],['tok-op','();']] }, { code: [['',' '],['tok-kw','switch '],['tok-op','(choice) {']] }, { code: [['',' '],['tok-kw','case '],['tok-num','1'],['tok-op',' -> System.out.'],['tok-meth','println'],['tok-op','('],['tok-str','"Starting..."'],['tok-op',');']] }, { code: [['',' '],['tok-kw','case '],['tok-num','2'],['tok-op',' -> System.out.'],['tok-meth','println'],['tok-op','('],['tok-str','"Loading..."'],['tok-op',');']] }, { code: [['',' '],['tok-kw','case '],['tok-num','3'],['tok-op',' -> System.out.'],['tok-meth','println'],['tok-op','('],['tok-str','"Goodbye!"'],['tok-op',');']] }, { code: [['',' '],['tok-kw','default'],['tok-op',' -> System.out.'],['tok-meth','println'],['tok-op','('],['tok-str','"Invalid choice"'],['tok-op',');']] }, { code: [['',' '],['tok-op','}']] }, { code: [['tok-op','}']] }, ], steps: [ { line:0, stack:[{name:'main()',vars:[],active:true}], expl:{label:'Program starts', text:'main() begins. We will build a text menu driven by a switch.'} }, { line:1, stack:[{name:'main()',vars:[{n:'sc',v:'@Scanner1',fresh:true,cls:true}],active:true}], expl:{label:'Scanner created', text:'new Scanner(System.in) connects to the keyboard. sc holds a reference to it.'} }, { line:2, stack:[{name:'main()',vars:[{n:'sc',v:'@Scanner1',fresh:false,cls:true}],active:true}], expl:{label:'Menu prints', text:'println("1. New game") prints the first menu option. The user sees the menu building line by line.'} }, { line:3, stack:[{name:'main()',vars:[{n:'sc',v:'@Scanner1',fresh:false,cls:true}],active:true}], expl:{label:'Menu continues', text:'println("2. Load game") prints the second option.'} }, { line:4, stack:[{name:'main()',vars:[{n:'sc',v:'@Scanner1',fresh:false,cls:true}],active:true}], expl:{label:'Menu complete', text:'println("3. Quit") prints the last option. The full menu is now visible to the user.'} }, { line:5, stack:[{name:'main()',vars:[{n:'sc',v:'@Scanner1',fresh:false,cls:true},{n:'choice',v:'2',fresh:true,cls:false}],active:true}], expl:{label:'User picks 2', text:'sc.nextInt() waits. The user types 2 and presses Enter. choice is now 2.'} }, { line:6, stack:[{name:'main()',vars:[{n:'sc',v:'@Scanner1',fresh:false,cls:true},{n:'choice',v:'2',fresh:false,cls:false}],active:true}], expl:{label:'switch evaluates', text:'switch (choice) evaluates to 2 and looks for a matching case. Arrow syntax -- no fall-through possible.'} }, { line:8, stack:[{name:'main()',vars:[{n:'sc',v:'@Scanner1',fresh:false,cls:true},{n:'choice',v:'2',fresh:false,cls:false}],active:true}], expl:{label:'case 2 matches', text:'case 2 -> matches. println("Loading...") runs. The other cases are skipped completely, including default.'} }, { line:12, stack:[{name:'main()',vars:[{n:'sc',v:'@Scanner1',fresh:false,cls:true},{n:'choice',v:'2',fresh:false,cls:false}],active:true}], expl:{label:'Done', text:'main() ends. If the user had entered 99, none of the numbered cases would match and default would run instead, printing "Invalid choice".'} }, ] } ] });