[{"data":1,"prerenderedAt":1393},["ShallowReactive",2],{"blog-\u002Fblog\u002Fjava-try-with-resources":3},{"id":4,"title":5,"body":6,"description":1379,"difficulty":1380,"extension":1381,"framework":1382,"frameworkSlug":68,"meta":1383,"navigation":1163,"order":94,"path":1384,"qaPath":1385,"seo":1386,"stem":1387,"subtopic":1388,"topic":1389,"topicSlug":1390,"updated":1391,"__hash__":1392},"blog\u002Fblog\u002Fjava-try-with-resources.md","Java Try-With-Resources — Automatic Resource Management Explained",{"type":7,"value":8,"toc":1366},"minimark",[9,14,41,45,63,191,216,220,236,278,308,312,340,381,405,409,419,617,637,641,659,725,740,744,768,881,901,905,928,982,993,997,1007,1194,1221,1225,1248,1306,1319,1323,1362],[10,11,13],"h2",{"id":12},"the-leak-you-keep-writing","The leak you keep writing",[15,16,17,18,22,23,26,27,31,32,36,37,40],"p",{},"Every file, socket, and database connection you open holds an operating-system handle\nthat won't free itself. Before Java 7 the only way to release it reliably was a ",[19,20,21],"code",{},"finally","\nblock — and that block was a magnet for bugs. You forgot it, you null-checked it wrong, or\nworst of all, a failure in ",[19,24,25],{},"close()"," quietly swallowed the ",[28,29,30],"em",{},"real"," exception your code threw.\n",[33,34,35],"strong",{},"Try-with-resources"," (Java 7) turns that whole ritual into a few characters of syntax and,\ncritically, gets the exception handling ",[28,38,39],{},"more"," correct than most hand-written cleanup ever\ndid. This guide is about how it works, not just how to type it.",[10,42,44],{"id":43},"the-manual-finally-problem","The manual-finally problem",[15,46,47,48,51,52,55,56,58,59,62],{},"Here is the pattern try-with-resources replaces. The resource has to be declared ",[28,49,50],{},"outside","\nthe ",[19,53,54],{},"try"," so ",[19,57,21],{}," can see it, which forces a ",[19,60,61],{},"null"," initializer and a null check,\nbecause the constructor on line two could itself throw before the assignment completes.",[64,65,70],"pre",{"className":66,"code":67,"language":68,"meta":69,"style":69},"language-java shiki shiki-themes github-light github-dark","BufferedReader br = null;\ntry {\n    br = new BufferedReader(new FileReader(\"a.txt\"));\n    return br.readLine();\n} finally {\n    if (br != null) br.close();   \u002F\u002F close() can ALSO throw IOException\n}\n","java","",[19,71,72,92,100,133,148,158,185],{"__ignoreMap":69},[73,74,77,81,85,89],"span",{"class":75,"line":76},"line",1,[73,78,80],{"class":79},"sVt8B","BufferedReader br ",[73,82,84],{"class":83},"szBVR","=",[73,86,88],{"class":87},"sj4cs"," null",[73,90,91],{"class":79},";\n",[73,93,95,97],{"class":75,"line":94},2,[73,96,54],{"class":83},[73,98,99],{"class":79}," {\n",[73,101,103,106,108,111,115,118,121,124,126,130],{"class":75,"line":102},3,[73,104,105],{"class":79},"    br ",[73,107,84],{"class":83},[73,109,110],{"class":83}," new",[73,112,114],{"class":113},"sScJk"," BufferedReader",[73,116,117],{"class":79},"(",[73,119,120],{"class":83},"new",[73,122,123],{"class":113}," FileReader",[73,125,117],{"class":79},[73,127,129],{"class":128},"sZZnC","\"a.txt\"",[73,131,132],{"class":79},"));\n",[73,134,136,139,142,145],{"class":75,"line":135},4,[73,137,138],{"class":83},"    return",[73,140,141],{"class":79}," br.",[73,143,144],{"class":113},"readLine",[73,146,147],{"class":79},"();\n",[73,149,151,154,156],{"class":75,"line":150},5,[73,152,153],{"class":79},"} ",[73,155,21],{"class":83},[73,157,99],{"class":79},[73,159,161,164,167,170,172,175,178,181],{"class":75,"line":160},6,[73,162,163],{"class":83},"    if",[73,165,166],{"class":79}," (br ",[73,168,169],{"class":83},"!=",[73,171,88],{"class":87},[73,173,174],{"class":79},") br.",[73,176,177],{"class":113},"close",[73,179,180],{"class":79},"();   ",[73,182,184],{"class":183},"sJ8bj","\u002F\u002F close() can ALSO throw IOException\n",[73,186,188],{"class":75,"line":187},7,[73,189,190],{"class":79},"}\n",[15,192,193,194,197,198,201,202,204,205,207,208,211,212,215],{},"That last comment is the trap. If ",[19,195,196],{},"readLine()"," throws ",[28,199,200],{},"and"," ",[19,203,25],{}," throws, the\nexception from ",[19,206,25],{}," propagates and the original — the one describing what actually\nwent wrong — is ",[33,209,210],{},"lost forever",". Add a second resource and you nest two ",[19,213,214],{},"try\u002Ffinally","\nblocks to guarantee the outer one closes even when the inner constructor fails. The\nboilerplate grows faster than the logic it guards.",[10,217,219],{"id":218},"autocloseable-the-one-method-that-opts-you-in","AutoCloseable: the one method that opts you in",[15,221,222,223,228,229,232,233,235],{},"Any object can become a managed resource by implementing ",[33,224,225],{},[19,226,227],{},"AutoCloseable",", a\nsingle-method interface added to ",[19,230,231],{},"java.lang"," in Java 7. Only types that implement it (or\nits subtype) are legal inside the ",[19,234,54],{}," parentheses; anything else is a compile error.",[64,237,239],{"className":66,"code":238,"language":68,"meta":69,"style":69},"public interface AutoCloseable {\n    void close() throws Exception;   \u002F\u002F broadest checked exception allowed\n}\n",[19,240,241,254,274],{"__ignoreMap":69},[73,242,243,246,249,252],{"class":75,"line":76},[73,244,245],{"class":83},"public",[73,247,248],{"class":83}," interface",[73,250,251],{"class":113}," AutoCloseable",[73,253,99],{"class":79},[73,255,256,259,262,265,268,271],{"class":75,"line":94},[73,257,258],{"class":83},"    void",[73,260,261],{"class":113}," close",[73,263,264],{"class":79},"() ",[73,266,267],{"class":83},"throws",[73,269,270],{"class":79}," Exception;   ",[73,272,273],{"class":183},"\u002F\u002F broadest checked exception allowed\n",[73,275,276],{"class":75,"line":102},[73,277,190],{"class":79},[15,279,280,282,283,286,287,289,290,293,294,297,298,301,302,304,305,307],{},[19,281,25],{}," is declared to throw ",[19,284,285],{},"Exception"," because ",[19,288,227],{}," is the ",[28,291,292],{},"general","\nabstraction — a JNI handle or a DB connection should be free to report any failure. An\nimplementation is always allowed to ",[33,295,296],{},"narrow"," that: override it as ",[19,299,300],{},"throws IOException",",\nor, better still, ",[19,303,267],{}," nothing at all. A ",[19,306,25],{}," that cannot fail is dramatically\neasier to reason about, so prefer narrowing whenever your cleanup genuinely can't error.",[10,309,311],{"id":310},"closeable-and-why-it-predates-the-feature","Closeable, and why it predates the feature",[15,313,314,317,318,321,322,327,328,331,332,335,336,339],{},[19,315,316],{},"Closeable"," (Java 5, in ",[19,319,320],{},"java.io",") existed years before try-with-resources, built for I\u002FO\nstreams. Java 7 ",[33,323,324,325],{},"retrofitted it to extend ",[19,326,227],{},", so every existing\n",[19,329,330],{},"InputStream",", ",[19,333,334],{},"Reader",", and ",[19,337,338],{},"Writer"," instantly became a valid resource with no code\nchanges — a quietly brilliant bit of backward compatibility.",[64,341,343],{"className":66,"code":342,"language":68,"meta":69,"style":69},"public interface Closeable extends AutoCloseable {\n    void close() throws IOException;   \u002F\u002F narrowed; and MUST be idempotent\n}\n",[19,344,345,361,377],{"__ignoreMap":69},[73,346,347,349,351,354,357,359],{"class":75,"line":76},[73,348,245],{"class":83},[73,350,248],{"class":83},[73,352,353],{"class":113}," Closeable",[73,355,356],{"class":83}," extends",[73,358,251],{"class":113},[73,360,99],{"class":79},[73,362,363,365,367,369,371,374],{"class":75,"line":94},[73,364,258],{"class":83},[73,366,261],{"class":113},[73,368,264],{"class":79},[73,370,267],{"class":83},[73,372,373],{"class":79}," IOException;   ",[73,375,376],{"class":183},"\u002F\u002F narrowed; and MUST be idempotent\n",[73,378,379],{"class":75,"line":102},[73,380,190],{"class":79},[15,382,383,384,387,388,391,392,395,396,398,399,401,402,404],{},"Two contract differences matter. ",[19,385,386],{},"Closeable.close()"," narrows the throw to ",[19,389,390],{},"IOException",",\nand it ",[33,393,394],{},"must be idempotent"," — calling it twice has no extra effect and never throws.\nThat second rule exists because a stream can be closed both explicitly by your code and\nagain automatically by the ",[19,397,54],{}," statement; the redundant call must be harmless. Reach for\n",[19,400,316],{}," when your resource is I\u002FO-flavoured, ",[19,403,227],{}," for everything else.",[10,406,408],{"id":407},"what-the-compiler-actually-generates","What the compiler actually generates",[15,410,411,412,415,416,418],{},"Try-with-resources is ",[33,413,414],{},"syntactic sugar",". The compiler desugars it into an ordinary\n",[19,417,214],{}," with exception bookkeeping baked in. Seeing the expansion explains every\nbehaviour that follows.",[64,420,422],{"className":66,"code":421,"language":68,"meta":69,"style":69},"\u002F\u002F try (Resource r = ...) { body }  becomes roughly:\nResource r = ...;\nThrowable primary = null;\ntry {\n    body;\n} catch (Throwable t) {\n    primary = t;\n    throw t;\n} finally {\n    if (r != null) {                          \u002F\u002F null-safe close\n        if (primary != null) {\n            try { r.close(); }\n            catch (Throwable sup) { primary.addSuppressed(sup); }  \u002F\u002F attach, don't replace\n        } else {\n            r.close();                        \u002F\u002F body was clean; let close throw freely\n        }\n    }\n}\n",[19,423,424,429,439,450,456,461,478,488,496,505,523,538,552,575,586,600,606,612],{"__ignoreMap":69},[73,425,426],{"class":75,"line":76},[73,427,428],{"class":183},"\u002F\u002F try (Resource r = ...) { body }  becomes roughly:\n",[73,430,431,434,436],{"class":75,"line":94},[73,432,433],{"class":79},"Resource r ",[73,435,84],{"class":83},[73,437,438],{"class":79}," ...;\n",[73,440,441,444,446,448],{"class":75,"line":102},[73,442,443],{"class":79},"Throwable primary ",[73,445,84],{"class":83},[73,447,88],{"class":87},[73,449,91],{"class":79},[73,451,452,454],{"class":75,"line":135},[73,453,54],{"class":83},[73,455,99],{"class":79},[73,457,458],{"class":75,"line":150},[73,459,460],{"class":79},"    body;\n",[73,462,463,465,468,471,475],{"class":75,"line":160},[73,464,153],{"class":79},[73,466,467],{"class":83},"catch",[73,469,470],{"class":79}," (Throwable ",[73,472,474],{"class":473},"s4XuR","t",[73,476,477],{"class":79},") {\n",[73,479,480,483,485],{"class":75,"line":187},[73,481,482],{"class":79},"    primary ",[73,484,84],{"class":83},[73,486,487],{"class":79}," t;\n",[73,489,491,494],{"class":75,"line":490},8,[73,492,493],{"class":83},"    throw",[73,495,487],{"class":79},[73,497,499,501,503],{"class":75,"line":498},9,[73,500,153],{"class":79},[73,502,21],{"class":83},[73,504,99],{"class":79},[73,506,508,510,513,515,517,520],{"class":75,"line":507},10,[73,509,163],{"class":83},[73,511,512],{"class":79}," (r ",[73,514,169],{"class":83},[73,516,88],{"class":87},[73,518,519],{"class":79},") {                          ",[73,521,522],{"class":183},"\u002F\u002F null-safe close\n",[73,524,526,529,532,534,536],{"class":75,"line":525},11,[73,527,528],{"class":83},"        if",[73,530,531],{"class":79}," (primary ",[73,533,169],{"class":83},[73,535,88],{"class":87},[73,537,477],{"class":79},[73,539,541,544,547,549],{"class":75,"line":540},12,[73,542,543],{"class":83},"            try",[73,545,546],{"class":79}," { r.",[73,548,177],{"class":113},[73,550,551],{"class":79},"(); }\n",[73,553,555,558,560,563,566,569,572],{"class":75,"line":554},13,[73,556,557],{"class":83},"            catch",[73,559,470],{"class":79},[73,561,562],{"class":473},"sup",[73,564,565],{"class":79},") { primary.",[73,567,568],{"class":113},"addSuppressed",[73,570,571],{"class":79},"(sup); }  ",[73,573,574],{"class":183},"\u002F\u002F attach, don't replace\n",[73,576,578,581,584],{"class":75,"line":577},14,[73,579,580],{"class":79},"        } ",[73,582,583],{"class":83},"else",[73,585,99],{"class":79},[73,587,589,592,594,597],{"class":75,"line":588},15,[73,590,591],{"class":79},"            r.",[73,593,177],{"class":113},[73,595,596],{"class":79},"();                        ",[73,598,599],{"class":183},"\u002F\u002F body was clean; let close throw freely\n",[73,601,603],{"class":75,"line":602},16,[73,604,605],{"class":79},"        }\n",[73,607,609],{"class":75,"line":608},17,[73,610,611],{"class":79},"    }\n",[73,613,615],{"class":75,"line":614},18,[73,616,190],{"class":79},[15,618,619,620,622,623,626,627,629,630,633,634,636],{},"The close still lives in a ",[19,621,21],{},", but it is a ",[28,624,625],{},"smart"," one. When the body has already\nfailed, a failure from ",[19,628,25],{}," is ",[33,631,632],{},"attached"," to the original rather than thrown over\nit. That single ",[19,635,568],{}," call is the whole reason try-with-resources is safer than\nanything you'd write by hand.",[10,638,640],{"id":639},"reverse-close-order-and-multiple-resources","Reverse close order and multiple resources",[15,642,643,644,647,648,651,652,655,656,658],{},"Declare several resources separated by semicolons and each is closed independently. They\nclose in the ",[33,645,646],{},"reverse order of declaration"," — last opened, first closed — which is\nexactly what dependency stacking requires: a ",[19,649,650],{},"BufferedWriter"," wrapping a ",[19,653,654],{},"FileWriter"," must\nflush and close before the ",[19,657,654],{}," it sits on top of.",[64,660,662],{"className":66,"code":661,"language":68,"meta":69,"style":69},"try (FileInputStream in = new FileInputStream(\"src.txt\");\n     FileOutputStream out = new FileOutputStream(\"dst.txt\")) {\n    in.transferTo(out);\n}   \u002F\u002F close order: out first, then in\n",[19,663,664,686,706,717],{"__ignoreMap":69},[73,665,666,668,671,673,675,678,680,683],{"class":75,"line":76},[73,667,54],{"class":83},[73,669,670],{"class":79}," (FileInputStream in ",[73,672,84],{"class":83},[73,674,110],{"class":83},[73,676,677],{"class":113}," FileInputStream",[73,679,117],{"class":79},[73,681,682],{"class":128},"\"src.txt\"",[73,684,685],{"class":79},");\n",[73,687,688,691,693,695,698,700,703],{"class":75,"line":94},[73,689,690],{"class":79},"     FileOutputStream out ",[73,692,84],{"class":83},[73,694,110],{"class":83},[73,696,697],{"class":113}," FileOutputStream",[73,699,117],{"class":79},[73,701,702],{"class":128},"\"dst.txt\"",[73,704,705],{"class":79},")) {\n",[73,707,708,711,714],{"class":75,"line":102},[73,709,710],{"class":79},"    in.",[73,712,713],{"class":113},"transferTo",[73,715,716],{"class":79},"(out);\n",[73,718,719,722],{"class":75,"line":135},[73,720,721],{"class":79},"}   ",[73,723,724],{"class":183},"\u002F\u002F close order: out first, then in\n",[15,726,727,728,731,732,735,736,739],{},"Each close is guarded on its own. If closing ",[19,729,730],{},"out"," throws, the runtime ",[28,733,734],{},"still"," closes\n",[19,737,738],{},"in"," — there is no path where a failing close abandons the resources beneath it. The same\nguarantee covers construction: resources initialize left to right, and if a later\nconstructor throws, every resource already opened is closed in reverse before the exception\nescapes. Nothing leaks, even half-built.",[10,741,743],{"id":742},"suppressed-exceptions-and-the-lost-exception-bug","Suppressed exceptions and the lost-exception bug",[15,745,746,747,201,749,752,753,756,757,759,760,763,764,767],{},"This is the conceptual core. When the body throws and a ",[19,748,25],{},[28,750,751],{},"also"," throws,\ntry-with-resources propagates the ",[33,754,755],{},"body's"," exception — the useful one — and tucks the\n",[19,758,25],{}," exception onto it as a ",[33,761,762],{},"suppressed"," exception, reachable via\n",[19,765,766],{},"Throwable.getSuppressed()",".",[64,769,771],{"className":66,"code":770,"language":68,"meta":69,"style":69},"try (var r = new FlakyResource()) {\n    throw new RuntimeException(\"body failed\");   \u002F\u002F becomes the PRIMARY\n}   \u002F\u002F r.close() also throws -> attached as suppressed, not lost\ncatch (Exception e) {\n    for (Throwable s : e.getSuppressed())\n        System.out.println(\"suppressed: \" + s);  \u002F\u002F the close() failure\n}\n",[19,772,773,796,816,823,835,855,877],{"__ignoreMap":69},[73,774,775,777,780,783,786,788,790,793],{"class":75,"line":76},[73,776,54],{"class":83},[73,778,779],{"class":79}," (",[73,781,782],{"class":83},"var",[73,784,785],{"class":79}," r ",[73,787,84],{"class":83},[73,789,110],{"class":83},[73,791,792],{"class":113}," FlakyResource",[73,794,795],{"class":79},"()) {\n",[73,797,798,800,802,805,807,810,813],{"class":75,"line":94},[73,799,493],{"class":83},[73,801,110],{"class":83},[73,803,804],{"class":113}," RuntimeException",[73,806,117],{"class":79},[73,808,809],{"class":128},"\"body failed\"",[73,811,812],{"class":79},");   ",[73,814,815],{"class":183},"\u002F\u002F becomes the PRIMARY\n",[73,817,818,820],{"class":75,"line":102},[73,819,721],{"class":79},[73,821,822],{"class":183},"\u002F\u002F r.close() also throws -> attached as suppressed, not lost\n",[73,824,825,827,830,833],{"class":75,"line":135},[73,826,467],{"class":83},[73,828,829],{"class":79}," (Exception ",[73,831,832],{"class":473},"e",[73,834,477],{"class":79},[73,836,837,840,843,846,849,852],{"class":75,"line":150},[73,838,839],{"class":83},"    for",[73,841,842],{"class":79}," (Throwable s ",[73,844,845],{"class":83},":",[73,847,848],{"class":79}," e.",[73,850,851],{"class":113},"getSuppressed",[73,853,854],{"class":79},"())\n",[73,856,857,860,863,865,868,871,874],{"class":75,"line":160},[73,858,859],{"class":79},"        System.out.",[73,861,862],{"class":113},"println",[73,864,117],{"class":79},[73,866,867],{"class":128},"\"suppressed: \"",[73,869,870],{"class":83}," +",[73,872,873],{"class":79}," s);  ",[73,875,876],{"class":183},"\u002F\u002F the close() failure\n",[73,878,879],{"class":75,"line":187},[73,880,190],{"class":79},[15,882,883,884,886,887,889,890,893,894,897,898,900],{},"Compare that to the hand-written ",[19,885,21],{},", where an exception from the ",[19,888,21],{}," block\n",[33,891,892],{},"replaces"," the body's — the genuine cause vanishes and you debug the cleanup failure\ninstead of the real one. Try-with-resources inverts the priority: body wins, cleanup rides\nalong. The stack trace even prints the extras under a ",[19,895,896],{},"Suppressed:"," heading. Note the flip\nside: if the body succeeds and only ",[19,899,25],{}," throws, there's no primary to attach to, so\nthat exception propagates normally — a failed final flush is a real error, not a footnote.",[10,902,904],{"id":903},"the-java-9-effectively-final-form","The Java 9 effectively-final form",[15,906,907,908,911,912,915,916,919,920,923,924,927],{},"Originally you had to ",[28,909,910],{},"declare"," the resource inside the parentheses, leading to clumsy\nre-declarations like ",[19,913,914],{},"try (Reader r2 = r1)",". Java 9 lets you name an ",[33,917,918],{},"already-declared\nvariable",", provided it is ",[19,921,922],{},"final"," or ",[33,925,926],{},"effectively final"," (never reassigned after\ninitialization).",[64,929,931],{"className":66,"code":930,"language":68,"meta":69,"style":69},"BufferedReader br = new BufferedReader(new FileReader(\"a.txt\"));\ntry (br) {                       \u002F\u002F Java 9+: reference, don't redeclare\n    return br.readLine();\n}   \u002F\u002F br is still closed automatically before the method returns\n",[19,932,933,955,965,975],{"__ignoreMap":69},[73,934,935,937,939,941,943,945,947,949,951,953],{"class":75,"line":76},[73,936,80],{"class":79},[73,938,84],{"class":83},[73,940,110],{"class":83},[73,942,114],{"class":113},[73,944,117],{"class":79},[73,946,120],{"class":83},[73,948,123],{"class":113},[73,950,117],{"class":79},[73,952,129],{"class":128},[73,954,132],{"class":79},[73,956,957,959,962],{"class":75,"line":94},[73,958,54],{"class":83},[73,960,961],{"class":79}," (br) {                       ",[73,963,964],{"class":183},"\u002F\u002F Java 9+: reference, don't redeclare\n",[73,966,967,969,971,973],{"class":75,"line":102},[73,968,138],{"class":83},[73,970,141],{"class":79},[73,972,144],{"class":113},[73,974,147],{"class":79},[73,976,977,979],{"class":75,"line":135},[73,978,721],{"class":79},[73,980,981],{"class":183},"\u002F\u002F br is still closed automatically before the method returns\n",[15,983,984,985,988,989,992],{},"The variable must be stable so the runtime closes the exact object it managed; reassign it\nand the compiler rejects the code. Every exit path — fall-through, early ",[19,986,987],{},"return",",\n",[19,990,991],{},"break",", or a thrown exception — runs the generated close first, so the resource is gone\nbefore control actually leaves the block.",[10,994,996],{"id":995},"writing-your-own-autocloseable","Writing your own AutoCloseable",[15,998,999,1000,1002,1003,1006],{},"The feature isn't only for files. Anything with a clear \"enter, then guaranteed exit\" shape\nfits — timers, locks, transactions, logging context. Implement ",[19,1001,25],{},", make it\n",[33,1004,1005],{},"idempotent"," with a guard flag, and avoid throwing from it where you can.",[64,1008,1010],{"className":66,"code":1009,"language":68,"meta":69,"style":69},"class Timer implements AutoCloseable {\n    private final long start = System.nanoTime();\n    private boolean closed = false;\n    @Override public void close() {              \u002F\u002F narrowed: throws nothing\n        if (closed) return;                      \u002F\u002F idempotent guard\n        closed = true;\n        System.out.println(\"took \" + (System.nanoTime() - start) + \"ns\");\n    }\n}\n\ntry (var t = new Timer()) { doWork(); }          \u002F\u002F elapsed time printed on exit\n",[19,1011,1012,1027,1051,1068,1090,1105,1117,1151,1155,1159,1165],{"__ignoreMap":69},[73,1013,1014,1017,1020,1023,1025],{"class":75,"line":76},[73,1015,1016],{"class":83},"class",[73,1018,1019],{"class":113}," Timer",[73,1021,1022],{"class":83}," implements",[73,1024,251],{"class":113},[73,1026,99],{"class":79},[73,1028,1029,1032,1035,1038,1041,1043,1046,1049],{"class":75,"line":94},[73,1030,1031],{"class":83},"    private",[73,1033,1034],{"class":83}," final",[73,1036,1037],{"class":83}," long",[73,1039,1040],{"class":79}," start ",[73,1042,84],{"class":83},[73,1044,1045],{"class":79}," System.",[73,1047,1048],{"class":113},"nanoTime",[73,1050,147],{"class":79},[73,1052,1053,1055,1058,1061,1063,1066],{"class":75,"line":102},[73,1054,1031],{"class":83},[73,1056,1057],{"class":83}," boolean",[73,1059,1060],{"class":79}," closed ",[73,1062,84],{"class":83},[73,1064,1065],{"class":87}," false",[73,1067,91],{"class":79},[73,1069,1070,1073,1076,1079,1082,1084,1087],{"class":75,"line":135},[73,1071,1072],{"class":79},"    @",[73,1074,1075],{"class":83},"Override",[73,1077,1078],{"class":83}," public",[73,1080,1081],{"class":83}," void",[73,1083,261],{"class":113},[73,1085,1086],{"class":79},"() {              ",[73,1088,1089],{"class":183},"\u002F\u002F narrowed: throws nothing\n",[73,1091,1092,1094,1097,1099,1102],{"class":75,"line":150},[73,1093,528],{"class":83},[73,1095,1096],{"class":79}," (closed) ",[73,1098,987],{"class":83},[73,1100,1101],{"class":79},";                      ",[73,1103,1104],{"class":183},"\u002F\u002F idempotent guard\n",[73,1106,1107,1110,1112,1115],{"class":75,"line":160},[73,1108,1109],{"class":79},"        closed ",[73,1111,84],{"class":83},[73,1113,1114],{"class":87}," true",[73,1116,91],{"class":79},[73,1118,1119,1121,1123,1125,1128,1130,1133,1135,1137,1140,1143,1146,1149],{"class":75,"line":187},[73,1120,859],{"class":79},[73,1122,862],{"class":113},[73,1124,117],{"class":79},[73,1126,1127],{"class":128},"\"took \"",[73,1129,870],{"class":83},[73,1131,1132],{"class":79}," (System.",[73,1134,1048],{"class":113},[73,1136,264],{"class":79},[73,1138,1139],{"class":83},"-",[73,1141,1142],{"class":79}," start) ",[73,1144,1145],{"class":83},"+",[73,1147,1148],{"class":128}," \"ns\"",[73,1150,685],{"class":79},[73,1152,1153],{"class":75,"line":490},[73,1154,611],{"class":79},[73,1156,1157],{"class":75,"line":498},[73,1158,190],{"class":79},[73,1160,1161],{"class":75,"line":507},[73,1162,1164],{"emptyLinePlaceholder":1163},true,"\n",[73,1166,1167,1169,1171,1173,1176,1178,1180,1182,1185,1188,1191],{"class":75,"line":525},[73,1168,54],{"class":83},[73,1170,779],{"class":79},[73,1172,782],{"class":83},[73,1174,1175],{"class":79}," t ",[73,1177,84],{"class":83},[73,1179,110],{"class":83},[73,1181,1019],{"class":113},[73,1183,1184],{"class":79},"()) { ",[73,1186,1187],{"class":113},"doWork",[73,1189,1190],{"class":79},"(); }          ",[73,1192,1193],{"class":183},"\u002F\u002F elapsed time printed on exit\n",[15,1195,1196,1197,1199,1200,1202,1203,331,1206,201,1209,1211,1212,1214,1215,1217,1218,1220],{},"If you append ",[19,1198,467],{},"\u002F",[19,1201,21],{}," clauses to a try-with-resources, remember the ordering:\n",[33,1204,1205],{},"resources close first",[28,1207,1208],{},"then",[19,1210,467],{}," and ",[19,1213,21],{}," run. So a ",[19,1216,467],{}," block sees an\nalready-closed resource and can even handle exceptions thrown by ",[19,1219,25],{}," itself.",[10,1222,1224],{"id":1223},"when-tryfinally-is-still-the-right-tool","When try\u002Ffinally is still the right tool",[15,1226,1227,1228,1230,1231,1233,1234,1237,1238,1240,1241,1244,1245,1247],{},"Try-with-resources only manages objects that implement ",[19,1229,227],{},". For cleanup that\nisn't a closeable resource — resetting a flag, restoring thread-local state — plain\n",[19,1232,214],{}," remains correct. The canonical example is locking. A ",[19,1235,1236],{},"Lock"," is not\n",[19,1239,227],{},", and the acquisition must happen ",[28,1242,1243],{},"before"," the ",[19,1246,54],{},", or a failed acquire\nwould wrongly trigger an unlock.",[64,1249,1251],{"className":66,"code":1250,"language":68,"meta":69,"style":69},"lock.lock();                 \u002F\u002F acquire BEFORE the try\ntry {\n    criticalSection();\n} finally {\n    lock.unlock();           \u002F\u002F try\u002Ffinally, NOT try-with-resources\n}\n",[19,1252,1253,1267,1273,1280,1288,1302],{"__ignoreMap":69},[73,1254,1255,1258,1261,1264],{"class":75,"line":76},[73,1256,1257],{"class":79},"lock.",[73,1259,1260],{"class":113},"lock",[73,1262,1263],{"class":79},"();                 ",[73,1265,1266],{"class":183},"\u002F\u002F acquire BEFORE the try\n",[73,1268,1269,1271],{"class":75,"line":94},[73,1270,54],{"class":83},[73,1272,99],{"class":79},[73,1274,1275,1278],{"class":75,"line":102},[73,1276,1277],{"class":113},"    criticalSection",[73,1279,147],{"class":79},[73,1281,1282,1284,1286],{"class":75,"line":135},[73,1283,153],{"class":79},[73,1285,21],{"class":83},[73,1287,99],{"class":79},[73,1289,1290,1293,1296,1299],{"class":75,"line":150},[73,1291,1292],{"class":79},"    lock.",[73,1294,1295],{"class":113},"unlock",[73,1297,1298],{"class":79},"();           ",[73,1300,1301],{"class":183},"\u002F\u002F try\u002Ffinally, NOT try-with-resources\n",[73,1303,1304],{"class":75,"line":160},[73,1305,190],{"class":79},[15,1307,1308,1309,1312,1313,1315,1316,1318],{},"You ",[28,1310,1311],{},"can"," wrap a lock in a tiny ",[19,1314,227],{}," that unlocks in ",[19,1317,25],{},", but you must\nstill acquire outside the block. \"When is try-with-resources the wrong tool?\" is a favourite\ninterview question, and this lock idiom is the answer.",[10,1320,1322],{"id":1321},"recap","Recap",[15,1324,1325,1326,1328,1329,1335,1336,1338,1339,1341,1342,1344,1345,1348,1349,1351,1352,1354,1355,1358,1359,1361],{},"Try-with-resources replaces the error-prone manual ",[19,1327,21],{}," with a declaration that\n",[33,1330,1331,1332,1334],{},"closes any ",[19,1333,227],{}," automatically"," on every exit path. Under the hood it desugars\nto a ",[19,1337,214],{}," that null-checks the resource and, crucially, records a ",[19,1340,25],{}," failure\nas a ",[33,1343,762],{}," exception instead of letting it erase the body's — fixing the\nlost-exception bug that plagued hand-written cleanup. Resources close in ",[33,1346,1347],{},"reverse order",",\neven when a later constructor throws; ",[19,1350,316],{}," extends ",[19,1353,227],{}," and demands an\nidempotent close; Java 9 added the ",[33,1356,1357],{},"effectively-final"," form. Write your own resources for\nany scoped concern, and keep ",[19,1360,214],{}," for non-closeable teardown like lock release.",[1363,1364,1365],"style",{},"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 .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}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}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 .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}",{"title":69,"searchDepth":94,"depth":94,"links":1367},[1368,1369,1370,1371,1372,1373,1374,1375,1376,1377,1378],{"id":12,"depth":94,"text":13},{"id":43,"depth":94,"text":44},{"id":218,"depth":94,"text":219},{"id":310,"depth":94,"text":311},{"id":407,"depth":94,"text":408},{"id":639,"depth":94,"text":640},{"id":742,"depth":94,"text":743},{"id":903,"depth":94,"text":904},{"id":995,"depth":94,"text":996},{"id":1223,"depth":94,"text":1224},{"id":1321,"depth":94,"text":1322},"How Java try-with-resources works under the hood — AutoCloseable and Closeable, compiler desugaring, reverse close ordering, suppressed exceptions, the effectively-final form, and when to still reach for try\u002Ffinally.","medium","md","Java",{},"\u002Fblog\u002Fjava-try-with-resources","\u002Fjava\u002Fexceptions\u002Ftry-with-resources",{"title":5,"description":1379},"blog\u002Fjava-try-with-resources","try-with-resources","Exceptions","exceptions","2026-06-20","Uf2NQobVEFYo-I-DeS3ASyzxstIi9eRaPLr3JWVKiNg",1782244089972]