Each method has an Exception Table that maps a range of instructions plus and exception type to an exception handler (it's entry point). This is not always easy to translate back to Java code. But in general, you will need to examine this table and then analyse reachable code from those entry points. All of that code belongs to a catch
clause. Then it's just a matter of identifying athrow
instructions.
Use javap
or other good bytecode visualizer to play around and understand it better. Completing your code, compiling it, and subjecting it to javap
produces:
public class Test extends java.lang.Object{
public Test();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
public static void def() throws java.io.IOException;
Code:
0: new #2; //class java/io/IOException
3: dup
4: invokespecial #3; //Method java/io/IOException."<init>":()V
7: athrow
public static void main(java.lang.String[]) throws java.io.IOException;
Code:
0: invokestatic #4; //Method def:()V
3: goto 19
6: astore_1
7: aload_1
8: athrow
9: astore_1
10: new #6; //class java/lang/RuntimeException
13: dup
14: aload_1
15: invokespecial #7; //Method java/lang/RuntimeException."<init>":(Ljava/lang/Throwable;)V
18: athrow
19: return
Exception table:
from to target type
0 3 6 Class java/io/IOException
0 3 9 Class java/lang/Exception
}
For method main
we have 2 exception entry points ("targets"): 6 and 9. Following 6, we have an athrow
at offset 8. Following the entry point at 9, we have an athrow
at offset 18. That's it!