Я просто хочу добавить некоторые соображения, чтобы вообще не использовать проверенные исключения.Это не полный ответ, но я чувствую, что он отвечает на часть вашего вопроса и дополняет многие другие ответы.
Всякий раз, когда включаются проверенные исключения, где-то в сигнатуре метода есть throws CheckedException
(CheckedException
может быть любое проверенное исключение).Сигнатура НЕ выбрасывает исключение, исключение является аспектом реализации.Интерфейсы, сигнатуры методов, родительские классы, все это НЕ должно зависеть от их реализации.Использование проверенных исключений здесь (фактически тот факт, что вы должны объявить throws
в сигнатуре метода) связывает ваши интерфейсы более высокого уровня с вашими реализациями этих интерфейсов.
Позвольте мне показать вам пример.
Давайте создадим красивый и понятный интерфейс, подобный этому
public interface IFoo {
public void foo();
}
Теперь мы можем написать множество реализаций метода foo()
, например:
public class Foo implements IFoo {
@Override
public void foo() {
System.out.println("I don't throw and exception");
}
}
Класс Fooотлично в порядке.Теперь давайте сделаем первую попытку для класса Bar
public class Bar implements IFoo {
@Override
public void foo() {
//I'm using InterruptedExcepton because you probably heard about it somewhere. It's a checked exception. Any checked exception will work the same.
throw new InterruptedException();
}
}
Этот класс Bar не будет компилироваться.Поскольку InterruptedException является проверенным исключением, вы должны либо перехватить его (с помощью try-catch внутри метода foo ()), либо объявить, что вы его выбросили (добавив throws InterruptedException
к сигнатуре метода).Поскольку я не хочу фиксировать это исключение здесь (я хочу, чтобы оно распространялось вверх, чтобы я мог правильно с ним справиться где-то еще), давайте изменим сигнатуру.
public class Bar implements IFoo {
@Override
public void foo() throws InterruptedException {
throw new InterruptedException();
}
}
Этот класс Bar не скомпилируетсяили!Метод Бар foo () НЕ переопределяет метод IFoo foo (), так как их сигнатуры разные.Я мог бы удалить аннотацию @Override, но я хочу запрограммировать интерфейс IFoo, например IFoo foo;
, а затем решить, какую реализацию я хочу использовать, например, foo = new Bar();
.Если метод Бар foo () не переопределяет метод IFoo foo, то когда я делаю foo.foo();
, он не будет вызывать реализацию Баром foo ().
Чтобы public void foo() throws InterruptedException
Бара переопределил IFoo public void foo()
IДОЛЖЕН добавить throws InterruptedException
к сигнатуре метода IFoo.Это, однако, вызовет проблемы с моим классом Foo, так как сигнатура его метода foo () отличается от сигнатуры метода IFoo.Кроме того, если бы я добавил throws InterruptedException
в метод Foo foo (), я получил бы еще одну ошибку, утверждая, что метод Foo foo () объявляет, что он генерирует InterruptedException, но при этом никогда не генерирует InterruptedException.
Как вы можете видеть (если я проделал приличную работу по объяснению этого материала), тот факт, что я выбрасываю проверенное исключение, такое как InterruptedException, заставляет меня привязывать мой интерфейс IFoo к одной из его реализаций, что, в свою очередь, вызывает хаос в других реализациях IFoo!
Это одна из причин, почему проверенные исключения являются ПЛОХОЙ.В заглавных буквах.
Одно из решений - захватить проверенное исключение, заключить его в непроверенное исключение и выбросить непроверенное исключение.