One of the new features introduced in Java 7 was the possibility to handle multiple exception types in a single catch block.
Starting with March 2014 (added in SDK Tools 22.6), this feature can be used for Android applications too when targeting Android Froyo or later.
However, in Android, there is a special case where multi-catch can bring trouble for the developers.
The special case I’m talking about is ReflectiveOperationException that has been added in API level 19.
When creating code that uses the Reflection API, you may likely have to deal with the subclasses of the aforementioned exception.
An example
I created an example project to illustrate the scenario. When built and run, it will show a screen with a text and a Button. Pressing the Button will throw either a NoSuchFieldException or a NoSuchMethodException. The exception is caught, and a Snackbar notifies us about the successful exception handling.
The code contains two catch clauses, both containing the same code which is obviously code duplication. When using an IDE – preferably IntelliJ IDEA or Android Studio -, it may even complain about this:
After following the suggestion, another warning is shown:
Actually, this warning is right. When running on a device with API level 18 or lower, pressing the TEST button results in the following crash:
FATAL EXCEPTION: main java.lang.NoClassDefFoundError: java.lang.ReflectiveOperationException at com.gyulajuhasz.example.dangerousmulticatch.MainActivity$1.onClick(MainActivity.java:25) at android.view.View.performClick(View.java:4204) at android.view.View$PerformClick.run(View.java:17355) at android.os.Handler.handleCallback(Handler.java:725) at android.os.Handler.dispatchMessage(Handler.java:92) at android.os.Looper.loop(Looper.java:137) at android.app.ActivityThread.main(ActivityThread.java:5041) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:511) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560) at dalvik.system.NativeStart.main(Native Method)
The reason
As the warning suggests, the code is compiled as if ReflectiveOperationException is declared to be caught in the catch block. This Exception obviously does not exist on older devices and the stack trace correctly points this out. Using a Java Decompiler – such as Luyten – we can easily see examine the situation ourselves. The class file I decompiled is
app/build/intermediates/classes/debug/com/gyulajuhasz/example/dangerousmulticatch/MainActivity.class
Conclusion
There is not too much to say here other than catching subclasses of ReflectiveOperationException
with a multi-catch block should be avoided, unless API 19 is the minimum supported version for the developed application. As far as I know, this Exception is the only one that was added later as parents of other already existing ones, but you can always search for other cases by using an appropriate query and checking the subclasses of the results.