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".'} },
]
}
]
});