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; }
反编译结果:
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; }
反编译后部分截图:
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; }
反编译结果:
// 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 }
反编译后部分截图:
每个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; }
反编译结果:
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; }
最后也能反编译成功,但是反编译的文件有点看不懂了,反编译后部分截图:
以上是关于try-with-resource机制的一个编译陷阱的主要内容,如果未能解决你的问题,请参考以下文章
在 Java 7 try-with-resources 的 Clover 检测后编译失败
由编译器完成的 Java try-with-resource 实现
[Java开发之路](20)try-with-resource 异常声明