Подтвердить что ты не робот

Исключение и наследование в Java

Предположим, что мы имеем эту проблему

public class Father{
    public void method1(){...}
}

public class Child1 extends Father{
    public void method1() throws Exception{
    super.method1();
    ... 
    }

}

Child1 extends Father и переопределяет method1, но с учетом реализации Child1.method1 теперь выдает исключение. Это не будет компилироваться, поскольку метод переопределения не может генерировать новые исключения.

Какое наилучшее решение?

  • Распространять необходимое исключение на Father. Для меня это против инкапсуляции, наследования и общего ООП (Father потенциально генерирует исключение, которое никогда не произойдет).
  • Вместо этого используйте RuntimeException? Это решение не будет распространять Exception на Father, но документы Oracle и другие источники утверждают, что класс исключений должен использоваться, когда "Клиентский код не может ничего сделать". Это не тот случай, это исключение будет полезно для восстановления blablabla (почему это неправильно использовать RuntimeException вместо?).
  • Другое..
4b9b3361

Ответ 1

Использование RTE - неплохая идея. Это методология структуры Spring, и она работает отлично. Если вы используете приложение, вероятно, используйте это решение.

Если вы используете библиотеку, которая предоставляет API IMHO, вы должны использовать проверенное исключение. В этом случае вы должны создать свое собственное исключение, например BaseException. Метод method() of Father бросит его. Определите ChildException extends BaseException и объявите method1() дочернего класса бросить его.

Это не разрушает инкапсуляцию: базовый класс создает базовое исключение. Он не имеет никакого представления о конкретном исключении. Класс Child создает конкретное исключение, которое, однако, расширяет базовое исключение и поэтому может быть обработано клиентским кодом как базовое исключение.

В качестве примера я могу дать вам IOException и FileNotFoundException, который расширяет его. Вы можете работать с захватом входного потока IOException, в то время как бетонный поток FileInputStream, и он бросает FileNotFoundException. Но клиент этого не знает. Он ловит IOException.

Ответ 2

Если метод суперкласса не объявляет об исключении, то метод переопределения подкласса не может объявить проверенное исключение. Таким образом, вы можете использовать исключение Unchecked.

Другой вариант - разрешить Super class объявлять ParentException, а затем переопределенные методы ребенка могут объявлять любые исключения, которые являются дочерними элементами ParentException

Ответ 3

Зависит от того, что выбрасывает исключение в Child1. Если его некоторые предварительные условия и т.д., Вы всегда можете использовать любой из подклассов RuntimeException, например IllegalArgumentException.

Однако, если есть какое-то CheckedException, тогда логика предполагает, что вы должны обработать этот метод сам по себе и каким-то другим образом создать сообщение.

Я думаю, что общее правило состоит в том, что

если вы знаете, как с ним справиться.. используйте проверенное исключение else unchecked exception

Ответ 4

Часть "бросает" является частью сигнатуры метода.
Вот почему метод в "дочернем" классе не является переопределением метода родительского класса.

Ответ 5

Распространение обязательного исключения для Отца. Мне это противоречит инкапсуляции, наследованию и общему ООП (отец потенциально бросает и исключение, которое никогда не произойдет)

Au contraire: Это хороший OO. Изображение стороны вызывающего абонента:

Father f = factory.getSomeImplementation();
f.method1();
// user has no chance to see the `Exception` of Child coming...

factory может возвращать экземпляр Father или Child или что-то совершенно другое, например Brother. Но контракт method1 должен быть таким же во всех случаях. И этот контракт включает проверенные исключения. Это принцип замещения Лискова, один из основных правил OO.

Итак, если исключение является частью бизнес-контракта method1, оно должно быть объявлено в корне. Если это не так (например, простая проверка аргумента), то RuntimeException - это маршрут, который нужно идти в любом случае (т.е. Даже без наследования).