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 }
No comments:
Post a Comment