Я просто хочу добавить некоторые соображения, чтобы вообще не использовать проверенные исключения. Это не полный ответ, но я чувствую, что он отвечает на часть вашего вопроса и дополняет многие другие ответы.
Всякий раз, когда задействованы проверенные исключения, 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 like IFoo foo;
и позже решить, какую реализацию я хочу использовать, например foo = new Bar();
. Если метод Бар foo () не переопределяет метод IFoo IFoo, то когда я это сделаю, foo.foo();
он не вызовет реализацию Баром функции foo ().
Чтобы сделать public void foo() throws InterruptedException
переопределение Баром IFoo, public void foo()
я ДОЛЖЕН добавить throws InterruptedException
к сигнатуре метода IFoo. Это, однако, вызовет проблемы с моим классом Foo, поскольку его сигнатура метода foo () отличается от сигнатуры метода IFoo. Кроме того, если бы я добавил throws InterruptedException
в метод Foo foo (), я получил бы еще одну ошибку, утверждая, что метод Foo foo () объявляет, что он генерирует InterruptedException, но никогда не генерирует InterruptedException.
Как вы можете видеть (если я проделал приличную работу по объяснению этого материала), тот факт, что я выбрасываю проверенное исключение, такое как InterruptedException, заставляет меня связывать мой интерфейс IFoo с одной из его реализаций, что, в свою очередь, вызывает хаос в IFoo другие реализации!
Это одна из основных причин, почему проверенные исключения являются ПЛОХОЙ. В шапках.
Одно из решений состоит в том, чтобы перехватить проверенное исключение, поместить его в непроверенное исключение и выдать непроверенное исключение.
DataSeries
класс, который содержит данные, которые всегда должны оставаться в порядке времени. Есть способ добавить новыйDataPoint
в конецDataSeries
. Если весь мой код работает правильно на протяжении всего проекта,DataPoint
никогда не следует добавлять в конец, который имеет более раннюю дату, чем тот, который уже находится в конце. Каждый модуль во всем проекте построен с этим трюизмом. Однако я проверяю это условие и выкидываю непроверенное исключение, если это происходит. Почему? Если это произойдет, я хочу знать, кто это делает, и исправить это.