当前位置: 首页 > 知识库问答 >
问题:

Java8lambda函数接口-目标类型的二义性方法

柴俊捷
2023-03-14

我有以下代码:

public class LambdaTest1 {

    public static void method1(Predicate<Integer> predicate){
        System.out.println("Inside Predicate");
    }

    public static void method1(Function<Integer,String> function){
        System.out.println("Inside Function");
    }

    public static void main(String[] args) {        
        method1((i) -> "Test"); 
    }
}

这会给我一条错误消息,如

“方法method1(谓词)对于类型LambDateSt1”不明确。

我可以看到,对于functionconsumer函数接口,输入参数是integer。但是对于函数,返回类型为string

还有另一个例子:

public class LambdaTest1 {

public static void method1(Consumer<Integer> consumer){
    System.out.println("Inside Consumer");
}

public static void method1(Predicate<Integer> predicate){
    System.out.println("Inside Predicate");
}

public static void main(String[] args) {

    List<Integer> lst = new ArrayList<Integer>();

    method1(i -> true); 

    method1(s -> lst.add(s)); //ambiguous error
}
}

同样在上面的代码中,行method1(s->lst.add(s));给出了一个歧义错误,但是上面的行method1(i->true)可以正常工作。

共有1个答案

秦滨海
2023-03-14

正如在这个答案中所解释的,Java语言设计者在选择一个重载方法和类型推断相结合的过程中做了一个深思熟虑的切割。因此,并不是lambda表达式参数的每个方面都用于确定正确的重载方法。

最值得注意的是,在您的第一个示例中,lambda表达式(i)->“test”是一个隐式类型的lambda表达式,其返回值不考虑重载解析,而将其更改为(例如(Integer i)->“test”会将其变为一个显式类型的lambda表达式,其返回值考虑在内。与Java语言规范§15.12.2.2.:

参数表达式被认为与可能适用的方法m的适用性相关,除非它具有以下形式之一:

  • 隐式类型的lambda表达式(§15.27.1)。

>

  • 显式类型的lambda表达式,其主体是与适用性无关的表达式。

    一种显式类型的lambda表达式,其主体为块,其中至少有一个结果表达式与适用性无关。

    因此,显式类型的lambda表达式可以“与适用性相关”,这取决于它们的内容,而隐式类型的表达式通常被排除在外。还有一个增编更为具体:

    只有几种情况,形状模棱两可:

    • 当块从未正常完成时,例如arg->{throw new Exception();}
      arg->{for(;;);}
    • 当lambda表达式的形式为arg->expression并且expression也是一个语句时。这类表达式语句是
      • 分配,例如arg->foo=arg
      • 递增/递减表达式,例如arg->counter++
      • 方法调用,如示例s->lst.add
      • 中所示
      • 实例化,例如arg->new Foo(arg)

      请注意,带圆括号的表达式不在此列表中,因此将s->lst.add(s)更改为
      s->(Lst.add(s))足以将其变为不再与void兼容的表达式。同样,将其转换为类似s->{lst.add(s);}的语句会阻止它与值兼容。因此在此场景中很容易选择正确的方法。

  •  类似资料:
    • 我正在尝试实现一个示例库,客户端可以使用它来执行他们的代码,为了实现它,我使用了Java的函数式编程特性。但获取编译错误此表达式的目标类型必须是函数接口 请说说我缺了什么。

    • 流接口中的映射函数定义如下: 函数参数列表与函数接口自己的规范一致 方法是 这意味着它需要一个T,但返回一个R。但我正在运行这个代码 奇怪的是,为什么它能工作,但论点类型似乎不匹配?没有简单的方法来解释它,但我的理解是,一个函数应该接受类型T的输入并返回类型R。当它在流中使用时,它接受类型String的输入并返回类型int(即String.length())。但是小溪。map被键入以返回与流相同的

    • 问题内容: 目前我有这样的事情 main.go 还有我的工作包 和 我正在传递给NewJob的函数是在goroutine上每2秒执行一次,但是我想访问我传递的匿名结构…但是当我尝试访问时 编号 我越来越 t.Id未定义(类型interface {}是没有方法的接口) 但是打印t给我预期的结果 {1} 问题答案: 您必须先将其声明为兼容类型,然后才能访问其字段。

    • 问题内容: 我想了解为什么下面的代码片段无法编译。将函数接受为可能具有任何返回类型的函数参数的Go方法是什么? 播放:https://play.golang.org/p/CqbuEZGy12 我的解决方案基于Volker的答案: 播放:https://play.golang.org/p/waOGBZZwN7 问题答案: 你绊倒了围棋新人一个非常普遍的误解:空接口并 不能 意味着“任何类型”。确实不

    • 问题内容: 我正在尝试在Java中使用lambda和流,但我对此很陌生。当我尝试创建lambda表达式时,我在IntelliJ中收到了此错误“ lambda转换的目标类型必须是接口” 难道我做错了什么? 问题答案: 我怀疑这只是Java的类型推断不够聪明。尝试