如何告诉java泛型类型是一个功能接口?

时间:2017-02-02 16:43:35

标签: java generics lambda

我有一个通用的功能接口来询问用户有关错误(与java.util.function.Function非常相同)和一些参数化子接口:

@FunctionalInterface
public interface Handler<Err,Resp> {
    public Resp handle(Err param);
}
@FunctionalInterface
public interface RecoverableErrorHandler<Err> extends Handler<Err, RecoverableErrorResult > {}

@FunctionalInterface
public interface RetryIgnoreErrorHandler<Err> extends Handler<Err, RetryIgnoreAbortResult> {}

我想通过将处理程序包装到另一个处理程序中来为每个处理程序添加日志记录:

private <Err,Resp,H1 extends Handler<Err,Resp> > H1 addLogToHandler(String s, H1 h) {
    return (Err arg) -> {
        Resp res = h.handle(arg);
        logger.info(s+" returned "+res);
        return res;
    };
}

// some code omitted
RecoverableErrorHandler<String> netErrorHandler = ... // shows dialog and asks user what to do
netErrorHandler = addLogToHandler("Network Error handler", netErrorHandler);

这不会与error: incompatible types: H1 is not a functional interface一起编译return

问题是,我可以告诉java通用H1是一个功能接口吗?或者,我如何使这个代码工作?

1 个答案:

答案 0 :(得分:2)

没有办法告诉编译器H1应该是一个功能接口,事实上,你甚至不能告诉它H1应该是一个接口。

当您考虑它时,您可能会注意到,即使您能够将H1限制为扩展Handler<Err,Resp>的功能接口,也无法保证此类型具有兼容的功能类型代码中的lambda表达式。

例如,以下是满足约束条件的类型:

@FunctionalInterface
public interface Foo<E,R> extends Handler<E,R>, Runnable {
    default R handle(E param) { run(); return null; }
}

这是一个功能界面,它扩展了Handler,但尝试在addLogToHandler中使用(Err) -> Resp签名来实现它是不行的。

解决方案很简单。只需完全删除子接口RecoverableErrorHandler<Err>RetryIgnoreErrorHandler<Err>即可。与使用Handler<Err,RecoverableErrorResult> resp相比,它们没有任何优势。直接Handler<Err,RetryIgnoreAbortResult>

删除子类型后,您可以将方法更改为

private <Err,Resp> Handler<Err,Resp> addLogToHandler(String s, Handler<Err,Resp> h) {
    return arg -> {
        Resp res = h.handle(arg);
        logger.info(s+" returned "+res);
        return res;
    };
}