Передавайте контекст с исключениями
Каждое исключение, инициируемое в программе, должно содержать достаточно контекстной информации для определения источника и местонахождения ошибки. В Java из любого исключения можно получить данные трассировки стека; однако по трассировке невозможно узнать, с какой целью выполнялась операция, завершившаяся неудачей.
Создавайте содержательные сообщения об ошибках и передавайте их со своими исключениями. Включайте в них сведения о сбойной операции и типе сбоя. Если в приложении ведется журнал, передайте информацию, достаточную для регистрации ошибки из секции catch.
Определяйте классы исключений в контексте потребностей вызывающей стороны
Существует много способов классификации ошибок. Например, ошибки можно классифицировать по источнику, то есть по компоненту, в котором они произошли. Также возможна классификация по типу: сбои устройств, сетевые сбои, ошибки программирования и т.д. Однако при определении классов исключений в приложениях думать необходимо прежде всего о том, как они будут перехватываться.
Рассмотрим пример неудачной классификации исключений. Далее приводится конструкция try-catch-finally для сторонней библиотечной функции. Она учитывает все исключения, которые могут быть инициированы при вызовах:
>ACMEPort port = new ACMEPort(12);
>try {
> port.open();
>} catch (DeviceResponseException e) {
> reportPortError(e);
> logger.log("Device response exception", e);
>} catch (ATM1212UnlockedException e) {
> reportPortError(e);
> logger.log("Unlock exception", e);
>} catch (GMXError e) {
> reportPortError(e);
> logger.log("Device response exception");
>} finally {
> …
>}
Конструкция содержит множество повторений, и это неудивительно. В большинстве ситуаций при обработке исключений выполняются относительно стандартные действия, не зависящие от их реальной причины. Мы должны сохранить ошибку и убедиться в том, что работа программы может быть продолжена. В этом случае, поскольку выполняемая работа остается более или менее постоянной независимо от исключения, код можно существенно упростить — для этого мы создаем «обертку» для вызываемой функции API и обеспечиваем возвращение стандартного типа исключения:
> LocalPort port = new LocalPort(12);
> try {
> port.open();
> } catch (PortDeviceFailure e) {
> reportError(e);
> logger.log(e.getMessage(), e);