try with resources简洁的异常捕获机制

 通过前篇的《Java文件IO流的操作总结》,我们知道了基本输入输出流的使用方式,但是每次都需要在finally处关闭流资源,这样操作起来既啰嗦又麻烦,有没有更简洁的方式呢?本篇就来讲解jdk1.7引入的try with resources语法糖式写法。

什么是语法糖

1.之所以称之为语法糖,给人的感觉就是很甜,很甜。 
2.在相同功能下,语法糖的写法会让代码更加简洁流畅,代码更加语义自然。
3.通过编译器在编译期间以特定的字节码或者特定的方式对这些语法做一些处理
4.语法糖虽然不会提供实质性的功能改进,但是它们或能提高性能、或能提升语法的严谨性、或能减少编码出错的机会。

使用try with resources捕获异常

待读取的文件内容

 示例代码

package com.lingyejun.io;

import java.io.*;

/**
 * Created by Lingye on 2018/9/28 15:03
 */
public class SyntacticSugarTry {

    // 调用有finally的case值
    public static final int OLD_TRY = 1;
    // 调用新式语法糖式的case值
    public static final int SUGAR_TRY = 2;

    /**
     * 根据输入参数执行不同方法
     *
     * @param type
     * @return
     */
    public InputStream invokeTry(int type) {
        InputStream inputStream = null;
        switch (type) {
            case OLD_TRY:
                inputStream = oldTryCatch();
                break;
            case SUGAR_TRY:
                inputStream = newTryCatch();
                break;
            default:
                System.out.println("error type");
        }
        return inputStream;
    }

