Чтобы ответить на ваш конкретный вопрос: ваше решение должно основываться на том, как и почему будут обрабатываться ваши исключения. Вы хотите сделать свою программу максимально надежной и удобно реагировать на все возможные сценарии ошибок индивидуально? Тогда вы действительно должны создать класс исключения для каждой возможной ошибки, которую вы можете идентифицировать. В противном случае лучше всего решать каждый случай индивидуально.
Существует множество распространенных ошибок, которые ставят под угрозу стабильность всей вашей программы (например, ClassNotFoundException или NoSuchMethodException) - это определенно необходимо обрабатывать специально. Существуют и другие ошибки, которые тесно связаны друг с другом, что приводит к аналогичным проблемам - они могут быть сгруппированы или организованы иерархически (IOException означает всевозможные ошибки, связанные с вводом или выводом, NetworkIOException стоит только для ошибок ввода и вывода связанные с доступом к сети и т. д.).
Гораздо важнее, чем имя исключения и иерархия классов, на мой взгляд, это то, что вы с ним делаете: где вы размещаете блоки try/catch? Какие записи журнала должны быть записаны для какого файла журнала? Кто должен быть уведомлен? Какие сообщения об ошибках должны быть представлены только администраторам/разработчикам? Какие ошибки следует передавать конечному пользователю?
Существует множество шаблонов для обработки исключений, отвечающих на всевозможные вопросы, подобные этим. Вы можете найти довольно обширную коллекцию общих и полезных шаблонов here.
http://weblogs.java.net/blog/bakksjo/archive/2005/09/java_exception.html – drifter