Java 7 has been out for a few years and I admit this is one of the features I seem to neglect. Perhaps, I've been living under a rock, yeah?
I've got JDK 8 installed and because of my sheer laziness, I'll stick to this version of the compiler to analyse how multi-catch exception is implemented.
She saw first some bracelets, then a pearl necklace, then a Venetian gold cross set with precious stones, of admirable workmanship. She tried on the ornaments before the mirror, hesitated and could not make up her mind to part with them, to give them back.
She kept asking: "Haven't you any more?"
Let's define a few exceptions before dipping a toe in the water.
PearlNecklaceException.java
package org.lyeung.thenecklace;
public class PearlNecklaceException extends RuntimeException {
// do-nothing
}
VenetianCrossException.java
package org.lyeung.thenecklace;
public class VenetianCrossException extends RuntimeException {
// do-nothing
}
DiamondNecklaceException.java
package org.lyeung.thenecklace;
public class DiamondNecklaceException extends RuntimeException {
// do-nothing
}
Followed by the main class we'll look at:
Mathilde.java
package org.lyeung.thenecklace;
public class Mathilde {
private void retrieveNecklace(int value) throws PearlNecklaceException,
VenetianCrossException, DiamondNecklaceException {
if (value == 0) {
throw new PearlNecklaceException();
} else if (value == 1) {
throw new VenetianCrossException();
} else {
throw new DiamondNecklaceException();
}
}
public void findNecklace1(int value) {
try {
retrieveNecklace(value);
} catch (PearlNecklaceException e) {
e.printStackTrace();
} catch (VenetianCrossException e) {
e.printStackTrace();
} catch (DiamondNecklaceException e) {
e.printStackTrace();
}
}
public void findNecklace2(int value) {
try {
retrieveNecklace(value);
} catch (PearlNecklaceException e) {
handleException(e);
} catch (VenetianCrossException e) {
handleException(e);
} catch (DiamondNecklaceException e) {
handleException(e);
}
}
private void handleException(Exception e) {
e.printStackTrace();
}
public void findNecklace3(int value) {
try {
retrieveNecklace(value);
} catch (VenetianCrossException
| PearlNecklaceException
| DiamondNecklaceException e) {
e.printStackTrace();
}
}
}
All three variants of find necklaces call retrieveNecklace which throws different exceptions base on input value.
The first variant of find necklace is pretty old school. We declare different catch blocks for each exception thrown.
The second variant of find necklace, similar to the first variant, but minimises code duplication by moving the print stack trace into a common method.
The third variant uses multi-catch exception that results to a more readable and more compact code.
Under the hood, these variants produce different bytecodes.
The disassembled code for the first variant:
public void findNecklace1(int);
Code:
0: aload_0
1: iload_1
2: invokespecial #8 // Method retrieveNecklace:(I)V
5: goto 29
8: astore_2
9: aload_2
10: invokevirtual #9 // Method org/lyeung/thenecklace/PearlNecklaceException.printStackTrace:()V
13: goto 29
16: astore_2
17: aload_2
18: invokevirtual #10 // Method org/lyeung/thenecklace/VenetianCrossException.printStackTrace:()V
21: goto 29
24: astore_2
25: aload_2
26: invokevirtual #11 // Method org/lyeung/thenecklace/DiamondNecklaceException.printStackTrace:()V
29: return
Exception table:
from to target type
0 5 8 Class org/lyeung/thenecklace/PearlNecklaceException
0 5 16 Class org/lyeung/thenecklace/VenetianCrossException
0 5 24 Class org/lyeung/thenecklace/DiamondNecklaceException
The exception table says, "For program counter offset 0 to 5, inclusive and exclusive respectively, the program counter should jump to target offset 8 if PearlNecklaceException is thrown, 16 if VenetianCrossException is thrown and 24 if DiamondNecklaceException is thrown."
All offsets 8, 16 and 24 invoke the caught exception's printStackTrace() method.
The disassembled code for the second variant:
public void findNecklace2(int);
Code:
0: aload_0
1: iload_1
2: invokespecial #8 // Method retrieveNecklace:(I)V
5: goto 32
8: astore_2
9: aload_0
10: aload_2
11: invokespecial #12 // Method handleException:(Ljava/lang/Exception;)V
14: goto 32
17: astore_2
18: aload_0
19: aload_2
20: invokespecial #12 // Method handleException:(Ljava/lang/Exception;)V
23: goto 32
26: astore_2
27: aload_0
28: aload_2
29: invokespecial #12 // Method handleException:(Ljava/lang/Exception;)V
32: return
Exception table:
from to target type
0 5 8 Class org/lyeung/thenecklace/PearlNecklaceException
0 5 17 Class org/lyeung/thenecklace/VenetianCrossException
0 5 26 Class org/lyeung/thenecklace/DiamondNecklaceException
The exception table is not much different from the first variant.
The disassembled code for the last variant:
public void findNecklace3(int);
Code:
0: aload_0
1: iload_1
2: invokespecial #8 // Method retrieveNecklace:(I)V
5: goto 13
8: astore_2
9: aload_2
10: invokevirtual #14 // Method java/lang/RuntimeException.printStackTrace:()V
13: return
Exception table:
from to target type
0 5 8 Class org/lyeung/thenecklace/VenetianCrossException
0 5 8 Class org/lyeung/thenecklace/PearlNecklaceException
0 5 8 Class org/lyeung/thenecklace/DiamondNecklaceException
}
Now, the exception table looks different. As you can see, the target values all point at 8, where offset 8 prints the stack trace!
The generated bytecodes are definitely smaller and more compact than the previous variants.
Below is the disassembled code for entire Mathilde class:
Compiled from "Mathilde.java"
public class org.lyeung.thenecklace.Mathilde {
public org.lyeung.thenecklace.Mathilde();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."":()V
4: return
private void retrieveNecklace(int) throws org.lyeung.thenecklace.PearlNecklaceException, org.lyeung.thenecklace.VenetianCrossException, org.lyeung.thenecklace.DiamondNecklaceException;
Code:
0: iload_1
1: ifne 12
4: new #2 // class org/lyeung/thenecklace/PearlNecklaceException
7: dup
8: invokespecial #3 // Method org/lyeung/thenecklace/PearlNecklaceException."":()V
11: athrow
12: iload_1
13: iconst_1
14: if_icmpne 25
17: new #4 // class org/lyeung/thenecklace/VenetianCrossException
20: dup
21: invokespecial #5 // Method org/lyeung/thenecklace/VenetianCrossException."":()V
24: athrow
25: new #6 // class org/lyeung/thenecklace/DiamondNecklaceException
28: dup
29: invokespecial #7 // Method org/lyeung/thenecklace/DiamondNecklaceException."":()V
32: athrow
public void findNecklace1(int);
Code:
0: aload_0
1: iload_1
2: invokespecial #8 // Method retrieveNecklace:(I)V
5: goto 29
8: astore_2
9: aload_2
10: invokevirtual #9 // Method org/lyeung/thenecklace/PearlNecklaceException.printStackTrace:()V
13: goto 29
16: astore_2
17: aload_2
18: invokevirtual #10 // Method org/lyeung/thenecklace/VenetianCrossException.printStackTrace:()V
21: goto 29
24: astore_2
25: aload_2
26: invokevirtual #11 // Method org/lyeung/thenecklace/DiamondNecklaceException.printStackTrace:()V
29: return
Exception table:
from to target type
0 5 8 Class org/lyeung/thenecklace/PearlNecklaceException
0 5 16 Class org/lyeung/thenecklace/VenetianCrossException
0 5 24 Class org/lyeung/thenecklace/DiamondNecklaceException
public void findNecklace2(int);
Code:
0: aload_0
1: iload_1
2: invokespecial #8 // Method retrieveNecklace:(I)V
5: goto 32
8: astore_2
9: aload_0
10: aload_2
11: invokespecial #12 // Method handleException:(Ljava/lang/Exception;)V
14: goto 32
17: astore_2
18: aload_0
19: aload_2
20: invokespecial #12 // Method handleException:(Ljava/lang/Exception;)V
23: goto 32
26: astore_2
27: aload_0
28: aload_2
29: invokespecial #12 // Method handleException:(Ljava/lang/Exception;)V
32: return
Exception table:
from to target type
0 5 8 Class org/lyeung/thenecklace/PearlNecklaceException
0 5 17 Class org/lyeung/thenecklace/VenetianCrossException
0 5 26 Class org/lyeung/thenecklace/DiamondNecklaceException
private void handleException(java.lang.Exception);
Code:
0: aload_1
1: invokevirtual #13 // Method java/lang/Exception.printStackTrace:()V
4: return
public void findNecklace3(int);
Code:
0: aload_0
1: iload_1
2: invokespecial #8 // Method retrieveNecklace:(I)V
5: goto 13
8: astore_2
9: aload_2
10: invokevirtual #14 // Method java/lang/RuntimeException.printStackTrace:()V
13: return
Exception table:
from to target type
0 5 8 Class org/lyeung/thenecklace/VenetianCrossException
0 5 8 Class org/lyeung/thenecklace/PearlNecklaceException
0 5 8 Class org/lyeung/thenecklace/DiamondNecklaceException
}