Бросать исключение или возвращать коды ошибок/успеха? Является ли исключением то, что метод не может выполнить свою задачу?
Пока вы вызываете одну функцию и решаете, что делать с ее ответом, вы не поймете исключений.
Вот когда вам надо будет вызвать функцию, которая вызывает методы класса, которые вызывают методы других классов - вы либо изрисуете себе все стены теми вариантами ошибок, которые каждый из этих методов может вернуть, либо поймете, как это прекрасно - просто поймать исключение, если что-то пошло не так, и не париться с тем, что и где именно.
Исключения и сообщения об ошибках решают разные задачи. Если условно разделить приложение на Контроллер, формы проверки входных значений и модель приложения.
Контроллер - управляет приложением
Формы - выполняют валидацию данных
Модель - основная логика, решение задачи бизнеса.
Во время валидации данных, сообщения должны накапливаться. Ошибка со стороны пользователя, при вводе данных, это вполне ожидаемое событие. Поэтому в данном случае исключение не уместно. 
Модель следит за своими инвариантами и должна быть целостная. Поэтому она в любом случае проверяет входящие данные. Если во входящих данных была найдена ошибка, это уже исключение, поскольку для модели получение неправильных данных ситуация неожиданная и приложение должно завершиться немедленно.
Мое мнение такое: 
Если ошибка ожидаемая или ошибки должны накапливаться для отображения в диалоге с пользователем, это не исключение. 
Если ошибка незапланированная, приводит к немедленному прекращению выполнения алгоритма, значит это исключение. Пример исключения: ошибка взаимодействия с базой данных, ошибка записи на диск, вызов метода запрещенного для текущего состояния объекта.