2009-08-03 7 views
16

Какова наилучшая практика, когда вам нужно создать исключение, которое не было определено в интерфейсе, который вы реализуете?Выбрасывание исключения не определено в интерфейсе

Вот пример:

public interface Reader 
{ 
    public abstract void read() throws IOException; 
} 

public class CarrotReader implements Reader 
{ 
    public void read() throws IOException {} 
} 

public class CupcakeReader implements Reader 
{ 
    public void read() throws IOException, CupcakeException {} 
} 

В этом случае, у вас есть определенное исключение, которое происходит при чтении кексов, так что вы хотите бросить исключение, связанное с этим. Однако Reader не определяет этот тип исключения в своем интерфейсе, так что вы делаете? Кроме того, это не имеет смысла, чтобы добавить CupcakeException к бросает пункт в Считыватель интерфейсу , так как этот тип исключения является специфичным для CupcakeReader. Один из способов: Читатель определяет так, чтобы он выдавал некоторый родительский тип, например Исключение, но затем вы теряете контекст для исключения. Что вы должны делать в этой ситуации? Благодаря!


Другая интересная ситуация, которая возникла, связана с интерфейсом, над которым вы не контролируете. В этом случае, каков наилучший способ указать, что возникла проблема?

Для наглядности, вот еще один пример:

public interface Reader 
{ 
    public abstract void read(); 
} 

public class CupcakeReader implements Reader 
{ 
    public void read() throws CupcakeException {} 
} 

В этом случае, вы не можете изменить чтения, но вы хотите, чтобы указать, что проблема возникла в CupcakeReader «s чтения метод.

+0

Это еще хуже, чем я думал. Таким образом, вы даже не можете использовать цепочку для обхода системы. Я думаю, вы должны прибегать к (ouch!) 'RuntimeExceptions'. –

+0

Я прибегал к System.err.println и exception.printStackTrace() ;. Является ли это подходящим, или я должен распространять ошибку с помощью RuntimeExecption, как вы сказали? – Scott

+3

Я думаю, что log + ласточка не подходит 99,99% времени. Это распространенная (анти-?) Модель среди разработчиков Java из-за проблемы, представленной здесь. В моей «школе мысли» есть только три действительных способа устранения исключений: реинтронирование, обработка (то есть исправление проблемы), или пусть это пузырится до тех, кто может справиться с этим. Никогда не глотайте. Если что-то пойдет не так, будут последствия. –

ответ

12

Возможно, вам придется создавать исключение ожидаемого типа.

... catch(CupcakeException e) { 
    throw new IOException("The sky is falling", e); 
} 
+1

+1 для обозначения цепочки исключений. –

+0

Это то, что я делаю в данный момент. – Scott

+0

Это, вероятно, лучшее решение, если вы не можете изменить интерфейс. Вы можете получить доступ ко всей информации, которая вам может понадобиться, и вы по-прежнему следуете контракту интерфейса. –

0

Возможно, вы могли бы создать абстрактный класс ReaderSpecificException, поместить его в интерфейс и подкласс CupcakeException из этого абстрактного класса.

+1

Я не думаю, что это хорошая практика для создания исключения как абстрактного класса. По умолчанию исключение без каких-либо атрибутов в нем все же может обеспечить понимание проблемы (просто выбрав правильное имя). Почему вы хотите определить его как абстрактный класс? – Manglu

9

Используйте что-то, называемое ReaderException, которое будет служить корневым интерфейсом вашей иерархии исключений. ReaderException также предоставляет ссылку на другие исключения, которые могут быть выбраны из-за исключений более низкого уровня.

+0

Разве это не то же самое, что добавление исключения в предложение бросков? Я понимаю, что, определяя свой собственный родительский класс, который несколько более определен, вы сохраняете больше контекста, но на каком-то уровне вы по-прежнему теряете информацию, верно? – Scott

+0

Это то, что я обычно делаю (+1). Но что бы вы сделали, если бы вы не могли изменить интерфейс (код не ваш, код уже отправлен и т. Д.)? –

+0

@Scott: вы ничего не теряете. Если вы выкинете 'CupcakeException', который расширяет' ReaderException', вы можете поймать его либо как 'ReadException', либо как' CupcakeException', в зависимости от того, насколько вы конкретно хотите. –

0

Если создать более высокое абстрактное исключение, которое работает в качестве базового класса для CupCakeException вы не связывать чтения интерфейса к конкретной реализации, как вы будете делать, если вы добавили CupCakeException к интерфейсу Reader. Если вы не допустили, чтобы одно исключение наследовалось от другого, в классе исключений есть класс constructor, который принимает забрасываемый второй аргумент, такой как Thorbjørn Ravn Andersen, который уже показан в его примере с коротким кодом. Это позволяет вам генерировать более абстрактное исключение, и каждая часть вашего кода, которая должна знать больше, а затем просто «есть ошибка», может искать причину более высокого исключения.

1

Только не используйте проверенные исключения.

Пример, который вы показали, является одной из причин, по которым проверенные исключения являются плохими.

Основная причина заключается в том, что пользователь вашего читателя кексов должен будет обработать ваше исключение, независимо от того, заинтересован ли он в нем или нет.

Таким образом, вместо:

Value value = reader.read(); 

Вы вынуждаете его сделать это:

Value value = null; 
try { 
    value = reader.read(); 
} catch (Exception e) { 
    // now what?? 
} 

value.doSomething(); // potential NPE here 

Подумайте, какой из них лучше, более удобным для чтения и менее подвержены ошибкам и просто прекратить использование отмеченных исключений.

EDIT:

Я удивлен, с отрицательным рейтингом. Есть люди, которые все еще считают, что проверенные исключения велики? Если так вот некоторые ссылки, почему вы не должны использовать проверенные исключения:

  • Ни одна современная структура не использует проверенные исключения (Spring, EJB3 и т.д.)
  • Статьи с примерами кода here
  • StackOverflow topic
  • Эффективное Java (разделы 58 и 59) - here
+4

Я думаю, что вы публикуете преднамеренно вводящий в заблуждение пример. Я бы написал выше, чтобы объявить и использовать переменную в блоке try {}. Нет причин, по которым вам придется писать код, как указано выше (независимо от того, отмечены ли исключения) –

+5

Проблема с проверенными исключениями не такая, как здесь. Как отметил Брайан, этот код просто неправильный. Одна из проблем с проверенными исключениями заключается в том, что вы теряете любую выгоду от выполнения предварительных проверок (когда можете) перед вызовом кода, который генерирует исключения. Даже если вы выполняете предварительные проверки, вы вынуждены использовать блок try-catch. Другим является тот факт, что если у вас есть что-то N метод вызывает глубины, которые бросает, и только вызов 0 может обрабатывать его, каждый вызов от 0 до N должен включать в себя броски в контракте (или обманывать с помощью 'RuntimeException' –

+0

. информация о «почему-нет» проверенных исключений: http://www.artima.com/intv/handcuffs.html –

2

Исключение является частью интерфейса. Определите родительский родитель для всех ваших исключений в интерфейсе, если вы можете переопределить интерфейс.

Вы также можете сделать CupcakeException ребенком исключения IOException.

+0

Имейте «голосование» за «также». Но я предвзятый, потому что это то, что я, скорее всего, сделал бы (подкласс объявленного исключения, если нужно). Конечно, наличие подкласса (например,) IOException предполагает, что вызывающий абонент должен действительно заботиться о том, чтобы что-то более конкретное происходило, а также подразумевая, что проблема действительно является какой-то проблемой, связанной с I/O. – Roboprog

Смежные вопросы