如何欺骗编译器,在Lambda中抛出受检异常

0x01:问题

写代码的时候遇到了一个需要在Java8 Predicate中抛出异常的问题,但无法通过编译:

Predicate<Integer> REQUESTCHECK = (value) -> {
        switch (value) {
            case 401:
                throw new InvalidTokenException();
                break;
            case 429:
                throw new RequestTooManyException();
                break;
            case 500:
                throw new ServiceUnavailableException();
                break;
            default:
                return true;
        }
        return false;
    };

请忽略我所抛出的自定义异常,但它们都属于受检异常。

0x02:分析

函数只实现了Predicate接口,但我无法修改原生类源码,所以得用非受检异常包装,或者绕过编译器的检查。

0x03:解决

利用泛型把要抛出异常的类型隐藏起来了,从泛型方法的声明来看,编译器不能明确的知道抛出异常类型,这样就把异常留给了运行时。

public class ExceptionUtils {
    public static <E extends Exception> void doThrow(Exception e) throws E {
        throw (E)e;
    }
}

将***0x01***的代码修改一下,就能通过编译,并且能在Function外部捕获那些异常:

Predicate<Integer> REQUESTCHECK = (value) -> {
        switch (value) {
            case 401:
                ExceptionUtils.doThrow(new InvalidTokenException());
                break;
            case 429:
                ExceptionUtils.doThrow(new RequestTooManyException());
                break;
            case 500:
                ExceptionUtils.doThrow(new ServiceUnavailableException());
                break;
            default:
                return true;
        }
        return false;
    };