<div dir="ltr"><div dir="auto"><div>Hi everyone. This is a really good idea to simplify such nested code. Here is 2 points I noted, if I may.</div><div><br></div><div>1. About scope management, I have noted something that might help (I am not sure, since this is my second participation to JEP while I read the whole history of this mail I find this example useful) : </div><div><br></div><div>In csharp / golang and rust, this resource management is done via scope. Usually brackets or space in fsharp.<br>To simplify the nested try-resource in java, we might remove brackets which explicitly indicate the scope.<br>If at the same time your declare variables combined to try-resources / using in csharp it cannot works since scope using brackets can be simplified using the one line scope feature.<br><br></div><div>So if I translate this pseudo java code :<br> ```java</div><div>public class example1 {<br> public static void main(String... args) throws<br>FileNotFoundException, IOException {<br> try (BufferedReader reader = new BufferedReader(new<br> FileReader("studentName.txt"))) {<br> String studentName = "not found"; <br> /* Variable 'studentName' is only alive in the scope of<br> try-with-resources statement. */<br><br> while ((studentName = reader.readLine()) != null) {<br> break;<br> }<br> }<br><br> System.out.println(studentName);<br> /* Variable 'studentName' cannot be resolved here. */<br> }<br> }<br>```</div><div><br></div><div>to a simplified csharp working version (autocloseable is IDisposable in csharp and using is just translated to a try finally calling dispose in the finally block) : </div><div>```csharp</div><div><pre style="color:rgb(0,0,0)">using System;
public class C {
private class D : IDisposable {
public D()
{
}
public D(IDisposable _):this() {
}
public void Dispose(){
}
}
public void M() {
using (var a = new D())
using (var b = new D(a))
using (var c = new D(b)){
System.Console.WriteLine("hello world");
}
}
}</pre></div><div>```</div><div>But if I try to add more statements between using, it does not work anymore because scope simplication works only for the next line:</div><div>this code will not compile</div><div>```csharp</div><div>using System;<br>public class C {<br> private class D : IDisposable {<br> public D()<br> {<br> }<br> public D(IDisposable _):this() {<br> }<br> <br> public void Dispose(){<br> }<br> }<br> public void M() {<br> using (var a = new D())<br> var x = "hello";<br> var y = "world";<br> using (var b = new D(a2))<br> using (var c = new D(b)){<br> System.Console.WriteLine("hello world"); <br> }<br> }<br>}<br></div><div>```</div><div><br></div><div>but by using a method, only one line and RAII are well managed : </div><div>```csharp</div><div>using System;<br>public class C {<br> private class D : IDisposable {<br> public D()<br> {<br> }<br> public D(IDisposable _):this() {<br> }<br> <br> public void Dispose(){<br> }<br> }<br> private static D build(string _, string _) {<br> return new D();<br> }<br> public void M() {<br> using (var a = new D())<br> using (var b = build("hello", "world"))<br> using (var c = new D(b)){<br> System.Console.WriteLine("hello world"); <br> }<br> }<br>}<br></div><div>```</div><div><br></div><div>2. About execution, exception and lifetime.<br>A problem might occur with the lifetime involving async code and resource lifetime management. I know that in csharp that by using async await does not separate async construction (using continuation like CompletableFuture) and execution of the task and it might be complex to handle resource and exception in such configuration and I am really agree with what
Tzengshinfu mentioned about "less is more". I think that creating a separation thanks to the new virtual threads are closed to what as been done in rust and goland and fsharp where handling such case become trivial.<br>So if the lifecycle is done thanks scope which requires awaiting available results inside the scope, it is not that hard to make like the code was not async from the developper point of view.</div><div><br></div><div>I hope, I did it well, do not hesitate do give me any pointer I missed if you think that the mentioned points have been already manage.<br><br>Have a good day.<br><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Wed, Sep 27, 2023, 23:01 Holo The Sage Wolf <<a href="mailto:holo3146@gmail.com" target="_blank">holo3146@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="auto">Hello Tzengshinfu,<div dir="auto">Unfortunately completely automatic cleanup is not a solved problem, so "as shown bellow" can't work (the 2 main problems are fields and concurrency).</div><div dir="auto"><br></div><div dir="auto">The best we can hope for is to have a set of modifiers to `new` and let the compiler throw a compile time exception if we don't specify the modifier (e.g. `new scoped Buffer()`, `new manual Buffer()`, ...), but this also has problems (it is annoying).</div><div dir="auto"><br></div><div dir="auto">Also the problem if "fluent cleanup" is not the only problem we have with the current TwR.</div><div dir="auto"><br></div><div dir="auto">Because of the complexity of the subject I don't think this discussion will go anywhere in here.</div><div dir="auto">I believe that a separate discussion should be opened in amber-spec-experts, I also don't know the current "free hands" to work on anything in this subject, but this is a different question.</div><br><br><div class="gmail_quote" dir="auto"><div dir="ltr" class="gmail_attr">On Wed, Sep 27, 2023, 11:24 tzengshinfu <<a href="mailto:tzengshinfu@gmail.com" rel="noreferrer noreferrer" target="_blank">tzengshinfu@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Hi, Folks:<br>
<br>
Since I previously used C# (to the extent that I consumed syntactic<br>
sugar until I almost got "syntax diabetes"), I unintentionally brought<br>
my habits into the Java world. However, I now recognize the<br>
differences in their design philosophies.<br>
<br>
In fact, I agree with Tagir's opinion. TWR (Try-With-Resources) is<br>
indeed a more explicit and reliable way of automatic resource cleanup.<br>
However, when I saw JEP 445: Unnamed Classes and Instance Main<br>
Methods, which bears similarities to C# Top-level statements, and<br>
noticed that Java chose Virtual Threads instead of async/await, I<br>
realized that "less is more, simplification is the future direction;<br>
we should make the compiler do more, and we should focus on business<br>
logic. So, wouldn't it be better if we didn't have to manage the<br>
timing of resource release?" That's the basis for my suggestion.<br>
<br>
Holo's opinion is excellent. The awkward thing is that C# chose to<br>
turn the using statement into a using declaration version, while Java<br>
chose to add resource management functionality to try-catch-finally.<br>
So, any modification would break the semantics of try, but I'm also<br>
concerned that since try-with-resources already exists, there may be<br>
little room for further changes in the automatic cleanup mechanism.<br>
<br>
I also agree with Brian's opinion. `defer` might behave unexpectedly<br>
due to different scope levels, and developers might lump logic outside<br>
of resource cleanup into it, leading to dreadful results. Instead of<br>
desiring the delayed execution effect of `defer`, I think we want "a<br>
more automated automatic cleanup mechanism" as shown below:<br>
<br>
```java<br>
public static void main(String... args) throws FileNotFoundException,<br>
IOException {<br>
BufferedReader reader = new BufferedReader(new<br>
FileReader("studentName.txt"));<br>
String studentName = "not found";<br>
<br>
while ((studentName = reader.readLine()) != null) {<br>
break;<br>
}<br>
<br>
System.out.println(studentName);<br>
/* The BufferedReader 'reader' will be automatically cleaned up<br>
before the method exits, even without explicit TWR indication. */<br>
}<br>
```<br>
<br>
Thank you for taking the time to provide thoughtful responses from<br>
various perspectives.<br>
<br>
<br>
/* GET BETTER EVERY DAY */<br>
<br>
<br>
<br>
tzengshinfu <<a href="mailto:tzengshinfu@gmail.com" rel="noreferrer noreferrer noreferrer" target="_blank">tzengshinfu@gmail.com</a>> 於 2023年9月25日 週一 下午2:10寫道:<br>
><br>
> Hi, Folks,<br>
><br>
> Since my last suggestion,<br>
> I've conducted some research and stumbled upon the<br>
> `@Cleanup`[<a href="https://projectlombok.org/features/Cleanup" rel="noreferrer noreferrer noreferrer noreferrer" target="_blank">https://projectlombok.org/features/Cleanup</a>] feature in the<br>
> popular library `Lombok`.<br>
><br>
> Personally, I believe that the existence of this feature indicates a<br>
> certain demand, but it's unfortunate that it requires importing the<br>
> library, which adds to the maintenance complexity.<br>
> I'd like to hear your thoughts on this situation. Is importing Lombok<br>
> the best approach?<br>
><br>
> P.S. This is my second email to the mail list. If there's anything I<br>
> may have overlooked or done incorrectly, please feel free to let me<br>
> know. Thank you.<br>
><br>
> Thanks for your interest and support,<br>
> Hsinfu Tseng<br>
><br>
> /* GET BETTER EVERY DAY */<br>
><br>
><br>
> tzengshinfu <<a href="mailto:tzengshinfu@gmail.com" rel="noreferrer noreferrer noreferrer" target="_blank">tzengshinfu@gmail.com</a>> 於 2023年9月4日 週一 上午11:14寫道:<br>
> ><br>
> > Hi, Folks:<br>
> ><br>
> > Recently, I've been using `JBang` to write some script tools, and I<br>
> > feel that Java has transformed with modern syntax features like<br>
> > `Records`, `Switch Expressions`, and `Pattern Matching`. These newly<br>
> > added language features provide developers with more options in<br>
> > specific scenarios, almost like giving Java a set of wings.<br>
> ><br>
> > When using the `try-with-resources statement`, I thought it might be<br>
> > possible to introduce an additional simplified syntax, which I believe<br>
> > would be useful when developing simple, small-scale programs.<br>
> > Meanwhile, scenarios requiring resource closure timing specification<br>
> > or exception handling can still make use of the original syntax.<br>
> ><br>
> > At first glance, this simplified syntax may seem a bit unusual, but<br>
> > considering that `switch` itself encompasses both statements and<br>
> > expressions, and that `switch<br>
> > expression`[<a href="https://openjdk.org/jeps/361" rel="noreferrer noreferrer noreferrer noreferrer" target="_blank">https://openjdk.org/jeps/361</a>] also adds a semicolon at the<br>
> > end of `}`, perhaps it won't be as difficult to accept.<br>
> ><br>
> > Because it reduces indentation, making the logic clearer and more<br>
> > visible, users don't need to consider resource closure timing; they<br>
> > can focus solely on business logic. It's possible that in the future,<br>
> > the likelihood of using this simplified syntax will increase.<br>
> ><br>
> > In my personal opinion, the original `try-with-resources statement`<br>
> > feels like driving a manual transmission car, where I have full<br>
> > control over everything. However, if we can let the runtime manage it<br>
> > autonomously, it's like driving an automatic car on the long journey<br>
> > of coding, and even more effortless.<br>
> ><br>
> > If there could be an alternative approach that is both hassle-free and<br>
> > doesn't require altering Java specifications, I hope that experienced<br>
> > individuals can share their insights.<br>
> ><br>
> ><br>
> > Thanks for your interest and support,<br>
> > Hsinfu Tseng<br>
> ><br>
> > (Using the JEP template because I've found it helps clarify my thoughts.)<br>
> ><br>
> ><br>
> > ## Summary<br>
> ><br>
> > Allow omitting the definition of scope when declaring<br>
> > `try-with-resources statement`.<br>
> ><br>
> ><br>
> > ## Goals<br>
> ><br>
> > * Not introducing new scopes to reduce the cognitive burden on<br>
> > developers, especially beginners.<br>
> > * Reducing the interference of hierarchical indentation to enhance<br>
> > code readability.<br>
> > * The declaration position of variables is not restricted by<br>
> > `try-with-resources statement`.<br>
> > * Ensure that resources are released before the current scope ends.<br>
> ><br>
> ><br>
> > ## Motivation<br>
> ><br>
> > The `try-with-resources statement` simplified resource management in<br>
> > Java after version 7. However, its side effect is the necessity to<br>
> > declare a scope and, at the same time, it restricts lifetime of the<br>
> > variable declared within the scope:<br>
> ><br>
> > ```java<br>
> > public class example1 {<br>
> > public static void main(String... args) throws<br>
> > FileNotFoundException, IOException {<br>
> > try (BufferedReader reader = new BufferedReader(new<br>
> > FileReader("studentName.txt"))) {<br>
> > String studentName = "not found";<br>
> > /* Variable 'studentName' is only alive in the scope of<br>
> > try-with-resources statement. */<br>
> ><br>
> > while ((studentName = reader.readLine()) != null) {<br>
> > break;<br>
> > }<br>
> > }<br>
> ><br>
> > System.out.println(studentName);<br>
> > /* Variable 'studentName' cannot be resolved here. */<br>
> > }<br>
> > }<br>
> ><br>
> > ```<br>
> ><br>
> > While it's possible to move variable declaration before<br>
> > `try-with-resources statement` and modify variable content within the<br>
> > scope of `try-with-resources statement`, the actions of declaration,<br>
> > assignment, and usage of variables are segmented by the scope of<br>
> > `try-with-resources statement`. In practice, we would prefer variable<br>
> > declarations to be as close as possible to their usage locations and<br>
> > avoid unnecessary<br>
> > separation[<a href="https://rules.sonarsource.com/java/RSPEC-1941/" rel="noreferrer noreferrer noreferrer noreferrer" target="_blank">https://rules.sonarsource.com/java/RSPEC-1941/</a>]:<br>
> ><br>
> > ```java<br>
> > public class example2 {<br>
> > public static void main(String... args) throws<br>
> > FileNotFoundException, IOException {<br>
> > String studentName = "not found";<br>
> ><br>
> > // #region<br>
> > // The scope of try-with-resources statement separates<br>
> > // the declaration, assignment, and usage of variable 'studentName'.<br>
> > try (BufferedReader reader = new BufferedReader(new<br>
> > FileReader("studentName.txt"))) {<br>
> > while ((studentName = reader.readLine()) != null) {<br>
> > break;<br>
> > }<br>
> > }<br>
> > // #endregion<br>
> ><br>
> > System.out.println(studentName);<br>
> > }<br>
> > }<br>
> ><br>
> > ```<br>
> ><br>
> > Furthermore, methods that involve multiple resources requiring<br>
> > management and dependencies might become cumbersome in terms of syntax<br>
> > due to `nested try-with-resources statements`:<br>
> ><br>
> > ```java<br>
> > public class example3 {<br>
> > public static void main(String... args) throws SQLException {<br>
> > String jdbcUrl = "jdbcUrl";<br>
> > String username = "username";<br>
> > String password = "password";<br>
> ><br>
> > try (Connection conn = DriverManager.getConnection(jdbcUrl,<br>
> > username, password)) {<br>
> > String selectSQL = "selectSQL";<br>
> > String studentID = "studentID";<br>
> ><br>
> > try (PreparedStatement statement =<br>
> > conn.prepareStatement(selectSQL)) {<br>
> > statement.setString(1, studentID);<br>
> ><br>
> > try (ResultSet result = statement.executeQuery()) {<br>
> > String studentName = "not found";<br>
> ><br>
> > while (result.next()) {<br>
> > studentName = result.getString(1);<br>
> > }<br>
> ><br>
> > System.out.println(studentName);<br>
> > }<br>
> > }<br>
> > }<br>
> > }<br>
> > }<br>
> ><br>
> > ```<br>
> ><br>
> > This proposal introduces a shorthand declaration that eliminates the<br>
> > scope limitations of `try-with-resources statement`. It enables<br>
> > variable declaration, assignment, and usage within the same scope,<br>
> > reduces indentation levels for improved code readability (particularly<br>
> > in `nested try-with-resources statements`), and defers the timing of<br>
> > resource release to the system, ensuring resource disposal before the<br>
> > scope in `try-with-resources statement` is declared ends. (Similar to<br>
> > Golang's `Defer statement` + resource<br>
> > close[<a href="https://go.dev/tour/flowcontrol/12" rel="noreferrer noreferrer noreferrer noreferrer" target="_blank">https://go.dev/tour/flowcontrol/12</a>], C#'s `using<br>
> > declarations`[<a href="https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-8.0/using" rel="noreferrer noreferrer noreferrer noreferrer" target="_blank">https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-8.0/using</a>],<br>
> > and Swift's `Defer statement` + resource<br>
> > close[<a href="https://docs.swift.org/swift-book/documentation/the-swift-programming-language/statements/#Defer-Statement" rel="noreferrer noreferrer noreferrer noreferrer" target="_blank">https://docs.swift.org/swift-book/documentation/the-swift-programming-language/statements/#Defer-Statement</a>])<br>
> ><br>
> ><br>
> > ## Description<br>
> ><br>
> > The format of the `simplified try-with-resources statement` is as follows:<br>
> ><br>
> > ```java<br>
> > try (resources);/* Change '{}' to ';'. */<br>
> ><br>
> > ```<br>
> ><br>
> > It can be observed that omitting `{}` reduces the indentation, thus<br>
> > enhancing code readability by not introducing new scopes. Moreover,<br>
> > variable declarations can be positioned either before or after the<br>
> > `simplified try-with-resources statement`:<br>
> ><br>
> > ```java<br>
> > public class example1_simplified {<br>
> > public static void main(String... args) throws<br>
> > FileNotFoundException, IOException {<br>
> > try (BufferedReader reader = new BufferedReader(new<br>
> > FileReader("studentName.txt")));<br>
> > String studentName = "not found";<br>
> ><br>
> > while ((studentName = reader.readLine()) != null) {<br>
> > break;<br>
> > }<br>
> ><br>
> > System.out.println(studentName);<br>
> > }<br>
> > }<br>
> ><br>
> > ```<br>
> ><br>
> > Because it automatically converts the `simplified try-with-resources<br>
> > statement` to an equivalent `try-with-resources statement` after<br>
> > compilation:<br>
> ><br>
> > ```java<br>
> > public class example1_converted {<br>
> > public static void main(String... args) throws<br>
> > FileNotFoundException, IOException {<br>
> > try (BufferedReader reader = new BufferedReader(new<br>
> > FileReader("studentName.txt"))) {/* Change ';' back to '{'. */<br>
> > String studentName = "not found";<br>
> ><br>
> > while ((studentName = reader.readLine()) != null) {<br>
> > break;<br>
> > }<br>
> ><br>
> > System.out.println(studentName);<br>
> > }/* Add '}' before the current scope ends. */<br>
> > }<br>
> > }<br>
> ><br>
> > ```<br>
> ><br>
> > Because the scope of `simplified try-with-resources statement` extends<br>
> > until the current scope is terminated, the variable `studentName`,<br>
> > which originally couldn't be resolved in `example1`, can now be<br>
> > resolved successfully. This allows variable declaration, assignment,<br>
> > and usage within the same scope, ensuring that resource close<br>
> > operations occur before the current scope ends.<br>
> ><br>
> > Invoking multiple dependent `simplified try-with-resources statements`<br>
> > is similar to regular variable declarations, thereby avoiding<br>
> > excessive nesting.<br>
> ><br>
> > ```java<br>
> > public class example3_simplified {<br>
> > public static void main(String... args) throws SQLException {<br>
> > String jdbcUrl = "jdbcUrl";<br>
> > String username = "username";<br>
> > String password = "password";<br>
> ><br>
> > try (Connection conn = DriverManager.getConnection(jdbcUrl,<br>
> > username, password));<br>
> > String selectSQL = "selectSQL";<br>
> > String studentID = "studentID";<br>
> ><br>
> > try (PreparedStatement statement = conn.prepareStatement(selectSQL));<br>
> > statement.setString(1, studentID);<br>
> ><br>
> > try (ResultSet result = statement.executeQuery());<br>
> > String studentName = "not found";<br>
> ><br>
> > while (result.next()) {<br>
> > studentName = result.getString(1);<br>
> > }<br>
> ><br>
> > System.out.println(studentName);<br>
> > }<br>
> > }<br>
> ><br>
> > ```<br>
> ><br>
> > It will be converted to equivalent `nested try-with-resources<br>
> > statements` after compilation:<br>
> ><br>
> > ```java<br>
> > public class example3_converted {<br>
> > public static void main(String... args) throws SQLException {<br>
> > String jdbcUrl = "jdbcUrl";<br>
> > String username = "username";<br>
> > String password = "password";<br>
> ><br>
> > try (Connection conn = DriverManager.getConnection(jdbcUrl,<br>
> > username, password)) {/* Change ';' back to '{'. */<br>
> > String selectSQL = "selectSQL";<br>
> > String studentID = "studentID";<br>
> ><br>
> > try (PreparedStatement statement =<br>
> > conn.prepareStatement(selectSQL)) {/* Change ';' back to '{'. */<br>
> > statement.setString(1, studentID);<br>
> ><br>
> > try (ResultSet result = statement.executeQuery()) {/* Change<br>
> > ';' back to '{'. */<br>
> > String studentName = "not found";<br>
> ><br>
> > while (result.next()) {<br>
> > studentName = result.getString(1);<br>
> > }<br>
> ><br>
> > System.out.println(studentName);<br>
> > }}}}/* Add the corresponding number (in this case, 3) of '}'<br>
> > before the current scope ends. */<br>
> > }<br>
> ><br>
> > ```<br>
> ><br>
> > After code formatting:<br>
> ><br>
> > ```java<br>
> > public class example3_formatted {<br>
> > public static void main(String... args) throws SQLException {<br>
> > String jdbcUrl = "jdbcUrl";<br>
> > String username = "username";<br>
> > String password = "password";<br>
> ><br>
> > try (Connection conn = DriverManager.getConnection(jdbcUrl,<br>
> > username, password)) {<br>
> > String selectSQL = "selectSQL";<br>
> > String studentID = "studentID";<br>
> ><br>
> > try (PreparedStatement statement =<br>
> > conn.prepareStatement(selectSQL)) {<br>
> > statement.setString(1, studentID);<br>
> ><br>
> > try (ResultSet result = statement.executeQuery()) {<br>
> > String studentName = "not found";<br>
> ><br>
> > while (result.next()) {<br>
> > studentName = result.getString(1);<br>
> > }<br>
> ><br>
> > System.out.println(studentName);<br>
> > }<br>
> > }<br>
> > }<br>
> > }<br>
> > }<br>
> ><br>
> > ```<br>
> ><br>
> > Comparing the code structures of `example3_simplified` and<br>
> > `example3_formatted`, it is evident that the usage of `simplified<br>
> > try-with-resources statement` enhances code readability by<br>
> > significantly reducing nested indentation levels. Additionally, it can<br>
> > be observed that in the converted `nested try-with-resources<br>
> > statements`, resource close actions will be executed in reverse order<br>
> > of declaration, just before the current scope ends.<br>
> ><br>
> > If coupled with `JEP 445: Unnamed Classes and Instance Main Methods<br>
> > (Preview)`[<a href="https://openjdk.org/jeps/445" rel="noreferrer noreferrer noreferrer noreferrer" target="_blank">https://openjdk.org/jeps/445</a>], it becomes convenient to<br>
> > create a simple, small-scale program:<br>
> ><br>
> > ```java<br>
> > String jdbcUrl = "jdbcUrl";<br>
> > String username = "username";<br>
> > String password = "password";<br>
> > String selectSQL = "selectSQL";<br>
> > String studentID = "studentID";<br>
> ><br>
> > void main() throws SQLException {<br>
> > try (Connection conn = DriverManager.getConnection(jdbcUrl,<br>
> > username, password));<br>
> > try (PreparedStatement statement = conn.prepareStatement(selectSQL));<br>
> > statement.setString(1, studentID);<br>
> ><br>
> > try (ResultSet result = statement.executeQuery());<br>
> > String studentName = "not found";<br>
> ><br>
> > while (result.next()) {<br>
> > studentName = result.getString(1);<br>
> > }<br>
> ><br>
> > System.out.println(studentName);<br>
> > }<br>
> ><br>
> > ```<br>
> ><br>
> ><br>
> > ## Alternatives<br>
> ><br>
> > * One approach to mitigate the impact on readability caused by deeply<br>
> > `nested try-with-resources statements` is to consolidate multiple<br>
> > resources within the same `try-with-resources statement` as much as<br>
> > possible. However, formatting multiple resources with line breaks can<br>
> > also disrupt visual clarity, and furthermore, it's not always feasible<br>
> > to close many resources simultaneously:<br>
> ><br>
> > ```java<br>
> > public class alternative1 {<br>
> > public static void main(String... args) throws SQLException {<br>
> > String jdbcUrl = "jdbcUrl";<br>
> > String username = "username";<br>
> > String password = "password";<br>
> > String selectSQL = "selectSQL";<br>
> > String studentID = "studentID";<br>
> ><br>
> > try (Connection conn = DriverManager.getConnection(jdbcUrl,<br>
> > username, password);<br>
> > PreparedStatement statement =<br>
> > conn.prepareStatement(selectSQL)) {<br>
> > /* In this case, there are only 2 resources, but if there are 3 or more,<br>
> > it will become even less aesthetically pleasing. */<br>
> ><br>
> > statement.setString(1, studentID);<br>
> ><br>
> > try (ResultSet result = statement.executeQuery()) {<br>
> > /* ResultSet 'result' cannot be closed simultaneously with<br>
> > PreparedStatement 'statement'<br>
> > because PreparedStatement 'statement' needs parameter<br>
> > configuration first. */<br>
> > String studentName = "not found";<br>
> ><br>
> > while (result.next()) {<br>
> > studentName = result.getString(1);<br>
> > }<br>
> ><br>
> > return studentName;<br>
> > }<br>
> > }<br>
> > }<br>
> > }<br>
> ><br>
> > ```<br>
> ><br>
> > * Alternatively, creating a separate method to confine the scope of<br>
> > managed resources within the method can be done, but it necessitates<br>
> > 'naming' the new<br>
> > method[<a href="https://www.karlton.org/2017/12/naming-things-hard/" rel="noreferrer noreferrer noreferrer noreferrer" target="_blank">https://www.karlton.org/2017/12/naming-things-hard/</a>]. This<br>
> > approach simply shifts complexity to the interior of additional<br>
> > method, which may not be conducive to creating simple, small-scale<br>
> > programs:<br>
> ><br>
> > ```java<br>
> > public class alternative2 {<br>
> > public static void main(String... args) throws SQLException {<br>
> > String selectSQL = "selectSQL";<br>
> > String studentID = "studentID";<br>
> > String studentName = getStudentName(selectSQL, studentID);<br>
> ><br>
> > System.out.println(studentName);<br>
> > }<br>
> ><br>
> > public static String getStudentName(String sql, String studentID)<br>
> > throws SQLException {<br>
> > String jdbcUrl = "jdbcUrl";<br>
> > String username = "username";<br>
> > String password = "password";<br>
> ><br>
> > try (Connection conn = DriverManager.getConnection(jdbcUrl,<br>
> > username, password)) {<br>
> > try (PreparedStatement statement = conn.prepareStatement(sql)) {<br>
> > statement.setString(1, studentID);<br>
> ><br>
> > try (ResultSet result = statement.executeQuery()) {<br>
> > String studentName = "not found";<br>
> ><br>
> > while (result.next()) {<br>
> > studentName = result.getString(1);<br>
> > }<br>
> ><br>
> > return studentName;<br>
> > }<br>
> > }<br>
> > }<br>
> > }<br>
> > }<br>
> ><br>
> > ```<br>
> ><br>
> > /* GET BETTER EVERY DAY */<br>
</blockquote></div></div>
</blockquote></div></div></div>
</div>