    /**
     * 采用旧式的finally写法
     *
     * @return
     */
    public InputStream oldTryCatch(){
        // 构建文件对象
        File inputFile = new File("D:\input.txt");
        // 初始化输入流
        InputStream inputStream = null;
        try {
            // 创建字节输入流
            inputStream = new FileInputStream(inputFile);
            // 读取到1KB字节数组中
            byte[] buffer = new byte[12];
            // 读取数据并放到buffer数组中
            inputStream.read(buffer);
            System.out.println("oldTryCatch读取输出"+new String(buffer));
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (inputStream != null) {
                try {
                    // 关闭流过程,也有可能出现异常
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return inputStream;
    }

    /**
     * 采用语法糖式写法
     *
     * @return
     */
    public InputStream newTryCatch() {
        // 构建文件对象
        File inputFile = new File("D:\input.txt");
        // 初始化输入流
        InputStream returnStream = null;
        // try with resource 语法糖式写法
        try (InputStream inputStream = new FileInputStream(inputFile)) {
            byte[] buffer = new byte[12];
            inputStream.read(buffer);
            System.out.println("newTryCatch读取输出"+new String(buffer));
            returnStream = inputStream;
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 省略了繁琐的finally
        return returnStream;
    }

    public static void main(String[] args) {
        SyntacticSugarTry sugarTry = new SyntacticSugarTry();
        InputStream oldStream = sugarTry.invokeTry(OLD_TRY);
        InputStream sugarStream = sugarTry.invokeTry(SUGAR_TRY);
        // 检查流是否正常关闭
        try {
            // 再次尝试读取,检查是否关闭
            oldStream.read();
        } catch (IOException e) {
            // 已关闭
            System.out.println("oldStream 输入流已关闭");
        }
        try {
            // 再次尝试读取,检查是否关闭
            sugarStream.read();
        } catch (IOException e) {
            // 已关闭
            System.out.println("sugarStream 输入流已关闭");
        }
    }
}

查看文件管道的关闭情况

 语法糖式写法,执行完毕后自动关闭输入流

查看输出结果 

不难看出,语法糖的使用其实就是让我们的写的代码更简单,看起来也更容易理解。

使用原理

语法糖是一种几乎每种语言或多或少都提供过的一些方便程序员开发代码的语法,它只是编译器实现的一些小把戏罢了,编译期间以特定的字节码或者特定的方式对这些语法做一些处理,开发者就可以直接方便地使用了。这些语法糖虽然不会提供实质性的功能改进,但是它们或能提高性能、或能提升语法的严谨性、或能减少编码出错的机会。

使用JD-GUI打开上面类的.class编译文件后会发现编译过后,编译器给我们自动加上了资源流的close关闭动作(81行、95行)。

/* Error */
  public InputStream newTryCatch()
  {
    // Byte code:
    //   0: new 49	java/io/File
    //   3: dup
    //   4: ldc 51
    //   6: invokespecial 53	java/io/File:<init>	(Ljava/lang/String;)V
    //   9: astore_1
    //   10: aconst_null
    //   11: astore_2
    //   12: aconst_null
    //   13: astore_3
    //   14: aconst_null
    //   15: astore 4
    //   17: new 55	java/io/FileInputStream
    //   20: dup
    //   21: aload_1
    //   22: invokespecial 57	java/io/FileInputStream:<init>	(Ljava/io/File;)V
    //   25: astore 5
    //   27: bipush 12
    //   29: newarray <illegal type>
    //   31: astore 6
    //   33: aload 5
    //   35: aload 6
    //   37: invokevirtual 60	java/io/InputStream:read	([B)I
    //   40: pop
    //   41: getstatic 29	java/lang/System:out	Ljava/io/PrintStream;
    //   44: new 64	java/lang/StringBuilder
    //   47: dup
    //   48: ldc 102
    //   50: invokespecial 68	java/lang/StringBuilder:<init>	(Ljava/lang/String;)V
    //   53: new 69	java/lang/String
    //   56: dup
    //   57: aload 6
    //   59: invokespecial 71	java/lang/String:<init>	([B)V
    //   62: invokevirtual 74	java/lang/StringBuilder:append	(Ljava/lang/String;)Ljava/lang/StringBuilder;
    //   65: invokevirtual 78	java/lang/StringBuilder:toString	()Ljava/lang/String;
    //   68: invokevirtual 37	java/io/PrintStream:println	(Ljava/lang/String;)V
    //   71: aload 5
    //   73: astore_2
    //   74: aload 5
    //   76: ifnull +55 -> 131
    //   79: aload 5
    //   81: invokevirtual 87	java/io/InputStream:close	()V
    //   84: goto +47 -> 131
    //   87: astore_3
    //   88: aload 5
    //   90: ifnull +8 -> 98
    //   93: aload 5
    //   95: invokevirtual 87	java/io/InputStream:close	()V
    //   98: aload_3
    //   99: athrow
    //   100: astore 4
    //   102: aload_3
    //   103: ifnonnull +9 -> 112
    //   106: aload 4
    //   108: astore_3
    //   109: goto +15 -> 124
    //   112: aload_3
    //   113: aload 4
    //   115: if_acmpeq +9 -> 124
    //   118: aload_3
    //   119: aload 4
    //   121: invokevirtual 104	java/lang/Throwable:addSuppressed	(Ljava/lang/Throwable;)V
    //   124: aload_3
    //   125: athrow
    //   126: astore_3
    //   127: aload_3
    //   128: invokevirtual 82	java/lang/Exception:printStackTrace	()V
    //   131: aload_2
    //   132: areturn
    // Line number table:
    //   Java source line #75	-> byte code offset #0
    //   Java source line #77	-> byte code offset #10
    //   Java source line #79	-> byte code offset #12
    //   Java source line #80	-> byte code offset #27
    //   Java source line #81	-> byte code offset #33
    //   Java source line #82	-> byte code offset #41
    //   Java source line #83	-> byte code offset #71
    //   Java source line #84	-> byte code offset #74
    //   Java source line #85	-> byte code offset #127
    //   Java source line #88	-> byte code offset #131
    // Local variable table:
    //   start	length	slot	name	signature
    //   0	133	0	this	SyntacticSugarTry
    //   9	13	1	inputFile	java.io.File
    //   11	121	2	returnStream	InputStream
    //   13	1	3	localObject1	Object
    //   87	16	3	localObject2	Object
    //   108	17	3	localObject3	Object
    //   126	2	3	e	Exception
    //   15	1	4	localObject4	Object
    //   100	20	4	localThrowable	Throwable
    //   25	69	5	inputStream	InputStream
    //   31	27	6	buffer	byte[]
    // Exception table:
    //   from	to	target	type
    //   27	74	87	finally
    //   17	100	100	finally
    //   12	126	126	java/lang/Exception
  }

参考文章:

https://www.cnblogs.com/jiumao/p/7136369.html

https://blog.csdn.net/Merlin2017/article/details/78075206 

原文地址:https://www.cnblogs.com/lingyejun/p/9744604.html