Почему одно из этих повторных исключений создает ошибку компилятора?

Почему throw outerE; генерирует ошибку компиляции? Я знаю, что throw e; не должен генерировать ошибку компилятора из-за точной функции ретролина.

Они представляют собой один и тот же объект Exception, но один из них ограничен только внутри блока catch, а другой - вне блока try-catch.

Не должно ли ни одна из них генерировать ошибку компилятора? Или, по крайней мере, оба ведут себя одинаково?

static void preciseRethrowTest()
{
    Exception outerE;
    try
    {

    }
    catch (Exception e)
    {
        outerE = e;

        // Compilation error here. Unhandled exception type Exception
        // throw outerE; 

        throw e; // No compiler error
    }
}

Я использую Java 1.8.0_51. (Точный ретрон введен в Java 7)

Ответ 1

В вашем методе нет объявлений throws.

Компилятор теперь достаточно умен, чтобы определить, что ваш блок try не может выкинуть любые проверенные исключения. Поэтому любые исключения, обнаруженные и привязанные к параметру Exception в вашем блоке catch, должны быть сняты. Поскольку они не отмечены, вы можете восстановить их на досуге (и они не потребуют объявления throws).

Здесь вы пытаетесь переназначить

outerE = e;
// Compilation error here. Unhandled exception type Exception
// throw outerE; 

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

Рассмотрим код типа

if (Math.random() < 0.5) 
    outerE = e;
else 
    outerE = new IOException("nope");
throw outerE; 

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

Ответ 2

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

Рассмотрим это:

public class RethrowTest {
  static void preciseRethrowTest() {
    Exception outerE;
    try {
      throw new Exception();
    } catch (Exception e) {
      outerE = e;

      // Compilation error here. Unhandled exception type Exception
      // throw outerE;

      throw e; // Now a compiler error *is* generated.
    }
  }
}

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