为啥这个 Java lambda 表达式参数有错误?

Posted

技术标签:

【中文标题】为啥这个 Java lambda 表达式参数有错误?【英文标题】:Why this Java lambda expression parameter has an error?为什么这个 Java lambda 表达式参数有错误? 【发布时间】:2016-07-22 19:50:04 【问题描述】:

这是一个使用解释器 GOF 模式的算术表达式求值器,BinaryOp 是一个非终结表达式。

public class BinaryOP<T> implements Expression<T> 

    private Expression<T> e1;
    private Expression<T> e2;
    private BiFunction<Expression<T>, Expression<T>, T> f;

    public BinaryOp(Expression<T> e1, Expression<T> e2, 
            BiFunction<Expression<T>, Expression<T>, T> f)
        this.e1 = e1; this.e2 = e2; this.f = f;
    

    @Override
    public <T> T interpret(IContext context)
        return (T)f.apply(e1, e2);
    

而变量是终结表达式。

public class Variable<T> implements Expression<T>      
    private T v;

    public Variable(T v)
        this.v = v;
    

    @Override
    public <T> T interpret(IContext context)
        return (T)context.recognize(v);
    

在定义 BiFunction 总和时,我在使用 lambda 时出现错误,如果 a 和 b 是表达式类型并且结果返回整数,则其参数出现错误 ¿为什么会出现此错误?

public class AritmeticInterpreter

    public static void main(String[] args)     
    IContext<Integer> ctxArimetic = value -> value;

    BiFunction<Expression<Integer>, Expression<Integer>, Integer> sum
    //Error = incompatible types: incompatible parameter types in lambda expression                                       
                = (a, b, result) -> 
                return (Integer)a.interpret(ctxArimetic) + (Integer)b.interpret(ctxArimetic);
           ;
    

是什么导致了这个错误,必须是返回类型另一个表达式? 如果我将解释方法的返回类型更改为表达式,我将无法像这样对两个表达式 a 和 b 求和:

(a, b) -> a + b

因为它们不是整数。

好吧,这不是标题的一部分,但是,¿我可以摆脱对方法的强制解释吗?我知道 java 编译器会删除泛型类型,但是,¿有办法吗?

更新:

这是表达式界面。

public interface Expression<T> 

     public <T> T interpret(IContext context);


【问题讨论】:

您能否将Expression 的代码包含在内?我建议使用您的 IDE 将代码重构为匿名类,修复代码以便编译并重构回来。 最后一个问题:不要使用原始类型。 e1 和 e2 应该是 Expression 类型,而不是 Expression。对于错误: BiFunction 接受两个参数,并返回一个结果。您的 lambda 接受 3 个参数:a、b 和结果。 @JB Nizet 谢谢,我可以在 lambda 上仅使用 a 和 b 来修复错误,但是对于最后一个问题,我将 e1 和 e2 更改为 Expression 并且我仍然需要强制转换。 public &lt;T&gt; T interpret(IContext context) 应该是public T interpret(IContext context) 是的,它可以工作,我不必投射。谢谢。 【参考方案1】:

根据 JB Nizet 评论和 example 我发现我只需要在 lambda 中使用 a 和 b 作为参数。

这是正确的代码。

public static void main(String[] args) 

    IContext<Integer> ctxArimetic = value -> value;     

    BiFunction<Expression<Integer>, Expression<Integer>, Integer> sum
            = (a, b) -> 
        return a.interpret(ctxArimetic) + b.interpret(ctxArimetic);
    ;


最后一个问题。

在 BinaryOP 类上我做了这个改变:

@Override
public T interpret(IContext<T> context)
        return f.apply(e1, e2);

在表达式接口上:

public interface Expression<T> 

       public T interpret(IContext<T> context);


这个错误是因为我参数化了解释方法,这允许该方法返回任何对象。我记得编译器输出错误“T#2 is different from type T#1” T#2 is the generic parameter on translate method and T#1 is the generic type on the class BinaryOp.

我不知道如何正确使用 lambda 和泛型。

更新:修复一些错误,我改变了

public T interpret(IContext context);

public T interpret(IContext<T> context);

【讨论】:

是的,昨天测试我的代码时,我必须修复一些错误。

以上是关于为啥这个 Java lambda 表达式参数有错误?的主要内容,如果未能解决你的问题,请参考以下文章

为啥在 lambda 表达式中使用迭代变量不好

Java8 lambda 表达式

为啥 Kotlin 不能推断以下 lambda 参数(在 Java -> Kotlin 转换之后)?

为啥将 lambda 传递给受约束的类型模板参数会导致“不完整类型”编译器错误?

为啥不能为 Java 中的 var 关键字分配 lambda 表达式?

java8型特性1- lambda表达式