Причина первая:
Нужно ловить определенные вещи. Если вызывающий код должен иметь дело с определенным исключительным условием, вам нужно дифференцировать свое исключение, а Java различает исключения с разными типами, поэтому вам нужно написать свое собственное.
В принципе, если кто-то должен написать:
catch(ExistingException e) {
if({condition}) {
{ some stuff here}
}
else {
{ different stuff here}
}
}
Вы, вероятно, хотите написать конкретное расширение; catch Exception match более понятен, чем условные выражения, ИМХО.
Помните: ваше новое исключение может быть подклассом RuntimeException
Причина вторая:
Консолидация API. Если вы пишете интерфейс и у вас есть несколько реализаций, возможно, что они будут вызывать разные API с целой кучей разных не-RuntimeExceptions:
interface MyInterface {
void methodA();
}
class MyImplA {
void methodA() throws SQLException { ... }
}
class MyImplB {
void methodA() throws IOException { ... }
}
Вы действительно хотите, чтобы MyInterface.methodA генерировал SQLException и IOException? Может быть, тогда имеет смысл обернуть возможные исключения в пользовательское исключение. Который снова может быть RuntimeException. Или даже само RuntimeException ...