【问题标题】:How to tell java that a generic type is a functional interface?如何告诉java泛型类型是函数式接口?
【发布时间】:2017-02-02 16:43:35
【问题描述】:

我有一个通用功能接口来询问用户错误(与 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是一个函数式接口吗?或者,我如何使这段代码工作?

【问题讨论】:

  • 这没有意义。您的返回类型是泛型参数H1。如何在不知道实际类型的情况下创建H1 的实例?
  • 在函数被参数调用和所需返回类型的地方,java 不推断类型吗?在我的示例中,我可以看出在netErrorHandler = addLogToHandler("Network Error handler", netErrorHandler); 中,H1 的类型应该是 RecoverableErrorHandler&lt;String&gt;
  • 那是调用站点,不在方法内。您实际上是在尝试做public &lt;T extends Animal&gt; T method() {return new Dog();}。那怎么办?如果我想调用这个方法并使用Cat 作为泛型类型参数怎么办?
  • 嗯,当它与 lambda 匹配的类型是可以检查的具体类型时。您有一个扩展接口的类这一事实并不意味着它不会扩展其他接口。其中哪一个将成为匹配的功能接口?
  • 好的,关于如何实现所描述的功能有什么想法吗?

标签: java generics lambda


【解决方案1】:

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

当您考虑它时,您可能会注意到,即使您能够将 H1 限制为扩展 Handler&lt;Err,Resp&gt; 的函数式接口,也不能保证此类型具有与 lambda 表达式兼容的函数式类型你的代码。

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

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

这是一个函数式接口,它扩展了Handler,但尝试在addLogToHandler 中使用(Err) -&gt; Resp 签名来实现它是行不通的。

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

消除子类型后,可以将方法改为

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;
    };
}

【讨论】:

  • 谢谢。这就是我最终所做的。
猜你喜欢
  • 1970-01-01
  • 2021-08-16
  • 2018-09-15
  • 1970-01-01
  • 1970-01-01
  • 2020-07-31
  • 1970-01-01
  • 2013-07-05
  • 2020-02-19
相关资源
最近更新 更多