The compiler determines which method to invoke, not the virtual machine. Thus, the class that you described will not solve the problem unless you check instanceof first and pass the parameter the correct type. Otherwise, you will get a handleError (exception e) every time.
But I didn’t want to create an answer for this reason, but to assert that in many cases only one error handler is preferable, and not responsibility. Often in java we find ourselves in terrible situations like:
catch (NoSuchAlgorithmException e) { throw new IllegalStateException("No such algorithm: RSA?", e); } catch (NoSuchProviderException e) { throw new IllegalStateException("No such provider: " + ANDROID_KEYSTORE_ID, e); } catch (InvalidAlgorithmParameterException e) { throw new IllegalStateException("Bug setting up encryption key for user credentials: ", e); } catch (KeyStoreException e) { throw new IllegalStateException("Bug setting up encryption key for user credentials: ", e); } catch (IOException e) { Log.w(TAG, "Exception setting up keystore for user creds. They won't be stored.", e); } catch (CertificateException e) { Log.w(TAG, "Exception setting up keystore for user creds. They won't be stored.", e); }
Having only one error handler allows us to combine many types of exceptions together. You can see in this code, there are exceptions that should never be thrown, exceptions that can only be the result of errors in the code, and legitimate exceptional conditions that we need to handle. I find this messy and prefer to say:
if (e instanceof NoSuchAlgorithmException || e instanceof NoSuchProviderException) { Log.wtf(TAG, "What the heck is this?", e); throw new IllegalStateException("This is some kind of weird bug", e); } else if (e instanceof IOException || e instanceof CertificateException) { // This can happen sometimes, track event in analytics and perhaps // try some alternative means of credential storage. } else { // At least here the app won't crash if some unexpected exception occurs, // since we're trapping everything. }
I don’t think it’s so bad that you can combine unexpected crashes together and handle them in a more user-friendly way than crashing the application. Even if this is just a mistake, it’s better to track it in your analytic structure behind the scenes than the user's bomb from the application. So many crashes in Android applications are actually fully repaired, but we don’t go around catching Throwable in every try / catch statement because it has a lot of extra code.