Противоречащие спецификации исключений для одного и того же метода в разных интерфейсах - PullRequest
2 голосов
/ 18 января 2012

В следующем коде:

class MyException extends Exception{}

interface Bread
{
    public void eat() throws MyException;
}

interface Fringe 
{
    public void eat() throws RuntimeException;
}

public class Test implements Fringe , Bread // #5
{
    public static void main(String[] args)
    {
        Fringe best = new Test(); // #1
        best.eat();// #2
    }

    public void eat() throws RuntimeException // #3
    {
        System.out.println("Test");
        throw new RuntimeException(); // #4
    }
}

MyException не является RuntimeException. Почему мы можем объявить Test.eat() броском RuntimeException, но не общим Exception?

Ответы [ 3 ]

4 голосов
/ 18 января 2012

Это связано с тем, что в методе переопределения вы можете выдавать только исключения, ниже или равные исключению, определенному в вашем контракте. Таким образом, eat() может выбросить MyException и его подклассы, но не все, что выше MyException, что и есть Exception. Исключения времени выполнения не являются частью этого правила, и вы можете свободно их выбрасывать, поскольку они не «проверены».

Это потому, что, скажем, я использую интерфейс Bread для доступа к экземпляру класса Test. Если я вызову метод eat(), я смогу «проверить» наличие MyException, поскольку это часть контракта, но если базовая реализация решит выбросить «более высокое» исключение, оно не будет обнаружено в моем MyException catch блокировать, тем самым нарушая договор. Посмотрите на приведенный ниже код для примера:

Bread b = new Test();
try {
  // if this throws Exception, it won't be caught in the catch block
  // thereby violating contract
  b.eat(); 
} catch (MyException e) {
  e.printStacktrace();
}
2 голосов
/ 18 января 2012

Две точки:

  • Вы не можете объявить его для выброса Exception, потому что тогда оно вызовет более общее исключение, чем тот, который указывает метод eat() в интерфейсе Bread.Метод, унаследованный от суперкласса или интерфейса, не может генерировать более общие исключения, чем указано в суперклассе или интерфейсе.
  • Вы можете объявить его для выброса RuntimeException, потому что методы всегда могут генерировать непроверенные исключения, независимо от того, указаны вы ихв throws предложении или нет.(Поэтому указание, что он может выдать RuntimeException, является избыточным.)

Чтобы объяснить причину правила, которое я упомянул в первом пункте: предположим, вы делаете это:

// Allowed because Test implements Bread
Bread obj = new Test();

Если вы сейчас вызываете obj.eat(), компилятор должен проверить, правильно ли вы обрабатываете все проверенные исключения, которые могут произойти в этом вызове.Это достигается путем просмотра типа переменной obj, которая равна Bread.Интерфейс Bread указывает, что eat() может выдавать MyException (и неявно, подклассы MyException).

Если вашему методу Test.eat() было разрешено генерировать более общий вид проверяемого исключения,например, Exception, компилятор не может проверить, просто посмотрев тип obj, что вы правильно обрабатываете все проверенные исключения.

Для предотвращения этой проблемы правило состоит в том, что переопределенный метод не разрешенбросить более общие исключения.

0 голосов
/ 18 января 2012

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

Если вы попытаетесь выбросить Exception в вашем классе, в то время как интерфейс выдает MyException ... компилятор видит, верно ли следующее утверждение:

Исключение IS-A MyException - и это ложь, вы знаете.поэтому компилятор отклоняет его.

Следовательно, вы можете выбросить только более конкретное исключение из метода в подклассе.

для вашего вопроса об исключении RunTime:

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

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