[{"data":1,"prerenderedAt":2303},["ShallowReactive",2],{"page-en-\u002Fblog\u002Fjava-21-features":3,"related-en-\u002Fblog\u002Fjava-21-features":2280},{"id":4,"title":5,"body":6,"date":2269,"description":2270,"extension":2271,"meta":2272,"navigation":468,"path":2273,"seo":2274,"stem":2275,"tags":2276,"translation":2278,"__hash__":2279},"pages_en\u002Fen\u002Fblog\u002Fjava-21-features.md","What's New in Java 21: Virtual Threads, Records and Pattern Matching",{"type":7,"value":8,"toc":2256},"minimark",[9,14,18,26,53,57,60,244,247,250,338,341,359,362,398,402,417,548,551,663,669,673,683,937,940,1019,1026,1030,1033,1343,1349,1411,1415,1422,1669,1680,1684,1687,1936,1961,1965,2110,2121,2125,2132,2163,2167,2242,2246,2252],[10,11,13],"h2",{"id":12},"introduction","Introduction",[15,16,17],"p",{},"Java 21 is the LTS (long-term support) release after Java 17 and the most common target for projects moving off Java 11\u002F17. Several of the features that landed between 17 and 21 directly change how we write Java: less boilerplate, safer type checks, and virtual threads that make the thread-per-request model viable again.",[15,19,20,21,25],{},"This post follows up on the Java 11 and beyond post and focuses on the features that are ",[22,23,24],"strong",{},"final"," in Java 21.",[27,28,33],"pre",{"className":29,"code":30,"language":31,"meta":32,"style":32},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","java -version          # openjdk version \"21.x\"\n","bash","",[34,35,36],"code",{"__ignoreMap":32},[37,38,41,45,49],"span",{"class":39,"line":40},"line",1,[37,42,44],{"class":43},"sBMFI","java",[37,46,48],{"class":47},"sfazB"," -version",[37,50,52],{"class":51},"sHwdD","          # openjdk version \"21.x\"\n",[10,54,56],{"id":55},"_1-virtual-threads-jep-444","1. Virtual threads (JEP 444)",[15,58,59],{},"Classic platform threads map one-to-one onto OS threads; each reserves about 1 MB of stack and spawning thousands is expensive. Virtual threads are lightweight threads managed by the JVM: you can start millions, and while waiting on I\u002FO (a database, an HTTP call) they release the underlying OS thread for other work.",[27,61,64],{"className":62,"code":63,"language":44,"meta":32,"style":32},"language-java shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {\n    for (int i = 0; i \u003C 10_000; i++) {\n        int id = i;\n        executor.submit(() -> {\n            Thread.sleep(Duration.ofSeconds(1));   \u002F\u002F simulated blocking I\u002FO\n            return id;\n        });\n    }\n}   \u002F\u002F try-with-resources waits for all tasks to finish\n",[34,65,66,103,144,160,179,212,223,229,235],{"__ignoreMap":32},[37,67,68,72,76,80,84,87,90,93,97,100],{"class":39,"line":40},[37,69,71],{"class":70},"s7zQu","try",[37,73,75],{"class":74},"sMK4o"," (",[37,77,79],{"class":78},"spNyl","var",[37,81,83],{"class":82},"sTEyZ"," executor ",[37,85,86],{"class":74},"=",[37,88,89],{"class":82}," Executors",[37,91,92],{"class":74},".",[37,94,96],{"class":95},"s2Zo4","newVirtualThreadPerTaskExecutor",[37,98,99],{"class":74},"())",[37,101,102],{"class":74}," {\n",[37,104,106,109,111,114,117,119,123,126,128,131,134,136,139,142],{"class":39,"line":105},2,[37,107,108],{"class":70},"    for",[37,110,75],{"class":74},[37,112,113],{"class":78},"int",[37,115,116],{"class":82}," i ",[37,118,86],{"class":74},[37,120,122],{"class":121},"sbssI"," 0",[37,124,125],{"class":74},";",[37,127,116],{"class":82},[37,129,130],{"class":74},"\u003C",[37,132,133],{"class":121}," 10_000",[37,135,125],{"class":74},[37,137,138],{"class":82}," i",[37,140,141],{"class":74},"++)",[37,143,102],{"class":74},[37,145,147,150,153,155,157],{"class":39,"line":146},3,[37,148,149],{"class":78},"        int",[37,151,152],{"class":82}," id ",[37,154,86],{"class":74},[37,156,138],{"class":82},[37,158,159],{"class":74},";\n",[37,161,163,166,168,171,174,177],{"class":39,"line":162},4,[37,164,165],{"class":82},"        executor",[37,167,92],{"class":74},[37,169,170],{"class":95},"submit",[37,172,173],{"class":74},"(()",[37,175,176],{"class":78}," ->",[37,178,102],{"class":74},[37,180,182,185,187,190,193,196,198,201,203,206,209],{"class":39,"line":181},5,[37,183,184],{"class":82},"            Thread",[37,186,92],{"class":74},[37,188,189],{"class":95},"sleep",[37,191,192],{"class":74},"(",[37,194,195],{"class":82},"Duration",[37,197,92],{"class":74},[37,199,200],{"class":95},"ofSeconds",[37,202,192],{"class":74},[37,204,205],{"class":121},"1",[37,207,208],{"class":74},"));",[37,210,211],{"class":51},"   \u002F\u002F simulated blocking I\u002FO\n",[37,213,215,218,221],{"class":39,"line":214},6,[37,216,217],{"class":70},"            return",[37,219,220],{"class":82}," id",[37,222,159],{"class":74},[37,224,226],{"class":39,"line":225},7,[37,227,228],{"class":74},"        });\n",[37,230,232],{"class":39,"line":231},8,[37,233,234],{"class":74},"    }\n",[37,236,238,241],{"class":39,"line":237},9,[37,239,240],{"class":74},"}",[37,242,243],{"class":51},"   \u002F\u002F try-with-resources waits for all tasks to finish\n",[15,245,246],{},"10,000 tasks finish in about a second; the same code on a fixed-size platform thread pool would take minutes.",[15,248,249],{},"To start a single virtual thread:",[27,251,253],{"className":62,"code":252,"language":44,"meta":32,"style":32},"Thread.startVirtualThread(() -> System.out.println(\"hello\"));\nThread.ofVirtual().name(\"worker-\", 0).start(task);\n",[34,254,255,295],{"__ignoreMap":32},[37,256,257,260,262,265,267,269,272,274,277,279,282,284,287,290,292],{"class":39,"line":40},[37,258,259],{"class":82},"Thread",[37,261,92],{"class":74},[37,263,264],{"class":95},"startVirtualThread",[37,266,173],{"class":74},[37,268,176],{"class":78},[37,270,271],{"class":82}," System",[37,273,92],{"class":74},[37,275,276],{"class":82},"out",[37,278,92],{"class":74},[37,280,281],{"class":95},"println",[37,283,192],{"class":74},[37,285,286],{"class":74},"\"",[37,288,289],{"class":47},"hello",[37,291,286],{"class":74},[37,293,294],{"class":74},"));\n",[37,296,297,299,301,304,307,310,312,314,317,319,322,324,327,330,332,335],{"class":39,"line":105},[37,298,259],{"class":82},[37,300,92],{"class":74},[37,302,303],{"class":95},"ofVirtual",[37,305,306],{"class":74},"().",[37,308,309],{"class":95},"name",[37,311,192],{"class":74},[37,313,286],{"class":74},[37,315,316],{"class":47},"worker-",[37,318,286],{"class":74},[37,320,321],{"class":74},",",[37,323,122],{"class":121},[37,325,326],{"class":74},").",[37,328,329],{"class":95},"start",[37,331,192],{"class":74},[37,333,334],{"class":82},"task",[37,336,337],{"class":74},");\n",[15,339,340],{},"In Spring Boot 3.2+ apps it's one line:",[27,342,346],{"className":343,"code":344,"language":345,"meta":32,"style":32},"language-properties shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","spring.threads.virtual.enabled=true\n","properties",[34,347,348],{"__ignoreMap":32},[37,349,350,354,356],{"class":39,"line":40},[37,351,353],{"class":352},"swJcz","spring.threads.virtual.enabled",[37,355,86],{"class":74},[37,357,358],{"class":82},"true\n",[15,360,361],{},"Things to watch out for:",[363,364,365,373,376,391],"ul",{},[366,367,368,369,372],"li",{},"Virtual threads help ",[22,370,371],{},"I\u002FO-bound"," work; they don't speed up CPU-bound computation.",[366,374,375],{},"Don't pool virtual threads; creating a new one per task is the intended use.",[366,377,378,379,382,383,386,387,390],{},"In Java 21, a blocking call inside a ",[34,380,381],{},"synchronized"," block ",[22,384,385],{},"pins"," the virtual thread to its carrier thread. Prefer ",[34,388,389],{},"ReentrantLock"," in hot critical sections. (This limitation was removed in Java 24.)",[366,392,393,394,397],{},"Holding large objects in ",[34,395,396],{},"ThreadLocal"," can become a memory problem across millions of threads.",[10,399,401],{"id":400},"_2-records","2. Records",[15,403,404,405,408,409,412,413,416],{},"Final since Java 16, records remove the need to write constructors, getters, ",[34,406,407],{},"equals",", ",[34,410,411],{},"hashCode"," and ",[34,414,415],{},"toString"," for classes that just carry data:",[27,418,420],{"className":62,"code":419,"language":44,"meta":32,"style":32},"public record User(Long id, String name, String email) { }\n\nvar user = new User(1L, \"Şükrü\", \"sukru@example.com\");\nuser.name();            \u002F\u002F accessor: name(), not getName()\nSystem.out.println(user);   \u002F\u002F User[id=1, name=Şükrü, email=sukru@example.com]\n",[34,421,422,464,470,510,525],{"__ignoreMap":32},[37,423,424,427,430,433,435,438,440,442,445,448,450,452,455,458,461],{"class":39,"line":40},[37,425,426],{"class":78},"public",[37,428,429],{"class":78}," record",[37,431,432],{"class":43}," User",[37,434,192],{"class":74},[37,436,437],{"class":78},"Long",[37,439,220],{"class":82},[37,441,321],{"class":74},[37,443,444],{"class":78}," String",[37,446,447],{"class":82}," name",[37,449,321],{"class":74},[37,451,444],{"class":78},[37,453,454],{"class":82}," email",[37,456,457],{"class":74},")",[37,459,460],{"class":74}," {",[37,462,463],{"class":74}," }\n",[37,465,466],{"class":39,"line":105},[37,467,469],{"emptyLinePlaceholder":468},true,"\n",[37,471,472,474,477,479,482,484,486,489,491,494,497,499,501,503,506,508],{"class":39,"line":146},[37,473,79],{"class":78},[37,475,476],{"class":82}," user ",[37,478,86],{"class":74},[37,480,481],{"class":70}," new",[37,483,432],{"class":95},[37,485,192],{"class":74},[37,487,488],{"class":121},"1L",[37,490,321],{"class":74},[37,492,493],{"class":74}," \"",[37,495,496],{"class":47},"Şükrü",[37,498,286],{"class":74},[37,500,321],{"class":74},[37,502,493],{"class":74},[37,504,505],{"class":47},"sukru@example.com",[37,507,286],{"class":74},[37,509,337],{"class":74},[37,511,512,515,517,519,522],{"class":39,"line":162},[37,513,514],{"class":82},"user",[37,516,92],{"class":74},[37,518,309],{"class":95},[37,520,521],{"class":74},"();",[37,523,524],{"class":51},"            \u002F\u002F accessor: name(), not getName()\n",[37,526,527,530,532,534,536,538,540,542,545],{"class":39,"line":181},[37,528,529],{"class":82},"System",[37,531,92],{"class":74},[37,533,276],{"class":82},[37,535,92],{"class":74},[37,537,281],{"class":95},[37,539,192],{"class":74},[37,541,514],{"class":82},[37,543,544],{"class":74},");",[37,546,547],{"class":51},"   \u002F\u002F User[id=1, name=Şükrü, email=sukru@example.com]\n",[15,549,550],{},"A compact constructor for validation:",[27,552,554],{"className":62,"code":553,"language":44,"meta":32,"style":32},"public record Money(BigDecimal amount, String currency) {\n    public Money {\n        if (amount.signum() \u003C 0) throw new IllegalArgumentException(\"negative amount\");\n        currency = currency.toUpperCase();\n    }\n}\n",[34,555,556,584,593,637,654,658],{"__ignoreMap":32},[37,557,558,560,562,565,567,570,573,575,577,580,582],{"class":39,"line":40},[37,559,426],{"class":78},[37,561,429],{"class":78},[37,563,564],{"class":43}," Money",[37,566,192],{"class":74},[37,568,569],{"class":78},"BigDecimal",[37,571,572],{"class":82}," amount",[37,574,321],{"class":74},[37,576,444],{"class":78},[37,578,579],{"class":82}," currency",[37,581,457],{"class":74},[37,583,102],{"class":74},[37,585,586,589,591],{"class":39,"line":105},[37,587,588],{"class":78},"    public",[37,590,564],{"class":95},[37,592,102],{"class":74},[37,594,595,598,600,603,605,608,611,614,616,618,621,623,626,628,630,633,635],{"class":39,"line":146},[37,596,597],{"class":70},"        if",[37,599,75],{"class":74},[37,601,602],{"class":82},"amount",[37,604,92],{"class":74},[37,606,607],{"class":95},"signum",[37,609,610],{"class":74},"()",[37,612,613],{"class":74}," \u003C",[37,615,122],{"class":121},[37,617,457],{"class":74},[37,619,620],{"class":70}," throw",[37,622,481],{"class":70},[37,624,625],{"class":95}," IllegalArgumentException",[37,627,192],{"class":74},[37,629,286],{"class":74},[37,631,632],{"class":47},"negative amount",[37,634,286],{"class":74},[37,636,337],{"class":74},[37,638,639,642,644,646,648,651],{"class":39,"line":162},[37,640,641],{"class":82},"        currency ",[37,643,86],{"class":74},[37,645,579],{"class":82},[37,647,92],{"class":74},[37,649,650],{"class":95},"toUpperCase",[37,652,653],{"class":74},"();\n",[37,655,656],{"class":39,"line":181},[37,657,234],{"class":74},[37,659,660],{"class":39,"line":214},[37,661,662],{"class":74},"}\n",[15,664,665,666,668],{},"Records are immutable and ",[34,667,24],{},"; ideal for DTOs, API responses and map keys. They can't be used as JPA entities.",[10,670,672],{"id":671},"_3-pattern-matching-for-switch-jep-441","3. Pattern matching for switch (JEP 441)",[15,674,675,678,679,682],{},[34,676,677],{},"switch"," can now match on types, bind the variable directly, and add conditions with ",[34,680,681],{},"when",":",[27,684,686],{"className":62,"code":685,"language":44,"meta":32,"style":32},"static String describe(Object obj) {\n    return switch (obj) {\n        case null                      -> \"null\";\n        case Integer i when i > 100    -> \"big number: \" + i;\n        case Integer i                 -> \"number: \" + i;\n        case String s when s.isBlank() -> \"blank string\";\n        case String s                  -> \"string: \" + s;\n        case List\u003C?> list              -> \"list, size \" + list.size();\n        default                        -> \"unknown: \" + obj.getClass().getSimpleName();\n    };\n}\n",[34,687,688,710,727,747,780,805,832,857,895,926,932],{"__ignoreMap":32},[37,689,690,693,695,698,700,703,706,708],{"class":39,"line":40},[37,691,692],{"class":78},"static",[37,694,444],{"class":78},[37,696,697],{"class":95}," describe",[37,699,192],{"class":74},[37,701,702],{"class":78},"Object",[37,704,705],{"class":82}," obj",[37,707,457],{"class":74},[37,709,102],{"class":74},[37,711,712,715,718,720,723,725],{"class":39,"line":105},[37,713,714],{"class":70},"    return",[37,716,717],{"class":70}," switch",[37,719,75],{"class":74},[37,721,722],{"class":82},"obj",[37,724,457],{"class":74},[37,726,102],{"class":74},[37,728,729,732,735,738,740,743,745],{"class":39,"line":146},[37,730,731],{"class":70},"        case",[37,733,734],{"class":74}," null",[37,736,737],{"class":78},"                      ->",[37,739,493],{"class":74},[37,741,742],{"class":47},"null",[37,744,286],{"class":74},[37,746,159],{"class":74},[37,748,749,751,754,757,760,763,766,768,771,773,776,778],{"class":39,"line":162},[37,750,731],{"class":70},[37,752,753],{"class":78}," Integer",[37,755,756],{"class":82}," i when i ",[37,758,759],{"class":74},">",[37,761,762],{"class":121}," 100",[37,764,765],{"class":78},"    ->",[37,767,493],{"class":74},[37,769,770],{"class":47},"big number: ",[37,772,286],{"class":74},[37,774,775],{"class":74}," +",[37,777,138],{"class":82},[37,779,159],{"class":74},[37,781,782,784,786,789,792,794,797,799,801,803],{"class":39,"line":181},[37,783,731],{"class":70},[37,785,753],{"class":78},[37,787,788],{"class":82}," i                 ",[37,790,791],{"class":78},"->",[37,793,493],{"class":74},[37,795,796],{"class":47},"number: ",[37,798,286],{"class":74},[37,800,775],{"class":74},[37,802,138],{"class":82},[37,804,159],{"class":74},[37,806,807,809,811,814,816,819,821,823,825,828,830],{"class":39,"line":214},[37,808,731],{"class":70},[37,810,444],{"class":78},[37,812,813],{"class":82}," s when s",[37,815,92],{"class":74},[37,817,818],{"class":95},"isBlank",[37,820,610],{"class":74},[37,822,176],{"class":78},[37,824,493],{"class":74},[37,826,827],{"class":47},"blank string",[37,829,286],{"class":74},[37,831,159],{"class":74},[37,833,834,836,838,841,843,845,848,850,852,855],{"class":39,"line":225},[37,835,731],{"class":70},[37,837,444],{"class":78},[37,839,840],{"class":82}," s                  ",[37,842,791],{"class":78},[37,844,493],{"class":74},[37,846,847],{"class":47},"string: ",[37,849,286],{"class":74},[37,851,775],{"class":74},[37,853,854],{"class":82}," s",[37,856,159],{"class":74},[37,858,859,861,864,866,869,871,874,876,878,881,883,885,888,890,893],{"class":39,"line":231},[37,860,731],{"class":70},[37,862,863],{"class":78}," List",[37,865,130],{"class":74},[37,867,868],{"class":70},"?",[37,870,759],{"class":74},[37,872,873],{"class":82}," list              ",[37,875,791],{"class":78},[37,877,493],{"class":74},[37,879,880],{"class":47},"list, size ",[37,882,286],{"class":74},[37,884,775],{"class":74},[37,886,887],{"class":82}," list",[37,889,92],{"class":74},[37,891,892],{"class":95},"size",[37,894,653],{"class":74},[37,896,897,900,903,905,908,910,912,914,916,919,921,924],{"class":39,"line":237},[37,898,899],{"class":70},"        default",[37,901,902],{"class":78},"                        ->",[37,904,493],{"class":74},[37,906,907],{"class":47},"unknown: ",[37,909,286],{"class":74},[37,911,775],{"class":74},[37,913,705],{"class":82},[37,915,92],{"class":74},[37,917,918],{"class":95},"getClass",[37,920,306],{"class":74},[37,922,923],{"class":95},"getSimpleName",[37,925,653],{"class":74},[37,927,929],{"class":39,"line":928},10,[37,930,931],{"class":74},"    };\n",[37,933,935],{"class":39,"line":934},11,[37,936,662],{"class":74},[15,938,939],{},"Compare with the old way:",[27,941,943],{"className":62,"code":942,"language":44,"meta":32,"style":32},"if (obj instanceof Integer) {\n    Integer i = (Integer) obj;\n    ...\n} else if (obj instanceof String) {\n    ...\n}\n",[34,944,945,964,984,989,1011,1015],{"__ignoreMap":32},[37,946,947,950,952,955,958,960,962],{"class":39,"line":40},[37,948,949],{"class":70},"if",[37,951,75],{"class":74},[37,953,954],{"class":82},"obj ",[37,956,957],{"class":74},"instanceof",[37,959,753],{"class":82},[37,961,457],{"class":74},[37,963,102],{"class":74},[37,965,966,969,971,973,975,978,980,982],{"class":39,"line":105},[37,967,968],{"class":78},"    Integer",[37,970,116],{"class":82},[37,972,86],{"class":74},[37,974,75],{"class":74},[37,976,977],{"class":82},"Integer",[37,979,457],{"class":74},[37,981,705],{"class":82},[37,983,159],{"class":74},[37,985,986],{"class":39,"line":146},[37,987,988],{"class":74},"    ...\n",[37,990,991,993,996,999,1001,1003,1005,1007,1009],{"class":39,"line":162},[37,992,240],{"class":74},[37,994,995],{"class":70}," else",[37,997,998],{"class":70}," if",[37,1000,75],{"class":74},[37,1002,954],{"class":82},[37,1004,957],{"class":74},[37,1006,444],{"class":82},[37,1008,457],{"class":74},[37,1010,102],{"class":74},[37,1012,1013],{"class":39,"line":181},[37,1014,988],{"class":74},[37,1016,1017],{"class":39,"line":214},[37,1018,662],{"class":74},[15,1020,1021,1022,1025],{},"Thanks to ",[34,1023,1024],{},"case null",", you no longer need a separate null check before the switch.",[10,1027,1029],{"id":1028},"_4-record-patterns-jep-440","4. Record patterns (JEP 440)",[15,1031,1032],{},"Records can be deconstructed into their components while matching, including nested structures:",[27,1034,1036],{"className":62,"code":1035,"language":44,"meta":32,"style":32},"record Point(int x, int y) { }\nrecord Line(Point start, Point end) { }\n\nstatic String where(Object obj) {\n    return switch (obj) {\n        case Point(int x, int y) when x == 0 && y == 0 -> \"origin\";\n        case Point(var x, var y)                        -> \"point (\" + x + \", \" + y + \")\";\n        case Line(Point(var x1, var y1), Point(var x2, var y2))\n            -> \"line of length \" + Math.hypot(x2 - x1, y2 - y1);\n        default -> \"unknown\";\n    };\n}\n",[34,1037,1038,1067,1095,1099,1118,1132,1181,1236,1274,1319,1334,1338],{"__ignoreMap":32},[37,1039,1040,1043,1046,1048,1050,1053,1055,1058,1061,1063,1065],{"class":39,"line":40},[37,1041,1042],{"class":78},"record",[37,1044,1045],{"class":43}," Point",[37,1047,192],{"class":74},[37,1049,113],{"class":78},[37,1051,1052],{"class":82}," x",[37,1054,321],{"class":74},[37,1056,1057],{"class":78}," int",[37,1059,1060],{"class":82}," y",[37,1062,457],{"class":74},[37,1064,460],{"class":74},[37,1066,463],{"class":74},[37,1068,1069,1071,1074,1076,1079,1082,1084,1086,1089,1091,1093],{"class":39,"line":105},[37,1070,1042],{"class":78},[37,1072,1073],{"class":43}," Line",[37,1075,192],{"class":74},[37,1077,1078],{"class":78},"Point",[37,1080,1081],{"class":82}," start",[37,1083,321],{"class":74},[37,1085,1045],{"class":78},[37,1087,1088],{"class":82}," end",[37,1090,457],{"class":74},[37,1092,460],{"class":74},[37,1094,463],{"class":74},[37,1096,1097],{"class":39,"line":146},[37,1098,469],{"emptyLinePlaceholder":468},[37,1100,1101,1103,1105,1108,1110,1112,1114,1116],{"class":39,"line":162},[37,1102,692],{"class":78},[37,1104,444],{"class":78},[37,1106,1107],{"class":95}," where",[37,1109,192],{"class":74},[37,1111,702],{"class":78},[37,1113,705],{"class":82},[37,1115,457],{"class":74},[37,1117,102],{"class":74},[37,1119,1120,1122,1124,1126,1128,1130],{"class":39,"line":181},[37,1121,714],{"class":70},[37,1123,717],{"class":70},[37,1125,75],{"class":74},[37,1127,722],{"class":82},[37,1129,457],{"class":74},[37,1131,102],{"class":74},[37,1133,1134,1136,1138,1140,1142,1144,1146,1148,1150,1152,1155,1158,1160,1163,1166,1168,1170,1172,1174,1177,1179],{"class":39,"line":214},[37,1135,731],{"class":70},[37,1137,1045],{"class":95},[37,1139,192],{"class":74},[37,1141,113],{"class":78},[37,1143,1052],{"class":82},[37,1145,321],{"class":74},[37,1147,1057],{"class":78},[37,1149,1060],{"class":82},[37,1151,457],{"class":74},[37,1153,1154],{"class":82}," when x ",[37,1156,1157],{"class":74},"==",[37,1159,122],{"class":121},[37,1161,1162],{"class":74}," &&",[37,1164,1165],{"class":82}," y ",[37,1167,1157],{"class":74},[37,1169,122],{"class":121},[37,1171,176],{"class":78},[37,1173,493],{"class":74},[37,1175,1176],{"class":47},"origin",[37,1178,286],{"class":74},[37,1180,159],{"class":74},[37,1182,1183,1185,1187,1189,1192,1194,1197,1199,1201,1203,1206,1208,1210,1213,1216,1218,1220,1222,1224,1226,1228,1230,1232,1234],{"class":39,"line":225},[37,1184,731],{"class":70},[37,1186,1045],{"class":95},[37,1188,192],{"class":74},[37,1190,1191],{"class":82},"var x",[37,1193,321],{"class":74},[37,1195,1196],{"class":82}," var y",[37,1198,457],{"class":74},[37,1200,902],{"class":78},[37,1202,493],{"class":74},[37,1204,1205],{"class":47},"point (",[37,1207,286],{"class":74},[37,1209,775],{"class":74},[37,1211,1212],{"class":82}," x ",[37,1214,1215],{"class":74},"+",[37,1217,493],{"class":74},[37,1219,408],{"class":47},[37,1221,286],{"class":74},[37,1223,775],{"class":74},[37,1225,1165],{"class":82},[37,1227,1215],{"class":74},[37,1229,493],{"class":74},[37,1231,457],{"class":47},[37,1233,286],{"class":74},[37,1235,159],{"class":74},[37,1237,1238,1240,1242,1244,1246,1248,1251,1253,1256,1259,1261,1263,1266,1268,1271],{"class":39,"line":231},[37,1239,731],{"class":70},[37,1241,1073],{"class":95},[37,1243,192],{"class":74},[37,1245,1078],{"class":95},[37,1247,192],{"class":74},[37,1249,1250],{"class":82},"var x1",[37,1252,321],{"class":74},[37,1254,1255],{"class":82}," var y1",[37,1257,1258],{"class":74},"),",[37,1260,1045],{"class":95},[37,1262,192],{"class":74},[37,1264,1265],{"class":82},"var x2",[37,1267,321],{"class":74},[37,1269,1270],{"class":82}," var y2",[37,1272,1273],{"class":74},"))\n",[37,1275,1276,1279,1281,1284,1286,1288,1291,1293,1296,1298,1301,1304,1307,1309,1312,1314,1317],{"class":39,"line":237},[37,1277,1278],{"class":78},"            ->",[37,1280,493],{"class":74},[37,1282,1283],{"class":47},"line of length ",[37,1285,286],{"class":74},[37,1287,775],{"class":74},[37,1289,1290],{"class":82}," Math",[37,1292,92],{"class":74},[37,1294,1295],{"class":95},"hypot",[37,1297,192],{"class":74},[37,1299,1300],{"class":82},"x2 ",[37,1302,1303],{"class":74},"-",[37,1305,1306],{"class":82}," x1",[37,1308,321],{"class":74},[37,1310,1311],{"class":82}," y2 ",[37,1313,1303],{"class":74},[37,1315,1316],{"class":82}," y1",[37,1318,337],{"class":74},[37,1320,1321,1323,1325,1327,1330,1332],{"class":39,"line":928},[37,1322,899],{"class":70},[37,1324,176],{"class":78},[37,1326,493],{"class":74},[37,1328,1329],{"class":47},"unknown",[37,1331,286],{"class":74},[37,1333,159],{"class":74},[37,1335,1336],{"class":39,"line":934},[37,1337,931],{"class":74},[37,1339,1341],{"class":39,"line":1340},12,[37,1342,662],{"class":74},[15,1344,1345,1346,1348],{},"It works with ",[34,1347,957],{}," too:",[27,1350,1352],{"className":62,"code":1351,"language":44,"meta":32,"style":32},"if (obj instanceof Point(int x, int y)) {\n    System.out.println(x + y);\n}\n",[34,1353,1354,1383,1407],{"__ignoreMap":32},[37,1355,1356,1358,1360,1362,1364,1366,1368,1370,1372,1374,1376,1378,1381],{"class":39,"line":40},[37,1357,949],{"class":70},[37,1359,75],{"class":74},[37,1361,954],{"class":82},[37,1363,957],{"class":74},[37,1365,1045],{"class":95},[37,1367,192],{"class":74},[37,1369,113],{"class":78},[37,1371,1052],{"class":82},[37,1373,321],{"class":74},[37,1375,1057],{"class":78},[37,1377,1060],{"class":82},[37,1379,1380],{"class":74},"))",[37,1382,102],{"class":74},[37,1384,1385,1388,1390,1392,1394,1396,1398,1401,1403,1405],{"class":39,"line":105},[37,1386,1387],{"class":82},"    System",[37,1389,92],{"class":74},[37,1391,276],{"class":82},[37,1393,92],{"class":74},[37,1395,281],{"class":95},[37,1397,192],{"class":74},[37,1399,1400],{"class":82},"x ",[37,1402,1215],{"class":74},[37,1404,1060],{"class":82},[37,1406,337],{"class":74},[37,1408,1409],{"class":39,"line":146},[37,1410,662],{"class":74},[10,1412,1414],{"id":1413},"_5-sealed-classes-and-exhaustive-switches","5. Sealed classes and exhaustive switches",[15,1416,1417,1418,1421],{},"Final since Java 17, sealed classes restrict which subtypes a type can have. Combined with pattern matching, the compiler checks that every case is handled and no ",[34,1419,1420],{},"default"," is needed:",[27,1423,1425],{"className":62,"code":1424,"language":44,"meta":32,"style":32},"public sealed interface PaymentResult\n        permits Success, Declined, Failed { }\n\npublic record Success(String transactionId) implements PaymentResult { }\npublic record Declined(String reason) implements PaymentResult { }\npublic record Failed(Exception error) implements PaymentResult { }\n\nString message = switch (result) {\n    case Success s  -> \"Payment received: \" + s.transactionId();\n    case Declined d -> \"Declined: \" + d.reason();\n    case Failed f   -> \"Error: \" + f.error().getMessage();\n};\n",[34,1426,1427,1440,1462,1466,1494,1519,1545,1549,1569,1599,1629,1664],{"__ignoreMap":32},[37,1428,1429,1431,1434,1437],{"class":39,"line":40},[37,1430,426],{"class":78},[37,1432,1433],{"class":78}," sealed",[37,1435,1436],{"class":78}," interface",[37,1438,1439],{"class":43}," PaymentResult\n",[37,1441,1442,1445,1448,1450,1453,1455,1458,1460],{"class":39,"line":105},[37,1443,1444],{"class":78},"        permits",[37,1446,1447],{"class":43}," Success",[37,1449,321],{"class":74},[37,1451,1452],{"class":43}," Declined",[37,1454,321],{"class":74},[37,1456,1457],{"class":43}," Failed",[37,1459,460],{"class":74},[37,1461,463],{"class":74},[37,1463,1464],{"class":39,"line":146},[37,1465,469],{"emptyLinePlaceholder":468},[37,1467,1468,1470,1472,1474,1476,1479,1482,1484,1487,1490,1492],{"class":39,"line":162},[37,1469,426],{"class":78},[37,1471,429],{"class":78},[37,1473,1447],{"class":43},[37,1475,192],{"class":74},[37,1477,1478],{"class":78},"String",[37,1480,1481],{"class":82}," transactionId",[37,1483,457],{"class":74},[37,1485,1486],{"class":78}," implements",[37,1488,1489],{"class":43}," PaymentResult",[37,1491,460],{"class":74},[37,1493,463],{"class":74},[37,1495,1496,1498,1500,1502,1504,1506,1509,1511,1513,1515,1517],{"class":39,"line":181},[37,1497,426],{"class":78},[37,1499,429],{"class":78},[37,1501,1452],{"class":43},[37,1503,192],{"class":74},[37,1505,1478],{"class":78},[37,1507,1508],{"class":82}," reason",[37,1510,457],{"class":74},[37,1512,1486],{"class":78},[37,1514,1489],{"class":43},[37,1516,460],{"class":74},[37,1518,463],{"class":74},[37,1520,1521,1523,1525,1527,1529,1532,1535,1537,1539,1541,1543],{"class":39,"line":214},[37,1522,426],{"class":78},[37,1524,429],{"class":78},[37,1526,1457],{"class":43},[37,1528,192],{"class":74},[37,1530,1531],{"class":78},"Exception",[37,1533,1534],{"class":82}," error",[37,1536,457],{"class":74},[37,1538,1486],{"class":78},[37,1540,1489],{"class":43},[37,1542,460],{"class":74},[37,1544,463],{"class":74},[37,1546,1547],{"class":39,"line":225},[37,1548,469],{"emptyLinePlaceholder":468},[37,1550,1551,1553,1556,1558,1560,1562,1565,1567],{"class":39,"line":231},[37,1552,1478],{"class":78},[37,1554,1555],{"class":82}," message ",[37,1557,86],{"class":74},[37,1559,717],{"class":70},[37,1561,75],{"class":74},[37,1563,1564],{"class":82},"result",[37,1566,457],{"class":74},[37,1568,102],{"class":74},[37,1570,1571,1574,1576,1579,1581,1583,1586,1588,1590,1592,1594,1597],{"class":39,"line":237},[37,1572,1573],{"class":70},"    case",[37,1575,1447],{"class":78},[37,1577,1578],{"class":82}," s  ",[37,1580,791],{"class":78},[37,1582,493],{"class":74},[37,1584,1585],{"class":47},"Payment received: ",[37,1587,286],{"class":74},[37,1589,775],{"class":74},[37,1591,854],{"class":82},[37,1593,92],{"class":74},[37,1595,1596],{"class":95},"transactionId",[37,1598,653],{"class":74},[37,1600,1601,1603,1605,1608,1610,1612,1615,1617,1619,1622,1624,1627],{"class":39,"line":928},[37,1602,1573],{"class":70},[37,1604,1452],{"class":78},[37,1606,1607],{"class":82}," d ",[37,1609,791],{"class":78},[37,1611,493],{"class":74},[37,1613,1614],{"class":47},"Declined: ",[37,1616,286],{"class":74},[37,1618,775],{"class":74},[37,1620,1621],{"class":82}," d",[37,1623,92],{"class":74},[37,1625,1626],{"class":95},"reason",[37,1628,653],{"class":74},[37,1630,1631,1633,1635,1638,1640,1642,1645,1647,1649,1652,1654,1657,1659,1662],{"class":39,"line":934},[37,1632,1573],{"class":70},[37,1634,1457],{"class":78},[37,1636,1637],{"class":82}," f   ",[37,1639,791],{"class":78},[37,1641,493],{"class":74},[37,1643,1644],{"class":47},"Error: ",[37,1646,286],{"class":74},[37,1648,775],{"class":74},[37,1650,1651],{"class":82}," f",[37,1653,92],{"class":74},[37,1655,1656],{"class":95},"error",[37,1658,306],{"class":74},[37,1660,1661],{"class":95},"getMessage",[37,1663,653],{"class":74},[37,1665,1666],{"class":39,"line":1340},[37,1667,1668],{"class":74},"};\n",[15,1670,1671,1672,1675,1676,1679],{},"If a new type is added to ",[34,1673,1674],{},"PaymentResult"," tomorrow, every switch you haven't updated becomes a ",[22,1677,1678],{},"compile error",". A very powerful tool for modeling error types and state machines.",[10,1681,1683],{"id":1682},"_6-sequenced-collections-jep-431","6. Sequenced collections (JEP 431)",[15,1685,1686],{},"Ordered collections get a common API for the first and last elements:",[27,1688,1690],{"className":62,"code":1689,"language":44,"meta":32,"style":32},"List\u003CString> list = new ArrayList\u003C>(List.of(\"a\", \"b\", \"c\"));\nlist.getFirst();       \u002F\u002F \"a\"   (was list.get(0))\nlist.getLast();        \u002F\u002F \"c\"   (was list.get(list.size() - 1))\nlist.addFirst(\"z\");\nlist.removeLast();\nlist.reversed();       \u002F\u002F reversed view\n\nLinkedHashMap\u003CString, Integer> map = new LinkedHashMap\u003C>();\nmap.put(\"one\", 1);\nmap.put(\"two\", 2);\nmap.firstEntry();      \u002F\u002F one=1\nmap.lastEntry();       \u002F\u002F two=2\n",[34,1691,1692,1752,1767,1781,1801,1812,1826,1830,1858,1884,1908,1922],{"__ignoreMap":32},[37,1693,1694,1697,1699,1701,1703,1706,1708,1710,1713,1716,1718,1720,1723,1725,1727,1730,1732,1734,1736,1739,1741,1743,1745,1748,1750],{"class":39,"line":40},[37,1695,1696],{"class":78},"List",[37,1698,130],{"class":74},[37,1700,1478],{"class":78},[37,1702,759],{"class":74},[37,1704,1705],{"class":82}," list ",[37,1707,86],{"class":74},[37,1709,481],{"class":70},[37,1711,1712],{"class":78}," ArrayList",[37,1714,1715],{"class":74},"\u003C>(",[37,1717,1696],{"class":82},[37,1719,92],{"class":74},[37,1721,1722],{"class":95},"of",[37,1724,192],{"class":74},[37,1726,286],{"class":74},[37,1728,1729],{"class":47},"a",[37,1731,286],{"class":74},[37,1733,321],{"class":74},[37,1735,493],{"class":74},[37,1737,1738],{"class":47},"b",[37,1740,286],{"class":74},[37,1742,321],{"class":74},[37,1744,493],{"class":74},[37,1746,1747],{"class":47},"c",[37,1749,286],{"class":74},[37,1751,294],{"class":74},[37,1753,1754,1757,1759,1762,1764],{"class":39,"line":105},[37,1755,1756],{"class":82},"list",[37,1758,92],{"class":74},[37,1760,1761],{"class":95},"getFirst",[37,1763,521],{"class":74},[37,1765,1766],{"class":51},"       \u002F\u002F \"a\"   (was list.get(0))\n",[37,1768,1769,1771,1773,1776,1778],{"class":39,"line":146},[37,1770,1756],{"class":82},[37,1772,92],{"class":74},[37,1774,1775],{"class":95},"getLast",[37,1777,521],{"class":74},[37,1779,1780],{"class":51},"        \u002F\u002F \"c\"   (was list.get(list.size() - 1))\n",[37,1782,1783,1785,1787,1790,1792,1794,1797,1799],{"class":39,"line":162},[37,1784,1756],{"class":82},[37,1786,92],{"class":74},[37,1788,1789],{"class":95},"addFirst",[37,1791,192],{"class":74},[37,1793,286],{"class":74},[37,1795,1796],{"class":47},"z",[37,1798,286],{"class":74},[37,1800,337],{"class":74},[37,1802,1803,1805,1807,1810],{"class":39,"line":181},[37,1804,1756],{"class":82},[37,1806,92],{"class":74},[37,1808,1809],{"class":95},"removeLast",[37,1811,653],{"class":74},[37,1813,1814,1816,1818,1821,1823],{"class":39,"line":214},[37,1815,1756],{"class":82},[37,1817,92],{"class":74},[37,1819,1820],{"class":95},"reversed",[37,1822,521],{"class":74},[37,1824,1825],{"class":51},"       \u002F\u002F reversed view\n",[37,1827,1828],{"class":39,"line":225},[37,1829,469],{"emptyLinePlaceholder":468},[37,1831,1832,1835,1837,1839,1841,1843,1845,1848,1850,1852,1855],{"class":39,"line":231},[37,1833,1834],{"class":78},"LinkedHashMap",[37,1836,130],{"class":74},[37,1838,1478],{"class":78},[37,1840,321],{"class":74},[37,1842,753],{"class":78},[37,1844,759],{"class":74},[37,1846,1847],{"class":82}," map ",[37,1849,86],{"class":74},[37,1851,481],{"class":70},[37,1853,1854],{"class":78}," LinkedHashMap",[37,1856,1857],{"class":74},"\u003C>();\n",[37,1859,1860,1863,1865,1868,1870,1872,1875,1877,1879,1882],{"class":39,"line":237},[37,1861,1862],{"class":82},"map",[37,1864,92],{"class":74},[37,1866,1867],{"class":95},"put",[37,1869,192],{"class":74},[37,1871,286],{"class":74},[37,1873,1874],{"class":47},"one",[37,1876,286],{"class":74},[37,1878,321],{"class":74},[37,1880,1881],{"class":121}," 1",[37,1883,337],{"class":74},[37,1885,1886,1888,1890,1892,1894,1896,1899,1901,1903,1906],{"class":39,"line":928},[37,1887,1862],{"class":82},[37,1889,92],{"class":74},[37,1891,1867],{"class":95},[37,1893,192],{"class":74},[37,1895,286],{"class":74},[37,1897,1898],{"class":47},"two",[37,1900,286],{"class":74},[37,1902,321],{"class":74},[37,1904,1905],{"class":121}," 2",[37,1907,337],{"class":74},[37,1909,1910,1912,1914,1917,1919],{"class":39,"line":934},[37,1911,1862],{"class":82},[37,1913,92],{"class":74},[37,1915,1916],{"class":95},"firstEntry",[37,1918,521],{"class":74},[37,1920,1921],{"class":51},"      \u002F\u002F one=1\n",[37,1923,1924,1926,1928,1931,1933],{"class":39,"line":1340},[37,1925,1862],{"class":82},[37,1927,92],{"class":74},[37,1929,1930],{"class":95},"lastEntry",[37,1932,521],{"class":74},[37,1934,1935],{"class":51},"       \u002F\u002F two=2\n",[15,1937,1938,408,1940,408,1943,408,1946,408,1948,412,1951,1954,1955,408,1958,326],{},[34,1939,1696],{},[34,1941,1942],{},"Deque",[34,1944,1945],{},"LinkedHashSet",[34,1947,1834],{},[34,1949,1950],{},"TreeSet",[34,1952,1953],{},"TreeMap"," implement these interfaces (",[34,1956,1957],{},"SequencedCollection",[34,1959,1960],{},"SequencedMap",[10,1962,1964],{"id":1963},"_7-other-small-but-useful-additions","7. Other small but useful additions",[27,1966,1968],{"className":62,"code":1967,"language":44,"meta":32,"style":32},"\u002F\u002F String\n\"hello world\".indexOf('o', 2, 8);        \u002F\u002F search within a range\nnew StringBuilder().repeat(\"-\", 20);     \u002F\u002F \"--------------------\"\n\n\u002F\u002F Math\nMath.clamp(150, 0, 100);                 \u002F\u002F 100\n\n\u002F\u002F Character\nCharacter.isEmoji(0x1F600);              \u002F\u002F true\n",[34,1969,1970,1975,2013,2044,2048,2053,2081,2085,2090],{"__ignoreMap":32},[37,1971,1972],{"class":39,"line":40},[37,1973,1974],{"class":51},"\u002F\u002F String\n",[37,1976,1977,1979,1982,1984,1986,1989,1991,1994,1997,1999,2001,2003,2005,2008,2010],{"class":39,"line":105},[37,1978,286],{"class":74},[37,1980,1981],{"class":47},"hello world",[37,1983,286],{"class":74},[37,1985,92],{"class":74},[37,1987,1988],{"class":95},"indexOf",[37,1990,192],{"class":74},[37,1992,1993],{"class":74},"'",[37,1995,1996],{"class":47},"o",[37,1998,1993],{"class":74},[37,2000,321],{"class":74},[37,2002,1905],{"class":121},[37,2004,321],{"class":74},[37,2006,2007],{"class":121}," 8",[37,2009,544],{"class":74},[37,2011,2012],{"class":51},"        \u002F\u002F search within a range\n",[37,2014,2015,2018,2021,2023,2026,2028,2030,2032,2034,2036,2039,2041],{"class":39,"line":146},[37,2016,2017],{"class":70},"new",[37,2019,2020],{"class":95}," StringBuilder",[37,2022,306],{"class":74},[37,2024,2025],{"class":95},"repeat",[37,2027,192],{"class":74},[37,2029,286],{"class":74},[37,2031,1303],{"class":47},[37,2033,286],{"class":74},[37,2035,321],{"class":74},[37,2037,2038],{"class":121}," 20",[37,2040,544],{"class":74},[37,2042,2043],{"class":51},"     \u002F\u002F \"--------------------\"\n",[37,2045,2046],{"class":39,"line":162},[37,2047,469],{"emptyLinePlaceholder":468},[37,2049,2050],{"class":39,"line":181},[37,2051,2052],{"class":51},"\u002F\u002F Math\n",[37,2054,2055,2058,2060,2063,2065,2068,2070,2072,2074,2076,2078],{"class":39,"line":214},[37,2056,2057],{"class":82},"Math",[37,2059,92],{"class":74},[37,2061,2062],{"class":95},"clamp",[37,2064,192],{"class":74},[37,2066,2067],{"class":121},"150",[37,2069,321],{"class":74},[37,2071,122],{"class":121},[37,2073,321],{"class":74},[37,2075,762],{"class":121},[37,2077,544],{"class":74},[37,2079,2080],{"class":51},"                 \u002F\u002F 100\n",[37,2082,2083],{"class":39,"line":225},[37,2084,469],{"emptyLinePlaceholder":468},[37,2086,2087],{"class":39,"line":231},[37,2088,2089],{"class":51},"\u002F\u002F Character\n",[37,2091,2092,2095,2097,2100,2102,2105,2107],{"class":39,"line":237},[37,2093,2094],{"class":82},"Character",[37,2096,92],{"class":74},[37,2098,2099],{"class":95},"isEmoji",[37,2101,192],{"class":74},[37,2103,2104],{"class":121},"0x1F600",[37,2106,544],{"class":74},[37,2108,2109],{"class":51},"              \u002F\u002F true\n",[15,2111,2112,2113,2116,2117,2120],{},"Java 21 also brought ",[22,2114,2115],{},"Generational ZGC",": worth trying with ",[34,2118,2119],{},"-XX:+UseZGC -XX:+ZGenerational"," for latency-sensitive apps.",[10,2122,2124],{"id":2123},"_8-preview-features","8. Preview features",[15,2126,2127,2128,2131],{},"Some features exist in Java 21 only as previews and are enabled with ",[34,2129,2130],{},"--enable-preview",": string templates (later withdrawn), unnamed classes and instance main methods, structured concurrency, scoped values. Don't rely on preview features in production code; they can change or be removed in the next release.",[27,2133,2135],{"className":29,"code":2134,"language":31,"meta":32,"style":32},"javac --release 21 --enable-preview Main.java\njava --enable-preview Main\n",[34,2136,2137,2154],{"__ignoreMap":32},[37,2138,2139,2142,2145,2148,2151],{"class":39,"line":40},[37,2140,2141],{"class":43},"javac",[37,2143,2144],{"class":47}," --release",[37,2146,2147],{"class":121}," 21",[37,2149,2150],{"class":47}," --enable-preview",[37,2152,2153],{"class":47}," Main.java\n",[37,2155,2156,2158,2160],{"class":39,"line":105},[37,2157,44],{"class":43},[37,2159,2150],{"class":47},[37,2161,2162],{"class":47}," Main\n",[10,2164,2166],{"id":2165},"_9-moving-from-java-17-to-21","9. Moving from Java 17 to 21",[2168,2169,2170,2183],"table",{},[2171,2172,2173],"thead",{},[2174,2175,2176,2180],"tr",{},[2177,2178,2179],"th",{},"Step",[2177,2181,2182],{},"Note",[2184,2185,2186,2195,2205,2215,2223,2231],"tbody",{},[2174,2187,2188,2192],{},[2189,2190,2191],"td",{},"JDK",[2189,2193,2194],{},"Install an OpenJDK 21 distribution such as Temurin, Corretto or Zulu",[2174,2196,2197,2200],{},[2189,2198,2199],{},"Maven",[2189,2201,2202],{},[34,2203,2204],{},"\u003Cmaven.compiler.release>21\u003C\u002Fmaven.compiler.release>",[2174,2206,2207,2210],{},[2189,2208,2209],{},"Gradle",[2189,2211,2212],{},[34,2213,2214],{},"java { toolchain { languageVersion = JavaLanguageVersion.of(21) } }",[2174,2216,2217,2220],{},[2189,2218,2219],{},"Spring Boot",[2189,2221,2222],{},"3.2+ for virtual thread support",[2174,2224,2225,2228],{},[2189,2226,2227],{},"Lombok, Mockito, ByteBuddy",[2189,2229,2230],{},"Upgrade to current versions that support Java 21",[2174,2232,2233,2236],{},[2189,2234,2235],{},"Docker",[2189,2237,2238,2239],{},"A base image such as ",[34,2240,2241],{},"eclipse-temurin:21-jre",[10,2243,2245],{"id":2244},"conclusion","Conclusion",[15,2247,2248,2249,2251],{},"Java 21 brings several long-awaited features together in one LTS release. You can model data more clearly with records and sealed types, drop ",[34,2250,957],{},"\u002Fcast chains with pattern matching, and get high concurrency with virtual threads without switching to reactive code. If you're on Java 17, the upgrade is usually just a few dependency bumps; if you're on Java 8\u002F11, this is the best release to jump to.",[2253,2254,2255],"style",{},"html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}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 .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}",{"title":32,"searchDepth":105,"depth":105,"links":2257},[2258,2259,2260,2261,2262,2263,2264,2265,2266,2267,2268],{"id":12,"depth":105,"text":13},{"id":55,"depth":105,"text":56},{"id":400,"depth":105,"text":401},{"id":671,"depth":105,"text":672},{"id":1028,"depth":105,"text":1029},{"id":1413,"depth":105,"text":1414},{"id":1682,"depth":105,"text":1683},{"id":1963,"depth":105,"text":1964},{"id":2123,"depth":105,"text":2124},{"id":2165,"depth":105,"text":2166},{"id":2244,"depth":105,"text":2245},"2026-11-01","The Java 21 LTS features that change day-to-day code the most — virtual threads, records, switch pattern matching, record patterns, sealed classes and sequenced collections.","md",{},"\u002Fen\u002Fblog\u002Fjava-21-features",{"title":5,"description":2270},"en\u002Fblog\u002Fjava-21-features",[44,2277],"guide","\u002Fblog\u002Fjava-21-features","XWePgSj7aNNBc4iA5PvrPqBVUM8ChZ2EikSEtcsyTbU",[2281,2288,2294],{"path":2282,"title":2283,"description":2284,"date":2285,"tags":2286},"\u002Fen\u002Fblog\u002Finstall-java-on-centos-7-rhel-7","Installing Java on CentOS 7 & Red Hat Enterprise Linux 7","Installing Java 11 (OpenJDK) on CentOS 7 and RHEL 7 with yum, plus picking an alternative version — a short step-by-step guide.","2019-11-08",[44,2287],"linux",{"path":2289,"title":2290,"description":2291,"date":2292,"tags":2293},"\u002Fen\u002Fblog\u002Fjava-11-12-13-and-beyond","Java 11-12-13 and Beyond","What's new in Java 11 and later: the new release cadence and the standout features.","2019-02-13",[44],{"path":2295,"title":2296,"description":2297,"date":2298,"tags":2299},"\u002Fen\u002Fblog\u002Fspring-security-primefaces-redirect-issue-fix","Fixing the Spring Security + PrimeFaces Redirect Issue","The fix for the redirect problem that appears when using Spring Security with PrimeFaces.","2015-05-15",[44,2300,2301,2302],"jsf","primefaces","spring",1793491380644]