Почему вам нужно поймать "Исключение", но не подкласс "RuntimeException"?

На приведенном ниже рисунке показано, что "Проверено" и "Непроверено" Исключения являются подклассами Exception. Я сбиваю с толку, что вам нужно поймать Exception, но вам не нужно ловить RuntimeException, который непосредственно наследуется от Exception. Есть ли причина, по которой разработчики не позволяли нам бросать Исключения, не требуя их поймать?

В частности: почему вы можете игнорировать только RuntimeExceptions и это дети? Почему не было класса, введенного под названием CheckedException extends Exception, и вам нужно только его поймать и это дети?

Сбивая с толку часть, вы можете выбросить все ниже RuntimeException без проблем, но когда вы переходите к Exception в иерархии, вам нужно поймать ее в какой-то момент. Это сбивает с толку, потому что "абстракция" обычно работает иначе. Чем больше вы продвигаетесь, тем больше становится все больше и больше мета. Здесь не так. Чем больше вы двигаетесь вверх, тем больше вам нужно делать (например, ставить try/catch после достижения Exception).

введите описание изображения здесь

Ответ 1

Если флажок Exception не установлен, вы можете неявно использовать проверенные исключения для непроверенных, что означало бы, что вы могли бы перебросить проверенные исключения, не вылавливая их, как:

public void f() {
    Exception e = new IOException();
    throw e;
}

а также с помощью переопределяющих методов, если вы выбрали более конкретное исключение, вы можете добавить требование об исключении, которое не было в суперклассе:

public void f() throws Exception {
}

...

@Override
public void f() throws IOException {
}

Ответ 2

Предположим, что они разработали его другим способом. У нас есть класс CheckedException, и подклассы этого должны обрабатываться, но не другие подклассы Exception.

Теперь мы вызываем метод, который может вызвать произвольный Exception:

public static void example() {
    functionThatThrowsException();
}

Нужно ли нам это обрабатывать? Да, потому что Exception может быть CheckedException. Если нам не нужно было его обрабатывать, мы бы обошли проверенный характер проверенных исключений.

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

Ответ 3

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

У вас, похоже, есть идея, что проверенные исключения более сложны, потому что вам нужно больше работать, чтобы обойти их. Это не слишком здоровый способ думать об этом. Вместо этого учтите следующее: Исключения представляют собой проблемы с самой программой - кодом. Нам нужно найти эти исключения и правильно их обработать. После того, как уже существует эта концепция обработки исключений, мы обнаруживаем, что есть некоторые проблемы, которые мы просто не можем предсказать.

"Как я должен был знать, что пользователь вводит" мяу ", когда его попросят целое число! Мне не нужно было бы это кодировать!" Итак, NumberFormatException родился, и вам не нужно его ловить, потому что это "логическая ошибка", а не проблема, вызванная неправильным кодом (хотя, возможно, это может считаться плохим кодом, если вы не обрабатываете эта ситуация в некотором роде).

Короче говоря, отмените свое мышление. Exception - проблемы с программой, которые могут быть обработаны. Однако есть некоторые исключения, которые являются неожиданными и являются результатом плохой конструкции больше, чем неправильный код. Таким образом, существует добавление RuntimeException, которое невозможно ожидать, но, безусловно, может произойти.

Ответ 4

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

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

Мы можем выбросить любое исключение, проверить или снять флажок. Если Exception или любой суперкласс RuntimeException должны были быть установлены как проверенное исключение, тогда все подкласс станут проверенными исключениями. Поскольку компилятор, скорее всего, проверяет, возникает ли экземпляр исключения или класс в предложении throws из класса. Это могло бы легко сделать, проверив конкретный пакет, который, вероятно, был бы более уместным, поскольку он проверяется или не проверяется, просто не имеет ничего общего с наследованием.

Ответ 5

В вашем изображении уже есть ответ - Throwable отмечен и должен быть пойман, из-за этого проверяется Exception и т.д., кроме RuntimeException и его потомков.

Проверенные исключения должны быть пойманы или возвращены (JLS §11.2). Это гарантировано с помощью java-компилятора, поэтому мы гарантируем, что наша "исключительная" ситуация будет обработана.

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

Если вы меняете логику, тогда вы не можете предоставить эти гарантии во время компиляции:

public void notReallySafeMethod() {
    try {
        connect();
    } catch (IOException io) {
        Exception e = io;
        throw e; // IOException is unhandled
    }
}

public void suspiciousMethod() throws Exception {};

public void callSuspicious() {
    suspiciousMethod(); // what real type would be thrown? we can't know
    //  should I try-catch everything then?
}