[{"data":1,"prerenderedAt":2429},["ShallowReactive",2],{"blog-\u002Fblog\u002Fjava-switch-pattern-matching":3},{"id":4,"title":5,"body":6,"description":2415,"difficulty":2416,"extension":2417,"framework":2418,"frameworkSlug":95,"meta":2419,"navigation":200,"order":117,"path":2420,"qaPath":2421,"seo":2422,"stem":2423,"subtopic":2424,"topic":2425,"topicSlug":2426,"updated":2427,"__hash__":2428},"blog\u002Fblog\u002Fjava-switch-pattern-matching.md","Java Switch Pattern Matching — Expressions, Type Patterns, and Record Deconstruction",{"type":7,"value":8,"toc":2399},"minimark",[9,14,18,71,74,78,90,254,268,273,280,399,408,412,415,469,477,513,520,577,586,590,596,725,747,751,758,891,901,905,920,1090,1093,1097,1103,1343,1346,1465,1468,1472,1486,1570,1583,1587,1594,1737,1747,1751,1754,1818,1829,1833,2345,2351,2355,2395],[10,11,13],"h2",{"id":12},"a-brief-history-of-switch-in-java","A brief history of switch in Java",[15,16,17],"p",{},"Switch in Java evolved in stages:",[19,20,21,38,51,57],"ul",{},[22,23,24,28,29,32,33,37],"li",{},[25,26,27],"strong",{},"Java 14"," (JEP 361) — ",[25,30,31],{},"switch expressions",": produce a value, arrow ",[34,35,36],"code",{},"->"," syntax, no fall-through.",[22,39,40,43,44,50],{},[25,41,42],{},"Java 16"," (JEP 394) — ",[25,45,46,47],{},"pattern matching for ",[34,48,49],{},"instanceof",": bind a variable in one step.",[22,52,53,56],{},[25,54,55],{},"Java 17–20"," — switch pattern matching in preview (JEP 406, 420, 427, 433).",[22,58,59,62,63,66,67,70],{},[25,60,61],{},"Java 21"," (JEP 441) — ",[25,64,65],{},"switch pattern matching finalised",": type patterns, guarded patterns, record deconstruction, ",[34,68,69],{},"null"," cases.",[15,72,73],{},"Understanding the full picture — from basic switch expressions to exhaustive pattern-matching switches — is what separates a strong modern Java answer from a mediocre one.",[10,75,77],{"id":76},"switch-expressions-java-14","Switch expressions (Java 14)",[15,79,80,81,85,86,89],{},"A switch ",[82,83,84],"em",{},"expression"," produces a value and can be used anywhere an expression is expected. The key differences from the traditional switch ",[82,87,88],{},"statement",":",[91,92,97],"pre",{"className":93,"code":94,"language":95,"meta":96,"style":96},"language-java shiki shiki-themes github-light github-dark","\u002F\u002F Traditional switch statement:\nString label;\nswitch (day) {\n    case MONDAY:\n    case TUESDAY:\n        label = \"early week\";\n        break;\n    default:\n        label = \"later\";\n}\n\n\u002F\u002F Switch expression (Java 14):\nString label = switch (day) {\n    case MONDAY, TUESDAY -> \"early week\";\n    default              -> \"later\";\n};\n","java","",[34,98,99,108,115,125,137,147,163,171,177,189,195,202,208,221,235,248],{"__ignoreMap":96},[100,101,104],"span",{"class":102,"line":103},"line",1,[100,105,107],{"class":106},"sJ8bj","\u002F\u002F Traditional switch statement:\n",[100,109,111],{"class":102,"line":110},2,[100,112,114],{"class":113},"sVt8B","String label;\n",[100,116,118,122],{"class":102,"line":117},3,[100,119,121],{"class":120},"szBVR","switch",[100,123,124],{"class":113}," (day) {\n",[100,126,128,131,134],{"class":102,"line":127},4,[100,129,130],{"class":120},"    case",[100,132,133],{"class":113}," MONDAY",[100,135,136],{"class":120},":\n",[100,138,140,142,145],{"class":102,"line":139},5,[100,141,130],{"class":120},[100,143,144],{"class":113}," TUESDAY",[100,146,136],{"class":120},[100,148,150,153,156,160],{"class":102,"line":149},6,[100,151,152],{"class":113},"        label ",[100,154,155],{"class":120},"=",[100,157,159],{"class":158},"sZZnC"," \"early week\"",[100,161,162],{"class":113},";\n",[100,164,166,169],{"class":102,"line":165},7,[100,167,168],{"class":120},"        break",[100,170,162],{"class":113},[100,172,174],{"class":102,"line":173},8,[100,175,176],{"class":120},"    default:\n",[100,178,180,182,184,187],{"class":102,"line":179},9,[100,181,152],{"class":113},[100,183,155],{"class":120},[100,185,186],{"class":158}," \"later\"",[100,188,162],{"class":113},[100,190,192],{"class":102,"line":191},10,[100,193,194],{"class":113},"}\n",[100,196,198],{"class":102,"line":197},11,[100,199,201],{"emptyLinePlaceholder":200},true,"\n",[100,203,205],{"class":102,"line":204},12,[100,206,207],{"class":106},"\u002F\u002F Switch expression (Java 14):\n",[100,209,211,214,216,219],{"class":102,"line":210},13,[100,212,213],{"class":113},"String label ",[100,215,155],{"class":120},[100,217,218],{"class":120}," switch",[100,220,124],{"class":113},[100,222,224,226,229,231,233],{"class":102,"line":223},14,[100,225,130],{"class":120},[100,227,228],{"class":113}," MONDAY, TUESDAY ",[100,230,36],{"class":120},[100,232,159],{"class":158},[100,234,162],{"class":113},[100,236,238,241,244,246],{"class":102,"line":237},15,[100,239,240],{"class":120},"    default",[100,242,243],{"class":120},"              ->",[100,245,186],{"class":158},[100,247,162],{"class":113},[100,249,251],{"class":102,"line":250},16,[100,252,253],{"class":113},"};\n",[15,255,256,257,259,260,263,264,267],{},"Arrow labels (",[34,258,36],{},") don't fall through and don't need ",[34,261,262],{},"break",". Multiple labels per case are comma-separated. The expression ",[25,265,266],{},"must be exhaustive"," — the compiler rejects a switch expression that doesn't cover all possible values.",[269,270,272],"h3",{"id":271},"yield-in-block-arms","yield in block arms",[15,274,275,276,279],{},"When a case arm needs multiple statements, use a block with ",[34,277,278],{},"yield"," to return a value:",[91,281,283],{"className":93,"code":282,"language":95,"meta":96,"style":96},"int fee = switch (tier) {\n    case \"gold\"   -> 0;\n    case \"silver\" -> 5;\n    default -> {\n        int base = 10;\n        int penalty = tier.length();\n        yield base + penalty;   \u002F\u002F returns the value from this arm\n    }\n};\n",[34,284,285,300,316,331,340,355,374,390,395],{"__ignoreMap":96},[100,286,287,290,293,295,297],{"class":102,"line":103},[100,288,289],{"class":120},"int",[100,291,292],{"class":113}," fee ",[100,294,155],{"class":120},[100,296,218],{"class":120},[100,298,299],{"class":113}," (tier) {\n",[100,301,302,304,307,310,314],{"class":102,"line":110},[100,303,130],{"class":120},[100,305,306],{"class":158}," \"gold\"",[100,308,309],{"class":120},"   ->",[100,311,313],{"class":312},"sj4cs"," 0",[100,315,162],{"class":113},[100,317,318,320,323,326,329],{"class":102,"line":117},[100,319,130],{"class":120},[100,321,322],{"class":158}," \"silver\"",[100,324,325],{"class":120}," ->",[100,327,328],{"class":312}," 5",[100,330,162],{"class":113},[100,332,333,335,337],{"class":102,"line":127},[100,334,240],{"class":120},[100,336,325],{"class":120},[100,338,339],{"class":113}," {\n",[100,341,342,345,348,350,353],{"class":102,"line":139},[100,343,344],{"class":120},"        int",[100,346,347],{"class":113}," base ",[100,349,155],{"class":120},[100,351,352],{"class":312}," 10",[100,354,162],{"class":113},[100,356,357,359,362,364,367,371],{"class":102,"line":149},[100,358,344],{"class":120},[100,360,361],{"class":113}," penalty ",[100,363,155],{"class":120},[100,365,366],{"class":113}," tier.",[100,368,370],{"class":369},"sScJk","length",[100,372,373],{"class":113},"();\n",[100,375,376,379,381,384,387],{"class":102,"line":165},[100,377,378],{"class":120},"        yield",[100,380,347],{"class":113},[100,382,383],{"class":120},"+",[100,385,386],{"class":113}," penalty;   ",[100,388,389],{"class":106},"\u002F\u002F returns the value from this arm\n",[100,391,392],{"class":102,"line":173},[100,393,394],{"class":113},"    }\n",[100,396,397],{"class":102,"line":179},[100,398,253],{"class":113},[15,400,401,403,404,407],{},[34,402,278],{}," is to switch expressions what ",[34,405,406],{},"return"," is to methods — scoped to the expression, not the enclosing method.",[10,409,411],{"id":410},"pattern-matching-for-instanceof-java-16","Pattern matching for instanceof (Java 16)",[15,413,414],{},"Before Java 16, testing a type and then using it required two steps:",[91,416,418],{"className":93,"code":417,"language":95,"meta":96,"style":96},"\u002F\u002F Old way — redundant cast:\nif (obj instanceof String) {\n    String s = (String) obj;\n    System.out.println(s.toUpperCase());\n}\n",[34,419,420,425,438,448,465],{"__ignoreMap":96},[100,421,422],{"class":102,"line":103},[100,423,424],{"class":106},"\u002F\u002F Old way — redundant cast:\n",[100,426,427,430,433,435],{"class":102,"line":110},[100,428,429],{"class":120},"if",[100,431,432],{"class":113}," (obj ",[100,434,49],{"class":120},[100,436,437],{"class":113}," String) {\n",[100,439,440,443,445],{"class":102,"line":117},[100,441,442],{"class":113},"    String s ",[100,444,155],{"class":120},[100,446,447],{"class":113}," (String) obj;\n",[100,449,450,453,456,459,462],{"class":102,"line":127},[100,451,452],{"class":113},"    System.out.",[100,454,455],{"class":369},"println",[100,457,458],{"class":113},"(s.",[100,460,461],{"class":369},"toUpperCase",[100,463,464],{"class":113},"());\n",[100,466,467],{"class":102,"line":139},[100,468,194],{"class":113},[15,470,471,476],{},[25,472,473,474],{},"Pattern matching for ",[34,475,49],{}," (JEP 394) collapses the test and binding into one:",[91,478,480],{"className":93,"code":479,"language":95,"meta":96,"style":96},"if (obj instanceof String s) {\n    System.out.println(s.toUpperCase()); \u002F\u002F s is in scope and typed\n}\n",[34,481,482,493,509],{"__ignoreMap":96},[100,483,484,486,488,490],{"class":102,"line":103},[100,485,429],{"class":120},[100,487,432],{"class":113},[100,489,49],{"class":120},[100,491,492],{"class":113}," String s) {\n",[100,494,495,497,499,501,503,506],{"class":102,"line":110},[100,496,452],{"class":113},[100,498,455],{"class":369},[100,500,458],{"class":113},[100,502,461],{"class":369},[100,504,505],{"class":113},"()); ",[100,507,508],{"class":106},"\u002F\u002F s is in scope and typed\n",[100,510,511],{"class":102,"line":117},[100,512,194],{"class":113},[15,514,515,516,519],{},"The bound variable ",[34,517,518],{},"s"," is in scope only when the pattern matches. It also works in compound expressions:",[91,521,523],{"className":93,"code":522,"language":95,"meta":96,"style":96},"if (obj instanceof String s && s.length() > 5) {\n    System.out.println(\"long string: \" + s);\n}\n",[34,524,525,555,573],{"__ignoreMap":96},[100,526,527,529,531,533,536,539,542,544,547,550,552],{"class":102,"line":103},[100,528,429],{"class":120},[100,530,432],{"class":113},[100,532,49],{"class":120},[100,534,535],{"class":113}," String s ",[100,537,538],{"class":120},"&&",[100,540,541],{"class":113}," s.",[100,543,370],{"class":369},[100,545,546],{"class":113},"() ",[100,548,549],{"class":120},">",[100,551,328],{"class":312},[100,553,554],{"class":113},") {\n",[100,556,557,559,561,564,567,570],{"class":102,"line":110},[100,558,452],{"class":113},[100,560,455],{"class":369},[100,562,563],{"class":113},"(",[100,565,566],{"class":158},"\"long string: \"",[100,568,569],{"class":120}," +",[100,571,572],{"class":113}," s);\n",[100,574,575],{"class":102,"line":117},[100,576,194],{"class":113},[15,578,579,580,582,583,585],{},"The compiler is smart enough to know ",[34,581,518],{}," is only accessible in the ",[34,584,538],{}," branch where the test succeeded.",[10,587,589],{"id":588},"type-patterns-in-switch-java-21","Type patterns in switch (Java 21)",[15,591,592,593,595],{},"Switch pattern matching extends ",[34,594,49],{}," patterns to multi-way dispatch:",[91,597,599],{"className":93,"code":598,"language":95,"meta":96,"style":96},"Object obj = getValue();\n\nString desc = switch (obj) {\n    case Integer i  -> \"int: \" + i;\n    case Long l     -> \"long: \" + l;\n    case String s   -> \"str: \" + s;\n    case null       -> \"null\";\n    default         -> \"other: \" + obj.getClass().getName();\n};\n",[34,600,601,613,617,629,646,663,680,695,721],{"__ignoreMap":96},[100,602,603,606,608,611],{"class":102,"line":103},[100,604,605],{"class":113},"Object obj ",[100,607,155],{"class":120},[100,609,610],{"class":369}," getValue",[100,612,373],{"class":113},[100,614,615],{"class":102,"line":110},[100,616,201],{"emptyLinePlaceholder":200},[100,618,619,622,624,626],{"class":102,"line":117},[100,620,621],{"class":113},"String desc ",[100,623,155],{"class":120},[100,625,218],{"class":120},[100,627,628],{"class":113}," (obj) {\n",[100,630,631,633,636,638,641,643],{"class":102,"line":127},[100,632,130],{"class":120},[100,634,635],{"class":113}," Integer i  ",[100,637,36],{"class":120},[100,639,640],{"class":158}," \"int: \"",[100,642,569],{"class":120},[100,644,645],{"class":113}," i;\n",[100,647,648,650,653,655,658,660],{"class":102,"line":139},[100,649,130],{"class":120},[100,651,652],{"class":113}," Long l     ",[100,654,36],{"class":120},[100,656,657],{"class":158}," \"long: \"",[100,659,569],{"class":120},[100,661,662],{"class":113}," l;\n",[100,664,665,667,670,672,675,677],{"class":102,"line":149},[100,666,130],{"class":120},[100,668,669],{"class":113}," String s   ",[100,671,36],{"class":120},[100,673,674],{"class":158}," \"str: \"",[100,676,569],{"class":120},[100,678,679],{"class":113}," s;\n",[100,681,682,684,687,690,693],{"class":102,"line":165},[100,683,130],{"class":120},[100,685,686],{"class":312}," null",[100,688,689],{"class":120},"       ->",[100,691,692],{"class":158}," \"null\"",[100,694,162],{"class":113},[100,696,697,699,702,705,707,710,713,716,719],{"class":102,"line":173},[100,698,240],{"class":120},[100,700,701],{"class":120},"         ->",[100,703,704],{"class":158}," \"other: \"",[100,706,569],{"class":120},[100,708,709],{"class":113}," obj.",[100,711,712],{"class":369},"getClass",[100,714,715],{"class":113},"().",[100,717,718],{"class":369},"getName",[100,720,373],{"class":113},[100,722,723],{"class":102,"line":179},[100,724,253],{"class":113},[15,726,727,728,731,732,735,736,738,739,742,743,746],{},"This replaces chains of ",[34,729,730],{},"if (obj instanceof X x) ... else if (obj instanceof Y y) ..."," with a single, readable, exhaustiveness-checked construct. The selector can be ",[82,733,734],{},"any"," reference type — not just ",[34,737,289],{},", ",[34,740,741],{},"String",", or ",[34,744,745],{},"enum"," as with traditional switch.",[10,748,750],{"id":749},"guarded-patterns-the-when-clause","Guarded patterns — the when clause",[15,752,753,754,757],{},"A ",[34,755,756],{},"when"," clause adds a boolean condition to a type pattern:",[91,759,761],{"className":93,"code":760,"language":95,"meta":96,"style":96},"String classify(Object obj) {\n    return switch (obj) {\n        case Integer i when i \u003C 0   -> \"negative\";\n        case Integer i when i == 0  -> \"zero\";\n        case Integer i              -> \"positive\";\n        case String s when s.isEmpty() -> \"empty string\";\n        case String s               -> \"non-empty string\";\n        default                     -> \"unknown\";\n    };\n}\n",[34,762,763,774,783,803,822,836,855,869,882,887],{"__ignoreMap":96},[100,764,765,768,771],{"class":102,"line":103},[100,766,767],{"class":113},"String ",[100,769,770],{"class":369},"classify",[100,772,773],{"class":113},"(Object obj) {\n",[100,775,776,779,781],{"class":102,"line":110},[100,777,778],{"class":120},"    return",[100,780,218],{"class":120},[100,782,628],{"class":113},[100,784,785,788,791,794,796,798,801],{"class":102,"line":117},[100,786,787],{"class":120},"        case",[100,789,790],{"class":113}," Integer i when i ",[100,792,793],{"class":120},"\u003C",[100,795,313],{"class":312},[100,797,309],{"class":120},[100,799,800],{"class":158}," \"negative\"",[100,802,162],{"class":113},[100,804,805,807,809,812,814,817,820],{"class":102,"line":127},[100,806,787],{"class":120},[100,808,790],{"class":113},[100,810,811],{"class":120},"==",[100,813,313],{"class":312},[100,815,816],{"class":120},"  ->",[100,818,819],{"class":158}," \"zero\"",[100,821,162],{"class":113},[100,823,824,826,829,831,834],{"class":102,"line":139},[100,825,787],{"class":120},[100,827,828],{"class":113}," Integer i              ",[100,830,36],{"class":120},[100,832,833],{"class":158}," \"positive\"",[100,835,162],{"class":113},[100,837,838,840,843,846,848,850,853],{"class":102,"line":149},[100,839,787],{"class":120},[100,841,842],{"class":113}," String s when s.",[100,844,845],{"class":369},"isEmpty",[100,847,546],{"class":113},[100,849,36],{"class":120},[100,851,852],{"class":158}," \"empty string\"",[100,854,162],{"class":113},[100,856,857,859,862,864,867],{"class":102,"line":165},[100,858,787],{"class":120},[100,860,861],{"class":113}," String s               ",[100,863,36],{"class":120},[100,865,866],{"class":158}," \"non-empty string\"",[100,868,162],{"class":113},[100,870,871,874,877,880],{"class":102,"line":173},[100,872,873],{"class":120},"        default",[100,875,876],{"class":120},"                     ->",[100,878,879],{"class":158}," \"unknown\"",[100,881,162],{"class":113},[100,883,884],{"class":102,"line":179},[100,885,886],{"class":113},"    };\n",[100,888,889],{"class":102,"line":191},[100,890,194],{"class":113},[15,892,893,894,897,898,900],{},"Cases are tested ",[25,895,896],{},"top-to-bottom",". The ",[34,899,756],{}," guard is evaluated only if the type pattern matches first. Always put the most specific guards earlier — a later catch-all case for the same type handles the remaining values.",[10,902,904],{"id":903},"exhaustiveness-with-sealed-types","Exhaustiveness with sealed types",[15,906,907,908,911,912,915,916,919],{},"The most powerful feature: when the selector is a ",[25,909,910],{},"sealed type",", the compiler verifies that every permitted subtype is handled. No ",[34,913,914],{},"default"," needed, and adding a new subtype ",[82,917,918],{},"breaks the switch at compile time",", forcing you to update every exhaustive switch.",[91,921,923],{"className":93,"code":922,"language":95,"meta":96,"style":96},"sealed interface Shape permits Circle, Rectangle {}\nrecord Circle(double r)          implements Shape {}\nrecord Rectangle(double w, double h) implements Shape {}\n\ndouble area(Shape s) {\n    return switch (s) {\n        case Circle c        -> Math.PI * c.r() * c.r();\n        case Rectangle r     -> r.w() * r.h();\n    };\n    \u002F\u002F Compiler error if Triangle is added to Shape without handling it here\n}\n",[34,924,925,950,972,997,1001,1011,1020,1051,1077,1081,1086],{"__ignoreMap":96},[100,926,927,930,933,936,939,942,944,947],{"class":102,"line":103},[100,928,929],{"class":120},"sealed",[100,931,932],{"class":120}," interface",[100,934,935],{"class":369}," Shape",[100,937,938],{"class":120}," permits",[100,940,941],{"class":369}," Circle",[100,943,738],{"class":113},[100,945,946],{"class":369},"Rectangle",[100,948,949],{"class":113}," {}\n",[100,951,952,955,957,959,962,965,968,970],{"class":102,"line":110},[100,953,954],{"class":120},"record",[100,956,941],{"class":369},[100,958,563],{"class":113},[100,960,961],{"class":120},"double",[100,963,964],{"class":113}," r)          ",[100,966,967],{"class":120},"implements",[100,969,935],{"class":369},[100,971,949],{"class":113},[100,973,974,976,979,981,983,986,988,991,993,995],{"class":102,"line":117},[100,975,954],{"class":120},[100,977,978],{"class":369}," Rectangle",[100,980,563],{"class":113},[100,982,961],{"class":120},[100,984,985],{"class":113}," w, ",[100,987,961],{"class":120},[100,989,990],{"class":113}," h) ",[100,992,967],{"class":120},[100,994,935],{"class":369},[100,996,949],{"class":113},[100,998,999],{"class":102,"line":127},[100,1000,201],{"emptyLinePlaceholder":200},[100,1002,1003,1005,1008],{"class":102,"line":139},[100,1004,961],{"class":120},[100,1006,1007],{"class":369}," area",[100,1009,1010],{"class":113},"(Shape s) {\n",[100,1012,1013,1015,1017],{"class":102,"line":149},[100,1014,778],{"class":120},[100,1016,218],{"class":120},[100,1018,1019],{"class":113}," (s) {\n",[100,1021,1022,1024,1027,1029,1032,1035,1038,1041,1043,1045,1047,1049],{"class":102,"line":165},[100,1023,787],{"class":120},[100,1025,1026],{"class":113}," Circle c        ",[100,1028,36],{"class":120},[100,1030,1031],{"class":113}," Math.PI ",[100,1033,1034],{"class":120},"*",[100,1036,1037],{"class":113}," c.",[100,1039,1040],{"class":369},"r",[100,1042,546],{"class":113},[100,1044,1034],{"class":120},[100,1046,1037],{"class":113},[100,1048,1040],{"class":369},[100,1050,373],{"class":113},[100,1052,1053,1055,1058,1060,1063,1066,1068,1070,1072,1075],{"class":102,"line":173},[100,1054,787],{"class":120},[100,1056,1057],{"class":113}," Rectangle r     ",[100,1059,36],{"class":120},[100,1061,1062],{"class":113}," r.",[100,1064,1065],{"class":369},"w",[100,1067,546],{"class":113},[100,1069,1034],{"class":120},[100,1071,1062],{"class":113},[100,1073,1074],{"class":369},"h",[100,1076,373],{"class":113},[100,1078,1079],{"class":102,"line":179},[100,1080,886],{"class":113},[100,1082,1083],{"class":102,"line":191},[100,1084,1085],{"class":106},"    \u002F\u002F Compiler error if Triangle is added to Shape without handling it here\n",[100,1087,1088],{"class":102,"line":197},[100,1089,194],{"class":113},[15,1091,1092],{},"This is exhaustiveness you'd previously get only from enums — now available for any closed type hierarchy.",[10,1094,1096],{"id":1095},"record-deconstruction-in-switch","Record deconstruction in switch",[15,1098,1099,1102],{},[25,1100,1101],{},"Record patterns"," (Java 21, JEP 440) let you destructure a record's components directly in a case:",[91,1104,1106],{"className":93,"code":1105,"language":95,"meta":96,"style":96},"sealed interface Expr permits Num, Add, Mul {}\nrecord Num(int v)           implements Expr {}\nrecord Add(Expr l, Expr r)  implements Expr {}\nrecord Mul(Expr l, Expr r)  implements Expr {}\n\nint eval(Expr e) {\n    return switch (e) {\n        case Num(int v)           -> v;\n        case Add(Expr l, Expr r)  -> eval(l) + eval(r);\n        case Mul(Expr l, Expr r)  -> eval(l) * eval(r);\n    };\n}\n\nSystem.out.println(eval(new Add(new Num(3), new Mul(new Num(4), new Num(5))))); \u002F\u002F 23\n",[34,1107,1108,1134,1153,1169,1184,1188,1198,1207,1224,1246,1266,1270,1274,1278],{"__ignoreMap":96},[100,1109,1110,1112,1114,1117,1119,1122,1124,1127,1129,1132],{"class":102,"line":103},[100,1111,929],{"class":120},[100,1113,932],{"class":120},[100,1115,1116],{"class":369}," Expr",[100,1118,938],{"class":120},[100,1120,1121],{"class":369}," Num",[100,1123,738],{"class":113},[100,1125,1126],{"class":369},"Add",[100,1128,738],{"class":113},[100,1130,1131],{"class":369},"Mul",[100,1133,949],{"class":113},[100,1135,1136,1138,1140,1142,1144,1147,1149,1151],{"class":102,"line":110},[100,1137,954],{"class":120},[100,1139,1121],{"class":369},[100,1141,563],{"class":113},[100,1143,289],{"class":120},[100,1145,1146],{"class":113}," v)           ",[100,1148,967],{"class":120},[100,1150,1116],{"class":369},[100,1152,949],{"class":113},[100,1154,1155,1157,1160,1163,1165,1167],{"class":102,"line":117},[100,1156,954],{"class":120},[100,1158,1159],{"class":369}," Add",[100,1161,1162],{"class":113},"(Expr l, Expr r)  ",[100,1164,967],{"class":120},[100,1166,1116],{"class":369},[100,1168,949],{"class":113},[100,1170,1171,1173,1176,1178,1180,1182],{"class":102,"line":127},[100,1172,954],{"class":120},[100,1174,1175],{"class":369}," Mul",[100,1177,1162],{"class":113},[100,1179,967],{"class":120},[100,1181,1116],{"class":369},[100,1183,949],{"class":113},[100,1185,1186],{"class":102,"line":139},[100,1187,201],{"emptyLinePlaceholder":200},[100,1189,1190,1192,1195],{"class":102,"line":149},[100,1191,289],{"class":120},[100,1193,1194],{"class":369}," eval",[100,1196,1197],{"class":113},"(Expr e) {\n",[100,1199,1200,1202,1204],{"class":102,"line":165},[100,1201,778],{"class":120},[100,1203,218],{"class":120},[100,1205,1206],{"class":113}," (e) {\n",[100,1208,1209,1211,1213,1215,1217,1219,1221],{"class":102,"line":173},[100,1210,787],{"class":120},[100,1212,1121],{"class":369},[100,1214,563],{"class":113},[100,1216,289],{"class":120},[100,1218,1146],{"class":113},[100,1220,36],{"class":120},[100,1222,1223],{"class":113}," v;\n",[100,1225,1226,1228,1230,1232,1234,1236,1239,1241,1243],{"class":102,"line":179},[100,1227,787],{"class":120},[100,1229,1159],{"class":369},[100,1231,1162],{"class":113},[100,1233,36],{"class":120},[100,1235,1194],{"class":369},[100,1237,1238],{"class":113},"(l) ",[100,1240,383],{"class":120},[100,1242,1194],{"class":369},[100,1244,1245],{"class":113},"(r);\n",[100,1247,1248,1250,1252,1254,1256,1258,1260,1262,1264],{"class":102,"line":191},[100,1249,787],{"class":120},[100,1251,1175],{"class":369},[100,1253,1162],{"class":113},[100,1255,36],{"class":120},[100,1257,1194],{"class":369},[100,1259,1238],{"class":113},[100,1261,1034],{"class":120},[100,1263,1194],{"class":369},[100,1265,1245],{"class":113},[100,1267,1268],{"class":102,"line":197},[100,1269,886],{"class":113},[100,1271,1272],{"class":102,"line":204},[100,1273,194],{"class":113},[100,1275,1276],{"class":102,"line":210},[100,1277,201],{"emptyLinePlaceholder":200},[100,1279,1280,1283,1285,1287,1290,1292,1295,1297,1299,1301,1303,1305,1308,1311,1313,1315,1317,1319,1321,1323,1326,1328,1330,1332,1334,1337,1340],{"class":102,"line":223},[100,1281,1282],{"class":113},"System.out.",[100,1284,455],{"class":369},[100,1286,563],{"class":113},[100,1288,1289],{"class":369},"eval",[100,1291,563],{"class":113},[100,1293,1294],{"class":120},"new",[100,1296,1159],{"class":369},[100,1298,563],{"class":113},[100,1300,1294],{"class":120},[100,1302,1121],{"class":369},[100,1304,563],{"class":113},[100,1306,1307],{"class":312},"3",[100,1309,1310],{"class":113},"), ",[100,1312,1294],{"class":120},[100,1314,1175],{"class":369},[100,1316,563],{"class":113},[100,1318,1294],{"class":120},[100,1320,1121],{"class":369},[100,1322,563],{"class":113},[100,1324,1325],{"class":312},"4",[100,1327,1310],{"class":113},[100,1329,1294],{"class":120},[100,1331,1121],{"class":369},[100,1333,563],{"class":113},[100,1335,1336],{"class":312},"5",[100,1338,1339],{"class":113},"))))); ",[100,1341,1342],{"class":106},"\u002F\u002F 23\n",[15,1344,1345],{},"Nested deconstruction also works — components that are themselves records can be destructured inline:",[91,1347,1349],{"className":93,"code":1348,"language":95,"meta":96,"style":96},"record Point(int x, int y) {}\nrecord Segment(Point start, Point end) {}\n\nString describe(Segment seg) {\n    return switch (seg) {\n        case Segment(Point(int x1, int y1), Point(int x2, int y2))\n            -> \"(%d,%d)→(%d,%d)\".formatted(x1, y1, x2, y2);\n    };\n}\n",[34,1350,1351,1370,1380,1384,1394,1403,1440,1457,1461],{"__ignoreMap":96},[100,1352,1353,1355,1358,1360,1362,1365,1367],{"class":102,"line":103},[100,1354,954],{"class":120},[100,1356,1357],{"class":369}," Point",[100,1359,563],{"class":113},[100,1361,289],{"class":120},[100,1363,1364],{"class":113}," x, ",[100,1366,289],{"class":120},[100,1368,1369],{"class":113}," y) {}\n",[100,1371,1372,1374,1377],{"class":102,"line":110},[100,1373,954],{"class":120},[100,1375,1376],{"class":369}," Segment",[100,1378,1379],{"class":113},"(Point start, Point end) {}\n",[100,1381,1382],{"class":102,"line":117},[100,1383,201],{"emptyLinePlaceholder":200},[100,1385,1386,1388,1391],{"class":102,"line":127},[100,1387,767],{"class":113},[100,1389,1390],{"class":369},"describe",[100,1392,1393],{"class":113},"(Segment seg) {\n",[100,1395,1396,1398,1400],{"class":102,"line":139},[100,1397,778],{"class":120},[100,1399,218],{"class":120},[100,1401,1402],{"class":113}," (seg) {\n",[100,1404,1405,1407,1409,1411,1414,1416,1418,1421,1423,1426,1428,1430,1432,1435,1437],{"class":102,"line":149},[100,1406,787],{"class":120},[100,1408,1376],{"class":369},[100,1410,563],{"class":113},[100,1412,1413],{"class":369},"Point",[100,1415,563],{"class":113},[100,1417,289],{"class":120},[100,1419,1420],{"class":113}," x1, ",[100,1422,289],{"class":120},[100,1424,1425],{"class":113}," y1), ",[100,1427,1413],{"class":369},[100,1429,563],{"class":113},[100,1431,289],{"class":120},[100,1433,1434],{"class":113}," x2, ",[100,1436,289],{"class":120},[100,1438,1439],{"class":113}," y2))\n",[100,1441,1442,1445,1448,1451,1454],{"class":102,"line":165},[100,1443,1444],{"class":120},"            ->",[100,1446,1447],{"class":158}," \"(%d,%d)→(%d,%d)\"",[100,1449,1450],{"class":113},".",[100,1452,1453],{"class":369},"formatted",[100,1455,1456],{"class":113},"(x1, y1, x2, y2);\n",[100,1458,1459],{"class":102,"line":173},[100,1460,886],{"class":113},[100,1462,1463],{"class":102,"line":179},[100,1464,194],{"class":113},[15,1466,1467],{},"No accessor calls, no explicit casts — the structure is declared in the pattern itself.",[10,1469,1471],{"id":1470},"handling-null-explicitly","Handling null explicitly",[15,1473,1474,1475,1478,1479,1481,1482,1485],{},"Traditional switch throws ",[34,1476,1477],{},"NullPointerException"," if the selector is ",[34,1480,69],{},". Java 21 allows ",[34,1483,1484],{},"case null"," to handle it explicitly:",[91,1487,1489],{"className":93,"code":1488,"language":95,"meta":96,"style":96},"switch (input) {\n    case null           -> System.out.println(\"got null\");\n    case \"yes\", \"true\"  -> System.out.println(\"affirmative\");\n    default             -> System.out.println(\"other: \" + input);\n}\n",[34,1490,1491,1498,1520,1545,1566],{"__ignoreMap":96},[100,1492,1493,1495],{"class":102,"line":103},[100,1494,121],{"class":120},[100,1496,1497],{"class":113}," (input) {\n",[100,1499,1500,1502,1504,1507,1510,1512,1514,1517],{"class":102,"line":110},[100,1501,130],{"class":120},[100,1503,686],{"class":312},[100,1505,1506],{"class":120},"           ->",[100,1508,1509],{"class":113}," System.out.",[100,1511,455],{"class":369},[100,1513,563],{"class":113},[100,1515,1516],{"class":158},"\"got null\"",[100,1518,1519],{"class":113},");\n",[100,1521,1522,1524,1527,1529,1532,1534,1536,1538,1540,1543],{"class":102,"line":117},[100,1523,130],{"class":120},[100,1525,1526],{"class":158}," \"yes\"",[100,1528,738],{"class":113},[100,1530,1531],{"class":158},"\"true\"",[100,1533,816],{"class":120},[100,1535,1509],{"class":113},[100,1537,455],{"class":369},[100,1539,563],{"class":113},[100,1541,1542],{"class":158},"\"affirmative\"",[100,1544,1519],{"class":113},[100,1546,1547,1549,1552,1554,1556,1558,1561,1563],{"class":102,"line":127},[100,1548,240],{"class":120},[100,1550,1551],{"class":120},"             ->",[100,1553,1509],{"class":113},[100,1555,455],{"class":369},[100,1557,563],{"class":113},[100,1559,1560],{"class":158},"\"other: \"",[100,1562,569],{"class":120},[100,1564,1565],{"class":113}," input);\n",[100,1567,1568],{"class":102,"line":139},[100,1569,194],{"class":113},[15,1571,1572,1573,1576,1577,1579,1580,1582],{},"You can combine: ",[34,1574,1575],{},"case null, default ->"," handles both null and unmatched values together. If no ",[34,1578,1484],{}," is present, ",[34,1581,69],{}," still throws NPE for backward compatibility.",[10,1584,1586],{"id":1585},"dominance-ordering-matters","Dominance — ordering matters",[15,1588,1589,1590,1593],{},"When using type patterns, more specific types must appear before more general ones. The compiler rejects ",[25,1591,1592],{},"dominated"," cases — cases that can never be reached because a prior case already matches every value:",[91,1595,1597],{"className":93,"code":1596,"language":95,"meta":96,"style":96},"\u002F\u002F Compile error:\nswitch (obj) {\n    case Object o -> System.out.println(\"any\");   \u002F\u002F dominates everything\n    case String s -> System.out.println(\"string\"); \u002F\u002F unreachable!\n}\n\n\u002F\u002F Correct — most specific first:\nswitch (obj) {\n    case String s  -> System.out.println(\"string\");\n    case Integer i -> System.out.println(\"int\");\n    default        -> System.out.println(\"other\");\n}\n",[34,1598,1599,1604,1610,1634,1657,1661,1665,1670,1676,1695,1715,1733],{"__ignoreMap":96},[100,1600,1601],{"class":102,"line":103},[100,1602,1603],{"class":106},"\u002F\u002F Compile error:\n",[100,1605,1606,1608],{"class":102,"line":110},[100,1607,121],{"class":120},[100,1609,628],{"class":113},[100,1611,1612,1614,1617,1619,1621,1623,1625,1628,1631],{"class":102,"line":117},[100,1613,130],{"class":120},[100,1615,1616],{"class":113}," Object o ",[100,1618,36],{"class":120},[100,1620,1509],{"class":113},[100,1622,455],{"class":369},[100,1624,563],{"class":113},[100,1626,1627],{"class":158},"\"any\"",[100,1629,1630],{"class":113},");   ",[100,1632,1633],{"class":106},"\u002F\u002F dominates everything\n",[100,1635,1636,1638,1640,1642,1644,1646,1648,1651,1654],{"class":102,"line":127},[100,1637,130],{"class":120},[100,1639,535],{"class":113},[100,1641,36],{"class":120},[100,1643,1509],{"class":113},[100,1645,455],{"class":369},[100,1647,563],{"class":113},[100,1649,1650],{"class":158},"\"string\"",[100,1652,1653],{"class":113},"); ",[100,1655,1656],{"class":106},"\u002F\u002F unreachable!\n",[100,1658,1659],{"class":102,"line":139},[100,1660,194],{"class":113},[100,1662,1663],{"class":102,"line":149},[100,1664,201],{"emptyLinePlaceholder":200},[100,1666,1667],{"class":102,"line":165},[100,1668,1669],{"class":106},"\u002F\u002F Correct — most specific first:\n",[100,1671,1672,1674],{"class":102,"line":173},[100,1673,121],{"class":120},[100,1675,628],{"class":113},[100,1677,1678,1680,1683,1685,1687,1689,1691,1693],{"class":102,"line":179},[100,1679,130],{"class":120},[100,1681,1682],{"class":113}," String s  ",[100,1684,36],{"class":120},[100,1686,1509],{"class":113},[100,1688,455],{"class":369},[100,1690,563],{"class":113},[100,1692,1650],{"class":158},[100,1694,1519],{"class":113},[100,1696,1697,1699,1702,1704,1706,1708,1710,1713],{"class":102,"line":191},[100,1698,130],{"class":120},[100,1700,1701],{"class":113}," Integer i ",[100,1703,36],{"class":120},[100,1705,1509],{"class":113},[100,1707,455],{"class":369},[100,1709,563],{"class":113},[100,1711,1712],{"class":158},"\"int\"",[100,1714,1519],{"class":113},[100,1716,1717,1719,1722,1724,1726,1728,1731],{"class":102,"line":197},[100,1718,240],{"class":120},[100,1720,1721],{"class":120},"        ->",[100,1723,1509],{"class":113},[100,1725,455],{"class":369},[100,1727,563],{"class":113},[100,1729,1730],{"class":158},"\"other\"",[100,1732,1519],{"class":113},[100,1734,1735],{"class":102,"line":204},[100,1736,194],{"class":113},[15,1738,1739,1742,1743,1746],{},[25,1740,1741],{},"Rule of thumb:"," order from most specific to most general, same as ",[34,1744,1745],{},"catch"," blocks.",[10,1748,1750],{"id":1749},"switch-pattern-matching-vs-polymorphism","Switch pattern matching vs polymorphism",[15,1752,1753],{},"Switch pattern matching is not a replacement for polymorphism — it's a complement:",[1755,1756,1757,1770],"table",{},[1758,1759,1760],"thead",{},[1761,1762,1763,1767],"tr",{},[1764,1765,1766],"th",{},"Situation",[1764,1768,1769],{},"Prefer",[1771,1772,1773,1789,1797,1804,1811],"tbody",{},[1761,1774,1775,1786],{},[1776,1777,1778,1779,738,1782,1785],"td",{},"Operation belongs to the type (",[34,1780,1781],{},"area()",[34,1783,1784],{},"validate()",")",[1776,1787,1788],{},"Polymorphism",[1761,1790,1791,1794],{},[1776,1792,1793],{},"Operation is external (serialisation, logging, rendering)",[1776,1795,1796],{},"Switch patterns",[1761,1798,1799,1802],{},[1776,1800,1801],{},"Open hierarchy — third parties add subtypes",[1776,1803,1788],{},[1761,1805,1806,1809],{},[1776,1807,1808],{},"Closed hierarchy (sealed types)",[1776,1810,1796],{},[1761,1812,1813,1816],{},[1776,1814,1815],{},"Compile-time exhaustiveness required",[1776,1817,1796],{},[15,1819,1820,1821,1824,1825,1828],{},"The classic trade-off: adding a new ",[82,1822,1823],{},"operation"," on a closed type is easy with switch (add one function); adding a new ",[82,1826,1827],{},"type variant"," to an open type is easy with polymorphism (add one class). Sealed + switch inverts this: new type variants break existing switches (good — the compiler guides you), but new operations require no changes to existing classes.",[10,1830,1832],{"id":1831},"real-world-example-json-value-dispatch","Real-world example: JSON value dispatch",[91,1834,1836],{"className":93,"code":1835,"language":95,"meta":96,"style":96},"sealed interface JsonValue permits\n    JsonString, JsonNumber, JsonBool, JsonNull, JsonArray, JsonObject {}\n\nrecord JsonString(String value)        implements JsonValue {}\nrecord JsonNumber(double value)        implements JsonValue {}\nrecord JsonBool(boolean value)         implements JsonValue {}\nrecord JsonNull()                      implements JsonValue {}\nrecord JsonArray(List\u003CJsonValue> items) implements JsonValue {}\nrecord JsonObject(Map\u003CString, JsonValue> fields) implements JsonValue {}\n\nString toDisplayString(JsonValue v) {\n    return switch (v) {\n        case JsonString(String s)  -> \"\\\"\" + s + \"\\\"\";\n        case JsonNumber(double n)  -> n % 1 == 0\n            ? String.valueOf((long) n) : String.valueOf(n);\n        case JsonBool(boolean b)   -> String.valueOf(b);\n        case JsonNull()            -> \"null\";\n        case JsonArray(var items)  -> items.stream()\n            .map(this::toDisplayString).collect(joining(\",\", \"[\", \"]\"));\n        case JsonObject(var fields) -> fields.entrySet().stream()\n            .map(e -> \"\\\"\" + e.getKey() + \"\\\":\" + toDisplayString(e.getValue()))\n            .collect(joining(\",\", \"{\", \"}\"));\n    };\n}\n",[34,1837,1838,1850,1882,1886,1902,1922,1943,1959,1985,2011,2015,2025,2034,2069,2099,2128,2150,2166,2187,2233,2257,2308,2335,2340],{"__ignoreMap":96},[100,1839,1840,1842,1844,1847],{"class":102,"line":103},[100,1841,929],{"class":120},[100,1843,932],{"class":120},[100,1845,1846],{"class":369}," JsonValue",[100,1848,1849],{"class":120}," permits\n",[100,1851,1852,1855,1857,1860,1862,1865,1867,1870,1872,1875,1877,1880],{"class":102,"line":110},[100,1853,1854],{"class":369},"    JsonString",[100,1856,738],{"class":113},[100,1858,1859],{"class":369},"JsonNumber",[100,1861,738],{"class":113},[100,1863,1864],{"class":369},"JsonBool",[100,1866,738],{"class":113},[100,1868,1869],{"class":369},"JsonNull",[100,1871,738],{"class":113},[100,1873,1874],{"class":369},"JsonArray",[100,1876,738],{"class":113},[100,1878,1879],{"class":369},"JsonObject",[100,1881,949],{"class":113},[100,1883,1884],{"class":102,"line":117},[100,1885,201],{"emptyLinePlaceholder":200},[100,1887,1888,1890,1893,1896,1898,1900],{"class":102,"line":127},[100,1889,954],{"class":120},[100,1891,1892],{"class":369}," JsonString",[100,1894,1895],{"class":113},"(String value)        ",[100,1897,967],{"class":120},[100,1899,1846],{"class":369},[100,1901,949],{"class":113},[100,1903,1904,1906,1909,1911,1913,1916,1918,1920],{"class":102,"line":139},[100,1905,954],{"class":120},[100,1907,1908],{"class":369}," JsonNumber",[100,1910,563],{"class":113},[100,1912,961],{"class":120},[100,1914,1915],{"class":113}," value)        ",[100,1917,967],{"class":120},[100,1919,1846],{"class":369},[100,1921,949],{"class":113},[100,1923,1924,1926,1929,1931,1934,1937,1939,1941],{"class":102,"line":149},[100,1925,954],{"class":120},[100,1927,1928],{"class":369}," JsonBool",[100,1930,563],{"class":113},[100,1932,1933],{"class":120},"boolean",[100,1935,1936],{"class":113}," value)         ",[100,1938,967],{"class":120},[100,1940,1846],{"class":369},[100,1942,949],{"class":113},[100,1944,1945,1947,1950,1953,1955,1957],{"class":102,"line":165},[100,1946,954],{"class":120},[100,1948,1949],{"class":369}," JsonNull",[100,1951,1952],{"class":113},"()                      ",[100,1954,967],{"class":120},[100,1956,1846],{"class":369},[100,1958,949],{"class":113},[100,1960,1961,1963,1966,1969,1971,1974,1976,1979,1981,1983],{"class":102,"line":173},[100,1962,954],{"class":120},[100,1964,1965],{"class":369}," JsonArray",[100,1967,1968],{"class":113},"(List",[100,1970,793],{"class":120},[100,1972,1973],{"class":113},"JsonValue",[100,1975,549],{"class":120},[100,1977,1978],{"class":113}," items) ",[100,1980,967],{"class":120},[100,1982,1846],{"class":369},[100,1984,949],{"class":113},[100,1986,1987,1989,1992,1995,1997,2000,2002,2005,2007,2009],{"class":102,"line":179},[100,1988,954],{"class":120},[100,1990,1991],{"class":369}," JsonObject",[100,1993,1994],{"class":113},"(Map",[100,1996,793],{"class":120},[100,1998,1999],{"class":113},"String, JsonValue",[100,2001,549],{"class":120},[100,2003,2004],{"class":113}," fields) ",[100,2006,967],{"class":120},[100,2008,1846],{"class":369},[100,2010,949],{"class":113},[100,2012,2013],{"class":102,"line":191},[100,2014,201],{"emptyLinePlaceholder":200},[100,2016,2017,2019,2022],{"class":102,"line":197},[100,2018,767],{"class":113},[100,2020,2021],{"class":369},"toDisplayString",[100,2023,2024],{"class":113},"(JsonValue v) {\n",[100,2026,2027,2029,2031],{"class":102,"line":204},[100,2028,778],{"class":120},[100,2030,218],{"class":120},[100,2032,2033],{"class":113}," (v) {\n",[100,2035,2036,2038,2040,2043,2045,2048,2051,2054,2056,2059,2061,2063,2065,2067],{"class":102,"line":210},[100,2037,787],{"class":120},[100,2039,1892],{"class":369},[100,2041,2042],{"class":113},"(String s)  ",[100,2044,36],{"class":120},[100,2046,2047],{"class":158}," \"",[100,2049,2050],{"class":312},"\\\"",[100,2052,2053],{"class":158},"\"",[100,2055,569],{"class":120},[100,2057,2058],{"class":113}," s ",[100,2060,383],{"class":120},[100,2062,2047],{"class":158},[100,2064,2050],{"class":312},[100,2066,2053],{"class":158},[100,2068,162],{"class":113},[100,2070,2071,2073,2075,2077,2079,2082,2084,2087,2090,2093,2096],{"class":102,"line":223},[100,2072,787],{"class":120},[100,2074,1908],{"class":369},[100,2076,563],{"class":113},[100,2078,961],{"class":120},[100,2080,2081],{"class":113}," n)  ",[100,2083,36],{"class":120},[100,2085,2086],{"class":113}," n ",[100,2088,2089],{"class":120},"%",[100,2091,2092],{"class":312}," 1",[100,2094,2095],{"class":120}," ==",[100,2097,2098],{"class":312}," 0\n",[100,2100,2101,2104,2107,2110,2113,2116,2119,2121,2123,2125],{"class":102,"line":237},[100,2102,2103],{"class":120},"            ?",[100,2105,2106],{"class":113}," String.",[100,2108,2109],{"class":369},"valueOf",[100,2111,2112],{"class":113},"((",[100,2114,2115],{"class":120},"long",[100,2117,2118],{"class":113},") n) ",[100,2120,89],{"class":120},[100,2122,2106],{"class":113},[100,2124,2109],{"class":369},[100,2126,2127],{"class":113},"(n);\n",[100,2129,2130,2132,2134,2136,2138,2141,2143,2145,2147],{"class":102,"line":250},[100,2131,787],{"class":120},[100,2133,1928],{"class":369},[100,2135,563],{"class":113},[100,2137,1933],{"class":120},[100,2139,2140],{"class":113}," b)   ",[100,2142,36],{"class":120},[100,2144,2106],{"class":113},[100,2146,2109],{"class":369},[100,2148,2149],{"class":113},"(b);\n",[100,2151,2153,2155,2157,2160,2162,2164],{"class":102,"line":2152},17,[100,2154,787],{"class":120},[100,2156,1949],{"class":369},[100,2158,2159],{"class":113},"()            ",[100,2161,36],{"class":120},[100,2163,692],{"class":158},[100,2165,162],{"class":113},[100,2167,2169,2171,2173,2176,2178,2181,2184],{"class":102,"line":2168},18,[100,2170,787],{"class":120},[100,2172,1965],{"class":369},[100,2174,2175],{"class":113},"(var items)  ",[100,2177,36],{"class":120},[100,2179,2180],{"class":113}," items.",[100,2182,2183],{"class":369},"stream",[100,2185,2186],{"class":113},"()\n",[100,2188,2190,2193,2196,2198,2201,2204,2207,2210,2212,2215,2217,2220,2222,2225,2227,2230],{"class":102,"line":2189},19,[100,2191,2192],{"class":113},"            .",[100,2194,2195],{"class":369},"map",[100,2197,563],{"class":113},[100,2199,2200],{"class":312},"this",[100,2202,2203],{"class":120},"::",[100,2205,2206],{"class":113},"toDisplayString).",[100,2208,2209],{"class":369},"collect",[100,2211,563],{"class":113},[100,2213,2214],{"class":369},"joining",[100,2216,563],{"class":113},[100,2218,2219],{"class":158},"\",\"",[100,2221,738],{"class":113},[100,2223,2224],{"class":158},"\"[\"",[100,2226,738],{"class":113},[100,2228,2229],{"class":158},"\"]\"",[100,2231,2232],{"class":113},"));\n",[100,2234,2236,2238,2240,2243,2245,2248,2251,2253,2255],{"class":102,"line":2235},20,[100,2237,787],{"class":120},[100,2239,1991],{"class":369},[100,2241,2242],{"class":113},"(var fields) ",[100,2244,36],{"class":120},[100,2246,2247],{"class":113}," fields.",[100,2249,2250],{"class":369},"entrySet",[100,2252,715],{"class":113},[100,2254,2183],{"class":369},[100,2256,2186],{"class":113},[100,2258,2260,2262,2264,2267,2269,2271,2273,2275,2277,2280,2283,2285,2287,2289,2291,2294,2296,2299,2302,2305],{"class":102,"line":2259},21,[100,2261,2192],{"class":113},[100,2263,2195],{"class":369},[100,2265,2266],{"class":113},"(e ",[100,2268,36],{"class":120},[100,2270,2047],{"class":158},[100,2272,2050],{"class":312},[100,2274,2053],{"class":158},[100,2276,569],{"class":120},[100,2278,2279],{"class":113}," e.",[100,2281,2282],{"class":369},"getKey",[100,2284,546],{"class":113},[100,2286,383],{"class":120},[100,2288,2047],{"class":158},[100,2290,2050],{"class":312},[100,2292,2293],{"class":158},":\"",[100,2295,569],{"class":120},[100,2297,2298],{"class":369}," toDisplayString",[100,2300,2301],{"class":113},"(e.",[100,2303,2304],{"class":369},"getValue",[100,2306,2307],{"class":113},"()))\n",[100,2309,2311,2313,2315,2317,2319,2321,2323,2325,2328,2330,2333],{"class":102,"line":2310},22,[100,2312,2192],{"class":113},[100,2314,2209],{"class":369},[100,2316,563],{"class":113},[100,2318,2214],{"class":369},[100,2320,563],{"class":113},[100,2322,2219],{"class":158},[100,2324,738],{"class":113},[100,2326,2327],{"class":158},"\"{\"",[100,2329,738],{"class":113},[100,2331,2332],{"class":158},"\"}\"",[100,2334,2232],{"class":113},[100,2336,2338],{"class":102,"line":2337},23,[100,2339,886],{"class":113},[100,2341,2343],{"class":102,"line":2342},24,[100,2344,194],{"class":113},[15,2346,2347,2348,2350],{},"The switch is exhaustive (all six ",[34,2349,1973],{}," subtypes covered), the components are\ndestructured inline, and adding a new JSON type to the sealed interface immediately\nbreaks this method at compile time — intentional and safe.",[10,2352,2354],{"id":2353},"recap","Recap",[15,2356,2357,2360,2361,2365,2366,2369,2370,738,2373,2376,2377,1310,2379,2382,2383,2387,2388,2390,2391,2394],{},[25,2358,2359],{},"Switch expressions"," (Java 14) produce values, use arrow syntax, and are exhaustively\nchecked. ",[25,2362,473,2363],{},[34,2364,49],{}," (Java 16) binds a typed variable in a\nsingle test. ",[25,2367,2368],{},"Switch pattern matching"," (Java 21) extends this to multi-way type\ndispatch with ",[25,2371,2372],{},"type patterns",[25,2374,2375],{},"guarded patterns"," (",[34,2378,756],{},[25,2380,2381],{},"record\ndeconstruction",", and explicit ",[25,2384,2385],{},[34,2386,1484],{}," handling. When the selector is a\n",[25,2389,910],{},", the compiler verifies exhaustiveness — adding a new permitted subtype\nbreaks every unhandled switch at compile time. Order cases from most to least specific\nto avoid ",[25,2392,2393],{},"dominance"," errors. This combination of sealed interfaces + records + switch\npattern matching is the modern Java replacement for the Visitor pattern — less ceremony,\ncompile-time safety, and no external visitor infrastructure.",[2396,2397,2398],"style",{},"html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}",{"title":96,"searchDepth":110,"depth":110,"links":2400},[2401,2402,2405,2406,2407,2408,2409,2410,2411,2412,2413,2414],{"id":12,"depth":110,"text":13},{"id":76,"depth":110,"text":77,"children":2403},[2404],{"id":271,"depth":117,"text":272},{"id":410,"depth":110,"text":411},{"id":588,"depth":110,"text":589},{"id":749,"depth":110,"text":750},{"id":903,"depth":110,"text":904},{"id":1095,"depth":110,"text":1096},{"id":1470,"depth":110,"text":1471},{"id":1585,"depth":110,"text":1586},{"id":1749,"depth":110,"text":1750},{"id":1831,"depth":110,"text":1832},{"id":2353,"depth":110,"text":2354},"Complete guide to Java switch pattern matching — switch expressions vs statements, arrow vs colon syntax, yield, type patterns, guarded patterns with when, record deconstruction, exhaustiveness, null handling, and dominance rules.","medium","md","Java",{},"\u002Fblog\u002Fjava-switch-pattern-matching","\u002Fjava\u002Fmodern-java\u002Fswitch-pattern-matching",{"title":5,"description":2415},"blog\u002Fjava-switch-pattern-matching","Switch Pattern Matching","Modern Java","modern-java","2026-06-20","xyckF9JOiHO0nATFvqGh0NDoa4yYQxw0m2RkBWSFz1k",1782244090507]