绕过try/catch块以检查异常的Lamdas [英] Lamdas that bypass try/catch blocks for checked exceptions

查看:97
本文介绍了绕过try/catch块以检查异常的Lamdas的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

由于我尝试提取了我在大多数项目中使用的一些常见的包装lambda例程,因此我能够创建由PermeableFunction FunctionalInterface子类化的CheckedFunction,从而绕过了try/catch的需求块.我已经在Windows(v1.8.0_251)/linux(v1.8.0_261)和其他几个在线编译器的Oracle jdks上进行了测试(不确定在那里使用了哪种实现).

As a result of me trying to extract some common wrapping lambda routines that I use in most of my projects, I've been able to create CheckedFunction, subclassed by PermeableFunction FunctionalInterface that bypasses the need of try/catch blocks. I've tested that on Oracle jdks for windows(v1.8.0_251)/linux(v1.8.0_261) and several other online compilers(not sure which implementation is used there).

不确定这是否确实违反了规范或标准是否允许...根据我对

Wasn't sure if this actually violates the specification or is something allowed by the standard... According to my interpretaion of the docs this should not be possible:

更准确地说,假设B是类或接口,而A是B的超类或超接口,并且B中的方法声明n覆盖或隐藏A中的方法声明m.然后:

More precisely, suppose that B is a class or interface, and A is a superclass or superinterface of B, and a method declaration n in B overrides or hides a method declaration m in A. Then:

  • 如果n具有引发任何检查过的异常类型的throws子句,则m必须具有throws子句,否则会发生编译时错误.
  • 对于n的throws子句中列出的每个检查的异常类型,必须在m的throws子句的擦除(第4.6节)中出现相同的异常类或其超类型之一;否则,将发生编译时错误.
  • 如果m的未擦除throws子句在n的throws子句中不包含每种异常类型的超类型,则会发生编译时未经检查的警告.

这是我使用的示例代码:

Here is the sample code that I've used:

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.function.Function;

public class Main {

    public static void main(String[] args) {

        PermeableFunction<Path, Long> function = PermeableFunction.from(Files::size);

        Path doesNotExist = Paths.get("/does/not/exist");

        // function.apply(doesNotExist); -> throws WrappedException
        function.applyChecked(doesNotExist); // throws NoSuchFileException without the need of a try/catch block!
    }
}

interface PermeableFunction<T,R> extends CheckedFunction<T, R, RuntimeException> {

    static <T, R> PermeableFunction<T, R> from(WrappedFunction<T, R> wrappedFunction) {

        return CheckedFunction.<T,R, RuntimeException>from(wrappedFunction)::applyChecked;
    }
}

interface CheckedFunction<T, R, E extends Exception> extends WrappedFunction<T, R> {

    @Override
    R applyChecked(T t) throws E;

    static <T, R, E extends Exception> CheckedFunction<T, R, E> from(WrappedFunction<T, R> wrappedFunction) {

        return wrappedFunction::applyChecked;
    }
}

interface WrappedFunction<T, R> extends Function<T, R> {

    R applyChecked(T t) throws Exception;

    @Override
    default R apply(T t) {

        try {

            return applyChecked(t);

        } catch (Exception e) {

            throw new WrappedException(e);
        }
    }
}

class WrappedException extends RuntimeException {

    public WrappedException(Throwable cause) {
        super(cause);
    }
}

CheckedFunction还允许对可抛出对象进行阴影处理,如下所示:

CheckedFunction also allows shadowing of the throwable like so:

这是我的问题:

这是应该报告给实施者的问题,还是该标准强加的普遍问题?

Is this something that should be reported to the implementer(s) or it's a general issue imposed by the standard?

推荐答案

您的方法

static <T, R, E extends Exception> CheckedFunction<T, R, E> from(WrappedFunction<T, R> wrappedFunction) {
    return wrappedFunction::applyChecked;
}

被我的Eclipse版本以及所有9至14的所有JDK的javac拒绝.只有JDK 8接受了它,所以这是一个错误,但是不值得报告,因为较新的版本没有它.

was rejected by my Eclipse version, as well as javac of all JDKs from 9 to 14. Only JDK 8 accepted it, so it’s a bug, but not worth reporting, as newer versions do not have it.

也就是说,可以通过泛型类型系统来颠覆异常检查.

That said, subverting the exception checking via the generic type system is possible.

将方法更改为

static <T, R, E extends Exception> CheckedFunction<T, R, E> from(WrappedFunction<T, R> wrappedFunction) {
    return (CheckedFunction)(CheckedFunction<T, R, Exception>)wrappedFunction::applyChecked;
}

所有编译器都将接受它,但是会产生未经检查"的警告.这是已知的事情.

all compilers will accept it, but produce an "unchecked" warning. This is a known thing.

您可以将示例简化为:

public class Main {
    public static void main(String[] args) {
        CheckedFunction<Path, Long, RuntimeException> function = (CheckedFunction)
            (CheckedFunction<Path, Long, IOException>)Files::size;
        Path doesNotExist = Paths.get("/does/not/exist");

        function.applyChecked(doesNotExist); // throws NoSuchFileException without the need of a try/catch block!
    }

    interface CheckedFunction<T, R, E extends Exception> {
        R applyChecked(T t) throws E;
    }
}

即使没有lambda表达式,也可能有多种变体.它所需要的只是一个使用类型参数的throws声明以及与此类型参数有关的未经检查的操作.

There are several variations possible, even without lambda expressions. All it needs, is a throws declaration using a type parameter and an unchecked operation regarding this type parameter.

例如

public class Main {
    public static void main(String[] args) {
        try {
            Files.size(Paths.get("/does/not/exist"));
        }
        catch(IOException ex) {
            doThrow(ex); // throws undeclared IOException
        }
    }

    static <T extends Throwable> void doThrow(Throwable t) throws T {
        throw (T)t;
    }
}

如前所述,这是众所周知的,但总的来说,您永远不应忽略未经检查"的警告.

As said, this is known and the takeaway is, you should never ignore "unchecked" warnings.

这篇关于绕过try/catch块以检查异常的Lamdas的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