try-with-resource机制的一个编译陷阱

Posted 阿丙的博客园

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了try-with-resource机制的一个编译陷阱相关的知识,希望对你有一定的参考价值。

  为了解决问题,偶然发现一个奇怪的地方:就是使用try-with-resource机制的代码编译后,使用jd-gui反编译文件出现// ERROR //,但是程序运行却是正常的

  进一步确认后发现:如果try语句中只有一个定义时,反编译后也不会报错(如果有两个可以嵌套try语句);而且编译完以后的代码跟正常的代码编译完后的差距很大。

 

以下是测试证明:

 原始的写法举例

public byte[] file2byte(String filePath) {
    byte[] buffer = null;
    File file = new File(filePath);
    FileInputStream fis = null;
    ByteArrayOutputStream bos = null;
    try {
        fis = new FileInputStream(file);
        bos = new ByteArrayOutputStream();
        byte[] b = new byte[1024];
        int n;
        while ((n = fis.read(b)) != -1) {
            bos.write(b, 0, n);
        }
        buffer = bos.toByteArray();
    } catch (Exception e) {
        // e.printStackTrace();
    } finally{
        try {
            if(fis != null){
                fis.close();
            }
            if(bos != null){
                bos.close();
            }
        } catch (IOException e) {
            //e.printStackTrace();
        }
    }
    return buffer;
}
View Code

 反编译结果:

public byte[] file2byte(String filePath) {
    byte[] buffer = null;
    File file = new File(filePath);
    FileInputStream fis = null;
    ByteArrayOutputStream bos = null;
    try {
        fis = new FileInputStream(file);
        bos = new ByteArrayOutputStream();
        byte[] b = new byte[1024];
        int n;
        while ((n = fis.read(b)) != -1)
        {
            int n;
            bos.write(b, 0, n);
        }
        buffer = bos.toByteArray();
    }
    catch (Exception localException)
    {
        try {
            if (fis != null) {
                fis.close();
            }
            if (bos != null)
                bos.close();
        }
        catch (IOException localIOException)
        {
        }
    }
    finally
    {
        try
        {
            if (fis != null) {
                fis.close();
            }
            if (bos != null)
                bos.close();
        }
        catch (IOException localIOException1)
        {
        }
    }
    return buffer;
}
View Code

 反编译后部分截图:

 

try语句中有两个定义的时候

public byte[] file2byte(String filePath) {
    byte[] buffer = null;
    File file = new File(filePath);
    try (FileInputStream fis = new FileInputStream(file);
            ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
        byte[] b = new byte[1024];
        int n;
        while ((n = fis.read(b)) != -1) {
            bos.write(b, 0, n);
        }
        buffer = bos.toByteArray();
    } catch (Exception e) {
        // e.printStackTrace();
    }
    return buffer;
}
View Code

 反编译结果:

 

