Second brother, your previous article about me going to switch was so interesting that it left me wanting more after reading it. Do you want to write another one? Although it uses Java 13 syntax, it is not very friendly to older versions. But there’s no guarantee that Java won’t get another major update, like Java 8, which slaps Java 6 to death in the sand. Java 8 is sweet, but it will be upgraded sooner or later. I’m with you, brother. Don’t worry about the naysayers.

Reader Alice sent me a very moving message last week. Indeed, the last “I go” reading volume of the bar, several large reprinted, including CSDN, the second day are 15,000 reading. But there was plenty of criticism like, “I thought you were doing something new, but I didn’t realize it was Java 13.”

But my heart has always been big. Since I wrote my first article, I have been sprayed like a cloud of hair on my head. So I decided to keep up the good work and bring a new “I go”.

There is no need for remote review this time, because our company has also resumed work. The code of this review still belongs to Xiao Wang. Most of the codes he wrote are very beautiful, rigorous and well annotated, which makes me very satisfied. But when I saw that he didn’t use try-with-resources, I couldn’t help but scream, “Oh my God, Xiao Wang, you still try — catch-finally!”

Have a look at the code xiao Wang wrote.

public class Trycatchfinally {
    public static void main(String[] args) {
        BufferedReader br = null;
        try {
            br = new BufferedReader(new FileReader("/. TXT"));
            String str = null;
            while((str =br.readLine()) ! =null) { System.out.println(str); }}catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(br ! =null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
Copy the code

Try — catch-finally is used properly, especially when the file name is niubu.txt. You don’t need to write comments to understand what this code does: it reads the contents of the file in the try block and prints them line by line to the console. If the file is not found or an IO read/write error occurs, the incorrect stack information is caught and printed in a catch. Finally, the BufferedReader object is turned off in finally, effectively eliminating serious performance consequences if the resource is not closed.

Prior to Java 7, try — catch-finally was really the best way to ensure that a resource would be closed ina timely manner, whether or not a program would throw an exception.

However, experienced readers will notice two serious problems with the above code:

1) The file name “niubi.txt” contains Chinese, which needs to be escaped by java.net.URLDecoder class decode() method, otherwise this code will throw an exception when the file cannot be found.

2) If you create a FileReader object directly from new FileReader(” newfilereader “), the “newfilereader” object must be in the same level of directory as the project SRC, otherwise the file cannot be found. But in most cases, the files will be placed in the Resources directory so that they can be compiled in the Classes directory, as shown below.

To solve these two problems, we need to optimize the code:

public class TrycatchfinallyDecoder {
    public static void main(String[] args) {
        BufferedReader br = null;
        try {
            String path = TrycatchfinallyDecoder.class.getResource("/. TXT").getFile();
            String decodePath = URLDecoder.decode(path,"utf-8");
            br = new BufferedReader(new FileReader(decodePath));

            String str = null;
            while((str =br.readLine()) ! =null) { System.out.println(str); }}catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(br ! =null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
Copy the code

By running this code, the program outputs the correct contents of the file to the console. But if you’re a fan of the word “neat,” this code feels bloated, especially the finally code, which is like the belly of a 12-bottle Snowflake.

A Python programmer makes fun of a Java programmer.

Furthermore, there is a serious catch all the way through a try — catch-finally: Br.readline () ina try might throw an IOException, and br.close() in finally might throw an IOException. If ioExceptions are thrown in both places, the debugging task becomes complicated, and it takes a lot of effort to figure out where the error occurred, which we don’t want to see.

To simulate this situation, we customize a class, MyfinallyReadLineThrow, that has two methods, readLine() and close(), both of which actively throw exceptions.

class MyfinallyReadLineThrow {
    public void close(a) throws Exception {
        throw new Exception("close");
    }

    public void readLine(a) throws Exception {
        throw new Exception("readLine"); }}Copy the code

We then try-finally call MyfinallyReadLineThrow’s readLine() and close() methods in the main() method:

public class TryfinallyCustomReadLineThrow {
    public static void main(String[] args) throws Exception {
        MyfinallyReadLineThrow myThrow = null;
        try {
            myThrow = new MyfinallyReadLineThrow();
            myThrow.readLine();
        } finally{ myThrow.close(); }}}Copy the code

After running the code above, the error stack looks like this:

Exception in thread "main" java.lang.Exception: close
	at com.cmower.dzone.trycatchfinally.MyfinallyOutThrow.close(TryfinallyCustomOutThrow.java:17)
	at com.cmower.dzone.trycatchfinally.TryfinallyCustomOutThrow.main(TryfinallyCustomOutThrow.java:10)
Copy the code

The exception message from the readLine() method was eaten by the stack message from the close() method, which must have led us to believe that the target of our investigation was the close() method rather than readLine() — although it was also a suspect.

With try-with-resources, however, these problems are solved as long as the resources that need to be freed (such as bufferedReaders) implement the AutoCloseable interface. With the solution in place, let’s slim down the previous finally code block.

try (BufferedReader br = new BufferedReader(new FileReader(decodePath));) {
    String str = null;
    while((str =br.readLine()) ! =null) { System.out.println(str); }}catch (IOException e) {
    e.printStackTrace();
}
Copy the code

Lo and behold, the finally block is gone, and instead the resource to be released is written in the () after the try. If you have multiple resources (BufferedReader and PrintWriter) that need to be released, you can add them directly to ().

try (BufferedReader br = new BufferedReader(new FileReader(decodePath));
     PrintWriter writer = new PrintWriter(new File(writePath))) {
    String str = null;
    while((str =br.readLine()) ! =null) { writer.print(str); }}catch (IOException e) {
    e.printStackTrace();
}
Copy the code

If you want to free a custom resource, simply make it implement the AutoCloseable interface and provide the close() method.

public class TrywithresourcesCustom {
    public static void main(String[] args) {
        try (MyResource resource = newMyResource();) {}catch(Exception e) { e.printStackTrace(); }}}class MyResource implements AutoCloseable {
    @Override
    public void close(a) throws Exception {
        System.out.println("Close custom Resources"); }}Copy the code

After the code is run, the output should look like this:

Example Close a custom resourceCopy the code

Isn’t that amazing? We just new a MyResource object in try () and nothing else, but the output statement in the close() method executes. Want to know why? Take a look at the decompiled bytecode.

class MyResource implements AutoCloseable {
    MyResource() {
    }

    public void close(a) throws Exception {
        System.out.println("Close custom Resources"); }}public class TrywithresourcesCustom {
    public TrywithresourcesCustom(a) {}public static void main(String[] args) {
        try {
            MyResource resource = new MyResource();
            resource.close();
        } catch(Exception var2) { var2.printStackTrace(); }}}Copy the code

The compiler calls close() in a try for try-with-resources.

Next, we add another out() method to our custom class,

class MyResourceOut implements AutoCloseable {
    @Override
    public void close(a) throws Exception {
        System.out.println("Close custom Resources");
    }

    public void out(a) throws Exception{
        System.out.println("Silent King II, a funny programmer."); }}Copy the code

This time, we call the out() method in the try:

public class TrywithresourcesCustomOut {
    public static void main(String[] args) {
        try (MyResourceOut resource = new MyResourceOut();) {
            resource.out();
        } catch(Exception e) { e.printStackTrace(); }}}Copy the code

Take a look at the decompiled bytecode:

public class TrywithresourcesCustomOut {
    public TrywithresourcesCustomOut() { } public static void main(String[] args) { try { MyResourceOut resource = new MyResourceOut(); try { resource.out(); } catch (Throwable var5) { try { resource.close(); } catch (Throwable var4) { var5.addSuppressed(var4); } throw var5; } resource.close(); } catch (Exception var6) { var6.printStackTrace(); }}}Copy the code

This time, resource.close() was actively called in the catch block and there was a crucial piece of code var5.addsuppressed (var4). What use is it? When an exception is thrown, it is possible that other exceptions are suppressed because of the exception and cannot be thrown normally. You can then record these suppressed methods by using the addSuppressed() method. Suppressed exceptions appear in the stack information of thrown exceptions and can also be retrieved by using the getSuppressed() method. The advantage of this is that no exceptions are lost, making it easy for us developers to debug.

Wow, remember our previous example where the readLine() exception was eaten by the close() stack in the try-finally? Now that we have try-with-resources, let’s see if the out() method, which has the same effect as readLine(), is eaten by close().

Throw an exception directly in the close() and out() methods:

class MyResourceOutThrow implements AutoCloseable {
    @Override
    public void close(a) throws Exception {
        throw  new Exception("close()");
    }

    public void out(a) throws Exception{
        throw new Exception("out()"); }}Copy the code

Call these two methods:

public class TrywithresourcesCustomOutThrow {
    public static void main(String[] args) {
        try (MyResourceOutThrow resource = new MyResourceOutThrow();) {
            resource.out();
        } catch(Exception e) { e.printStackTrace(); }}}Copy the code

The output of the program is as follows:

java.lang.Exception: out()
	at com.cmower.dzone.trycatchfinally.MyResourceOutThrow.out(TrywithresourcesCustomOutThrow.java:20)
	at com.cmower.dzone.trycatchfinally.TrywithresourcesCustomOutThrow.main(TrywithresourcesCustomOutThrow.java:6)
	Suppressed: java.lang.Exception: close()
		at com.cmower.dzone.trycatchfinally.MyResourceOutThrow.close(TrywithresourcesCustomOutThrow.java:16)
		at com.cmower.dzone.trycatchfinally.TrywithresourcesCustomOutThrow.main(TrywithresourcesCustomOutThrow.java:5)
Copy the code

Lo, not this time, the exception stack information for out() is printed out, and the keyword Suppressed is added to the stack information for the close() method. It’s clear. It’s good. I like it.

To summarize, always consider try-with-resources rather than try-catch-finally only when dealing with resources that must be closed. The former produces cleaner, cleaner code and more reliable exception information. Will you promise me? Stop using try — catch-finally.

thanks

Well, my dear readers, that’s all for this article. Feel like you’ve learned something new? I am silent King 2, an interesting programmer. Original is not easy, do not want a free ticket, please praise for this article, this will be my writing more high-quality articles of the strongest power.

If you think this article is helpful to you, please search “Silent King ii” on wechat and read it for the first time. Reply [666] there is also a 500G HIGH-DEFINITION teaching video (classified) that I prepared for you. Interview on GitHub