【问题标题】:Java 11 Functional flow infers wrong type on method callJava 11 功能流在方法调用上推断错误类型
【发布时间】:2019-05-08 01:59:09
【问题描述】:

我有这样的代码:

public interface Checker<A,B> extends BiFunction<CheckRequest<A>,Function<A,B>,CheckResponse<B>> { // ... }

public class CheckResponse<B> {
  private B operationResponse;

  //...

  public void setOperationResponse(B operationResponse) {
   this.operationResponse = operationResponse;
  }

  public B getOperationResponse() {
    return operationResponse;
  }

}

还有一个类似的方法:

public B execute(A req){
  CheckRequest<A> chkReq = //...
  chkReq.setOriginalRequest(req);

  Function<A,B> op = //...

  CheckResponse<B> chkRes= checker.apply(chkReq ,op)
  // [...]
  return chkRes.getOperationResponse();
}

我想将“op”的执行包装到一个检查器对象中,该对象将执行一些其他副作用。我还需要将“op”的输入和输出包装到适当的 CheckRequest 和 CheckResponse 中,以传递和取回额外的数据。但是,为了取回“op”的原始结果,我需要 CheckResponse 中的 getOperationResponse() 方法。听起来很简单。

上面的代码按预期工作,但如果我“内联”它就像:

return checker.apply(chkReq ,op).getOperationResponse();

我明白了

不兼容的类型:java.lang.Object 无法转换为 [actual B型]

如果方法调用是内联的,为什么不能正确推断 getOperationResponse() 的返回类型?

我正在使用 Oracle 的 OpenJDK11:

IMPLEMENTOR="甲骨文公司" IMPLEMENTOR_VERSION="18.9" JAVA_VERSION="11" JAVA_VERSION_DATE="2018-09-25"

Windows 10 上的 Intellij IDEA 2018.3 和 Maven 3.5.4。

【问题讨论】:

  • 您能否提供CheckResponseCheckRequest 类的(相关)代码?另外,您能否在此处添加代码:CheckRequest&lt;A&gt; chkReq = //... 和此处Function&lt;A,B&gt; op = //...。听起来您在某处使用原始类型,导致checker.apply(chkReq, op) 变为CheckResponse 类型(有点相似,但与CheckResponse&lt;Object&gt; 不完全相同)而不是CheckResponse&lt;B&gt;,从而导致给出的错误。
  • @KevinCruijssen 你很可能是对的,我错过了一段代码,其中我使用了一个工厂类,例如:public Checker getChecker(OperationType operation) { switch(operation){ case getOperation: return new SecurityChecker&lt;GetOperationRequest, GetOperationResponse&gt;(serviceRepository); default: throw new UnsupportedOperationException("Unsopported Operation: "+operation); } } 如果我正确理解你的提示,哪个返回类型太“原始”了..

标签: java generics types functional-programming java-11


【解决方案1】:

您需要确保您的 checker 定义在类似于以下内容的行中:

Checker<A, B> checker = new Checker<A, B>() {
    @Override
    public CheckResponse<B> apply(CheckRequest<A> aCheckRequest, Function<A, B> abFunction) {
        // perform whatever operation and return a CheckResponse of type B
        return new CheckResponse<>();
    }
};

这里很少有假设的完整类是:

响应模型

class CheckResponse<B> {
    private B operationResponse;

    public void setOperationResponse(B operationResponse) {
        this.operationResponse = operationResponse;
    }

    public B getOperationResponse() {
        return operationResponse;
    }
}

请求模型

class CheckRequest<A> {
    private A operationRequest;

    public void setOperationRequest(A operationRequest) {
        this.operationRequest = operationRequest;
    }

    public A getOperationRequest() {
        return operationRequest;
    }
}

然后你对方法的完整定义可能是

public B execute(A req) {
    CheckRequest<A> chkReq = new CheckRequest<>();
    chkReq.setOperationRequest(req);

    Function<A, B> op;// intialised

    Checker<A, B> checker = new Checker<A, B>() {
        @Override
        public CheckResponse<B> apply(CheckRequest<A> aCheckRequest, Function<A, B> abFunction) {
            // perform whatever operation and return a CheckResponse of type B
            return new CheckResponse<>();
        }
    };

    return checker.apply(chkReq, op).getOperationResponse();
}

我可以确认上述在语法上对我来说很好。

【讨论】:

  • 这是匿名内联Checker 实现的“必须”吗?为什么我不能只使用实现Cheker 接口的具体类的实例?
  • @AleZ 我不小心删除了我之前的评论,但不,它不必是内联的。您可以创建一个实现Checker 接口的松散类。只需确保类与class CheckerImpl&lt;A, B&gt; implements Checker&lt;A, B&gt; 类似,并在nullpointer 的代码中覆盖apply-方法。重要的部分是钻石运算符&lt;&gt;。没有它,new CheckerResponse(); 将是“原始的”,正如我在您问题下方的评论中所描述的那样。然后你可以使用Checker&lt;A, B&gt; checker = new CheckerImpl&lt;A, B&gt;();
  • @AleZ 不,正如 Kevin 指出的那样,这只是为了演示与接口绑定的类型以及随后如何成功调用方法 apply
  • @KevinCruijssen 感谢您的解释,与我打算使用示例解释的内容非常相似。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-09-21
  • 1970-01-01
  • 2020-03-30
  • 1970-01-01
  • 1970-01-01
  • 2013-08-13
  • 2019-04-10
相关资源
最近更新 更多