// ERROR //
  public byte[] file2byte(String filePath)
  {
    // Byte code:
    //   0: aconst_null
    //   1: astore_2
    //   2: new 725    java/io/File
    //   5: dup
    //   6: aload_1
    //   7: invokespecial 727    java/io/File:<init>    (Ljava/lang/String;)V
    //   10: astore_3
    //   11: aconst_null
    //   12: astore 4
    //   14: aconst_null
    //   15: astore 5
    //   17: new 728    java/io/FileInputStream
    //   20: dup
    //   21: aload_3
    //   22: invokespecial 730    java/io/FileInputStream:<init>    (Ljava/io/File;)V
    //   25: astore 6
    //   27: new 733    java/io/ByteArrayOutputStream
    //   30: dup
    //   31: invokespecial 735    java/io/ByteArrayOutputStream:<init>    ()V
    //   34: astore 7
    //   36: ldc_w 736
    //   39: newarray byte
    //   41: astore 8
    //   43: goto +13 -> 56
    //   46: aload 7
    //   48: aload 8
    //   50: iconst_0
    //   51: iload 9
    //   53: invokevirtual 737    java/io/ByteArrayOutputStream:write    ([BII)V
    //   56: aload 6
    //   58: aload 8
    //   60: invokevirtual 740    java/io/FileInputStream:read    ([B)I
    //   63: dup
    //   64: istore 9
    //   66: iconst_m1
    //   67: if_icmpne -21 -> 46
    //   70: aload 7
    //   72: invokevirtual 744    java/io/ByteArrayOutputStream:toByteArray    ()[B
    //   75: astore_2
    //   76: aload 7
    //   78: ifnull +26 -> 104
    //   81: aload 7
    //   83: invokevirtual 748    java/io/ByteArrayOutputStream:close    ()V
    //   86: goto +18 -> 104
    //   89: astore 4
    //   91: aload 7
    //   93: ifnull +8 -> 101
    //   96: aload 7
    //   98: invokevirtual 748    java/io/ByteArrayOutputStream:close    ()V
    //   101: aload 4
    //   103: athrow
    //   104: aload 6
    //   106: ifnull +85 -> 191
    //   109: aload 6
    //   111: invokevirtual 749    java/io/FileInputStream:close    ()V
    //   114: goto +77 -> 191
    //   117: astore 5
    //   119: aload 4
    //   121: ifnonnull +10 -> 131
    //   124: aload 5
    //   126: astore 4
    //   128: goto +17 -> 145
    //   131: aload 4
    //   133: aload 5
    //   135: if_acmpeq +10 -> 145
    //   138: aload 4
    //   140: aload 5
    //   142: invokevirtual 700    java/lang/Throwable:addSuppressed    (Ljava/lang/Throwable;)V
    //   145: aload 6
    //   147: ifnull +8 -> 155
    //   150: aload 6
    //   152: invokevirtual 749    java/io/FileInputStream:close    ()V
    //   155: aload 4
    //   157: athrow
    //   158: astore 5
    //   160: aload 4
    //   162: ifnonnull +10 -> 172
    //   165: aload 5
    //   167: astore 4
    //   169: goto +17 -> 186
    //   172: aload 4
    //   174: aload 5
    //   176: if_acmpeq +10 -> 186
    //   179: aload 4
    //   181: aload 5
    //   183: invokevirtual 700    java/lang/Throwable:addSuppressed    (Ljava/lang/Throwable;)V
    //   186: aload 4
    //   188: athrow
    //   189: astore 4
    //   191: aload_2
    //   192: areturn
    //
    // Exception table:
    //   from    to    target    type
    //   36    76    89    finally
    //   27    104    117    finally
    //   17    158    158    finally
    //   11    189    189    java/lang/Exception
  }
View Code

 

 反编译后部分截图:

 

 

每个try语句中有只有一个定义的时候

public byte[] file2byte(String filePath) {
    byte[] buffer = null;
    File file = new File(filePath);
    try(FileInputStream fis = new FileInputStream(file);) {
        try(ByteArrayOutputStream bos = new ByteArrayOutputStream();){
            byte[] b = new byte[1024];
            int n;
            while ((n = fis.read(b)) != -1) {
                bos.write(b, 0, n);
            }
            buffer = bos.toByteArray();
        }
    } catch (Exception e) {
        // e.printStackTrace();
    }
    return buffer;
}
View Code

 反编译结果:

public byte[] file2byte(String filePath) {
    byte[] buffer = null;
    File file = new File(filePath);
    try { Object localObject1 = null; Object localObject4 = null;
      Object localObject3;
      label197: 
      try { fis = new FileInputStream(file);
      }
      finally
      {
        FileInputStream fis;
        Object localObject5;
        Object localObject8;
        ByteArrayOutputStream bos;
        byte[] b;
        int n;
        int n;
        Object localObject7;
        localObject3 = localThrowable1; break label197; if (localObject3 != localThrowable1) localObject3.addSuppressed(localThrowable1); 
      }
    } catch (Exception localException1) {
    }
    return buffer;
  }
View Code

 最后也能反编译成功,但是反编译的文件有点看不懂了,反编译后部分截图:

 

以上是关于try-with-resource机制的一个编译陷阱的主要内容,如果未能解决你的问题,请参考以下文章

在 Java 7 try-with-resources 的 Clover 检测后编译失败

由编译器完成的 Java try-with-resource 实现

try-with-resources

[Java开发之路](20)try-with-resource 异常声明

使用 try-with-resources 读取和写入同一个文件

了解 JDK 7 - try-with-resources