java - пример - Почему у меня нет catch для проверенного исключения для вызова, который генерирует общий?




try() java (2)

Это поведение указано в разделе 11.2.3 JLS :

Это ошибка времени компиляции, если предложение catch может уловить проверенный класс исключений E1 и это не тот случай, когда блок try, соответствующий предложению catch, может выдать проверенный класс исключений, который является подклассом или суперклассом E1 , если только E1 является Exception или суперкласс Exception .

MyCheckedException соответствует описанию класса E1 выше, поскольку он не объявлен в общем объявлении processable.apply() , и это не Exception или один из его суперклассов. Компилятор знает только, что метод может Throwable , поэтому MyCheckedException не объявляется.

Я работаю над небольшим помощником, который должен вызывать произвольный код (передается как лямбда). Помощник должен поймать определенные исключения и бросить их в какую-нибудь обертку. Мои «собственные» исключения не должны быть обернуты, а просто переброшены.

Я придумал этот код:

@FunctionalInterface
interface Processable<T, X extends Throwable> {
    public T apply() throws X;
}

class MyCheckedException extends Exception { ... }
class MyCheckedExceptionWrapper extends MyCheckedException { ... }

public class MyExceptionLogger<T, X extends Throwable> {
    public T process(Processable<T, X> processable) throws MyCheckedException {
        try {
            return processable.apply();
        } catch (MyCheckedException thrown) { // this line isn't accepted
            throw thrown;
        } catch (Exception | LinkageError thrown) {
            throw new MyCheckedExceptionWrapper(thrown);
        } catch (Throwable thrown) {
           ... just log
          return null; 
        }
    }
}

Приведенное выше дает ошибку компиляции:

Недостижимый блок catch для исключения MyCheckedException. Это исключение никогда не выбрасывается из тела оператора try MyExceptionLogger ...

Другими словами: хотя apply() определен для того, чтобы сбрасывать некоторые X extends Throwable я не могу поймать конкретное исключенное исключение при вызове этого метода.

Я знаю, что могу перейти к рабочему коду, поймав Throwable , чтобы затем использовать проверки instanceof но я хотел бы понять, почему невозможно попробовать try / catch, как описано выше.


Я думаю, что существует - на основе JSL - нет веской причины, по которой вы не должны улавливать свое выборочное проверочное исключение в своем примере.

Если вы прочтете цитату из JLS

Это ошибка времени компиляции, если предложение catch может уловить проверенный класс исключений E1 и это не тот случай, когда блок try, соответствующий предложению catch, может выдать проверенный класс исключений, который является подклассом или суперклассом E1 , если только E1 является Exception или суперкласс Exception .

Ловушку-предложение должно быть разрешено поймать любое проверенное Exception , если метод в соответствующем try-блоке объявляет Throwable . В вашем примере блок try может MyCheckedException проверенный класс исключений, который является подклассом или суперклассом MyCheckedException а именно Throwable и MyCheckedException , очевидно, не является Exception или суперклассом Exception

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

@FunctionalInterface
interface Processable<T> {
    public T apply() throws Throwable;
}


private <T> T process(Processable<T> aProcessable) {
    try {
        return aProcessable.apply();
    } catch (MyCheckedException e) {
        e.printStackTrace();
    } catch (Exception e) {
        e.printStackTrace();
    } catch (Throwable e) {
        e.printStackTrace();
    }

    return null;
}

То есть эта проблема как-то должна быть связана с использованием дженериков в сочетании с исключениями. Возможно, это связано с стиранием типа, но с стираемыми типами ваш пример отлично работает:

@FunctionalInterface
interface Processable {
    public Object apply() throws Throwable;
}


private Object process(Processable aProcessable) {
    try {
        return aProcessable.apply();
    } catch (MyCheckedException e) {
        e.printStackTrace();
    } catch (Exception e) {
        e.printStackTrace();
    } catch (Throwable e) {
        e.printStackTrace();
    }

    return null;
}






try-catch