Question

The Java code looks like this:

File f1 = File.createTempFile("example", ".txt");
File f2 = File.createTempFile("outExample", ".txt");        
FileInputStream in = new FileInputStream(f1);
FileOutputStream out = new FileOutputStream(f2);
try {
    int c;
    while ((c = in.read()) != -1) {
             out.write(c);
    }
} 
finally {
    if (in != null) {
        in.close();
    }
    if (out != null) {
        out.close();
    }
}       
return f1.delete() && f2.delete();

And bytecode for this:

TRYCATCHBLOCK L0 L1 L1 
   L2
    LINENUMBER 138 L2
    LDC "example"
    LDC ".txt"
    INVOKESTATIC File.createTempFile (String, String) : File
    ASTORE 1
   L3
    LINENUMBER 139 L3
    LDC "outExample"
    LDC ".txt"
    INVOKESTATIC File.createTempFile (String, String) : File
    ASTORE 2
   L4
    LINENUMBER 141 L4
    NEW FileInputStream
    DUP
    ALOAD 1: f1
    INVOKESPECIAL FileInputStream.<init> (File) : void
    ASTORE 3
   L5
    LINENUMBER 142 L5
    NEW FileOutputStream
    DUP
    ALOAD 2: f2
    INVOKESPECIAL FileOutputStream.<init> (File) : void
    ASTORE 4
   L0
    LINENUMBER 146 L0
    GOTO L6
   L7
    LINENUMBER 147 L7
    ALOAD 4: out
    ILOAD 5: c
    INVOKEVIRTUAL FileOutputStream.write (int) : void
   L6
    LINENUMBER 146 L6
    ALOAD 3: in
    INVOKEVIRTUAL FileInputStream.read () : int
    DUP
    ISTORE 5
   L8
    ICONST_M1
    IF_ICMPNE L7
   L9
    LINENUMBER 149 L9
    GOTO L10
   L1
    LINENUMBER 150 L1
    ASTORE 6
   L11
    LINENUMBER 151 L11
    ALOAD 3: in
    IFNULL L12
   L13
    LINENUMBER 152 L13
    ALOAD 3: in
    INVOKEVIRTUAL FileInputStream.close () : void
   L12
    LINENUMBER 154 L12
    ALOAD 4: out
    IFNULL L14
   L15
    LINENUMBER 155 L15
    ALOAD 4: out
    INVOKEVIRTUAL FileOutputStream.close () : void
   L14
    LINENUMBER 157 L14
    ALOAD 6
    ATHROW
   L10
    LINENUMBER 151 L10
    ALOAD 3: in
    IFNULL L16
   L17
    LINENUMBER 152 L17
    ALOAD 3: in
    INVOKEVIRTUAL FileInputStream.close () : void
   L16
    LINENUMBER 154 L16
    ALOAD 4: out
    IFNULL L18
   L19
    LINENUMBER 155 L19
    ALOAD 4: out
    INVOKEVIRTUAL FileOutputStream.close () : void
   L18
    LINENUMBER 159 L18
    ALOAD 1: f1
    INVOKEVIRTUAL File.delete () : boolean
    IFEQ L20
    ALOAD 2: f2
    INVOKEVIRTUAL File.delete () : boolean
    IFEQ L20
    ICONST_1
    IRETURN
   L20
    ICONST_0
    IRETURN

Can anybody please tell me why close() instructions are invoked twice per stream (L13 and L17, L15 and L19)? In case without finally block, but with try-catch there is only one close() invoked per stream in bytecode.

Was it helpful?

Solution

Ones is for the case when the exception was implicitly caught and needs to get rethrown (note the ATHROW at the end)

L15
 LINENUMBER 155 L15
 ALOAD 4: out
 INVOKEVIRTUAL FileOutputStream.close () : void
L14
 LINENUMBER 157 L14
 ALOAD 6
 ATHROW

The other for when no exception is thrown:

L19
 LINENUMBER 155 L19
 ALOAD 4: out
 INVOKEVIRTUAL FileOutputStream.close () : void

If you look at the top, you see

TRYCATCHBLOCK L0 L1 L1 

Those labels are something like for where to jump for the catch and where to jump for the finally. Catch leaves the thrown exception on the top of the stack (again, ATHROW). Inspecting the stack to see if the top member is an exception is a lot more expensive (and harder/impossible; the stack isn't typed) than just duplicating the code.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top