Что положить в предложение throws метода интерфейса? - PullRequest
5 голосов
/ 26 ноября 2010

Предположим, у меня есть интерфейс I и два класса A и B, которые его реализуют. Реализация метода f этого интерфейса в A выбрасывает один набор исключений, а реализация в B выбрасывает другой набор. Единственный общий предок этих исключений - java.lang.Exception. Разумно ли в этом случае объявить f бросать java.lang.Exception? Любые другие альтернативы?

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

Пример:

interface I {
    void f() throws Exception;
}

class A implements I {
    public void f() throws IOException {}
}

class B implements I {
    public void f() throws InterruptedException {}
}

Ответы [ 3 ]

16 голосов
/ 26 ноября 2010

Причиной использования интерфейса является абстрагирование деталей реализации.

Выбрасывая эти исключения, вы раскрываете детали реализации, которые, вероятно, следует абстрагировать.

Возможно, было бы лучше определить новое исключение. Затем каждая реализация f () будет перехватывать известные ей исключения и вместо этого выдает новое исключение, чтобы вы получили:

interface I {
    void f() throws MyException;
}

class A implements I {
    public void f() throws MyException {
         try {
             ...
         } catch (IOException e) {
             throw new MyException(e);
         }
    }
}

class B implements I {
    public void f() throws MyException {
         try {
             ...
         } catch (InterruptedException e) {
             throw new MyException(e);
         }
    }
}

Оборачивая исключение реализации, вы все равно выставляете его вызывающей стороне, и это может укусить вас, когда вы вызываете удаленные методы. В этих случаях вам нужно проделать дополнительную работу для получения полезной информации в общем виде.

Редактировать
Похоже, идет спор о правильном подходе.

Когда мы вызываем f (), нам понадобится такой код:

I instanceOfI = getI();
try {
    instanceOfI.f();
}
catch ( /* What should go here ? */ )

Все сводится к тому, что является хорошим классом Exception для помещения в блок catch.
С помощью исходного кода OP мы могли бы поймать Exception и затем, возможно, попытаться увидеть, какой у нас подкласс, или нет, в зависимости от требований. Или мы могли бы по отдельности перехватить каждый подкласс, но тогда мы должны были бы добавить блоки catch, когда новые реализации генерируют разные исключения.

Если бы мы использовали исключения Runtime, это привело бы к тому же самому, за исключением того, что мы могли бы альтернативно отложить обработку исключений до метода вызывающей стороны, даже не задумываясь об исключениях.

Если мы воспользовались моим предложением об использовании нового обернутого исключения, это означает, что мы должны поймать MyException и затем попытаться увидеть, какая дополнительная информация доступна. По сути, это очень похоже на использование исключения, но требует дополнительной работы для ограниченного преимущества, связанного с исключением bespoke, которое может быть адаптировано к цели.

3 голосов
/ 26 ноября 2010

Это кажется немного отсталым. Вы должны выдавать исключения, которые имеют отношение к вашему интерфейсу и, возможно, специфичны для него, или вообще не нужны. Измените реализации, чтобы обернуть общий класс Exception (хотя не сам Exception). Если вы не можете справиться с этим, вы можете заключить Исключения в реализациях в RuntimeException.

1 голос
/ 26 ноября 2010

Вы можете просто объявить исключения, которые вы выбросили

void f() throws IOException, InterruptedException;

Если вы используете достойную IDE, это исправит это для вас.Я просто выбрасываю исключение в методе, который IDE предоставляет опциям для добавления к методу метода и его интерфейсу.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...