当前位置: 首页 > 面试题库 >

无法在意外地方推断类型(可能是Javac错误?)

贺刚毅
2023-03-14
问题内容

我正在尝试执行新的JDK 8函数式编程领域中似乎是相对基本的事情,但是我无法使其工作。我有这个工作代码:

import java.util.*;
import java.util.concurrent.*;
import java.util.stream.*;

public class so1 {
   public static void main() {
      List<Number> l = new ArrayList<>(Arrays.asList(1, 2, 3));
      List<Callable<Object>> checks = l.stream().
               map(n -> (Callable<Object>) () -> {
                  System.out.println(n);
                  return null;
               }).
               collect(Collectors.toList());
   }
}

它接受一个数字列表,并产生可以打印出来的功能列表。但是,显式转换为Callable似乎是多余的。在我和IntelliJ中看来。我们都同意这也应该起作用:

List<Callable<Object>> checks = l.stream().
       map(n -> () -> {
          System.out.println(n);
          return null;
       }).
       collect(Collectors.toList());

但是我得到一个错误:

so1.java:10: error: incompatible types: cannot infer type-variable(s) R
      List<Callable<Object>> checks = l.stream().map(n -> () -> {System.out.println(n); return null;}).collect(Collectors.toList());
                                                    ^
    (argument mismatch; bad return type in lambda expression
      Object is not a functional interface)
  where R,T are type-variables:
    R extends Object declared in method <R>map(Function<? super T,? extends R>)
    T extends Object declared in interface Stream
1 error

问题答案:

您遇到了Java 8目标类型的限制,该限制适用于方法调用的 接收者 。尽管目标类型在大多数情况下适用于参数类型,但不适用于调用该方法的对象或表达式。

这里l.stream(). map(n -> () -> { System.out.println(n); return null; })collect(Collectors.toList())方法调用的接收者,因此List<Callable<Object>>不考虑目标类型。

如果知道目标类型,很容易证明嵌套的lambda表达式可以工作,例如

static <T> Function<T,Callable<Object>> toCallable() {
    return n -> () -> {
        System.out.println(n); 
        return null;
    };
}

可以正常工作,您可以用它来解决您原来的问题,因为

List<Callable<Object>> checks = l.stream()
    .map(toCallable()).collect(Collectors.toList());

您还可以通过引入辅助方法来解决该问题,该方法将第一个表达式的作用从方法接收者更改为参数

// turns the Stream s from receiver to a parameter
static <T, R, A> R collect(Stream<T> s, Collector<? super T, A, R> collector) {
    return s.collect(collector);
}

并将原始表达式重写为

List<Callable<Object>> checks = collect(l.stream().map(
    n -> () -> {
        System.out.println(n); 
        return null;
    }), Collectors.toList());

这不会降低代码的复杂性,但可以毫无问题地进行编译。对我来说,这是déjàvu。当Java
5和泛型问世时,程序员必须在new表达式上重复类型参数,而只是将表达式包装到泛型方法中就证明了推断类型是没有问题的。直到Java
7才允许程序员忽略类型参数的这些不必要的重复(使用“菱形运算符”)。现在,我们遇到了类似的情况,将调用表达式包装到另一种方法中,将接收者变成参数,证明此限制是不必要的。所以也许我们摆脱了Java
10中的这个限制…




 类似资料:
  • 我有一些用< code>javac 1.8.0_92编译的代码: 但是,对于 ,需要一些额外的类型 (): 可以想象,这会给用户从源代码构建的包带来问题。 > 这是为什么呢? 这是特定Java版本的错误吗?

  • 作为一个学习项目,我正在编写一个通过TCP的聊天服务器。我今天一直在修补ws crate,但我遇到了一个问题。这是我编写的代码,修改了他们的服务器示例。 当我尝试编译它时,我得到一个错误: 为什么会这样?我怎样才能解决这个问题?

  • 我的分类测试应用程序有一个问题,我使用了一个比较器。我收到一条信息: 线程“主”java.lang 中的异常:未解决的编译问题:无法推断排序器的类型参数 对于该代码: 分拣机类: 可比接口: id比较器类: 比较器接口: 这样用有什么错?我怎样才能做得更好?

  • 问题内容: 下面的方法完美无瑕 但是我没有指定此方法中的 是什么。编译器如何将 方法返回的值分配给 未指定类型i 的变量? 我只是测试了答案的有效性,指出了从该方法的返回类型推断出的答案。它似乎没有解决。请检查以下代码。它甚至不编译 再次修改源代码并对其进行测试,结果导致编译时错误 问题答案: 该方法如何推断类型 没有。泛型方法不推断其泛型类型-这就是为什么称为 类型参数 的原因。方法的 调用者

  • 我需要 Kotlin 中的一个集合来仅包含实现给定接口的元素。 例如:包含动物集合的地图: 通过阅读文档、博客和SO问题,我编写了使用Generics in关键字的代码: 现在我想在Test类中添加一个读取“data”内容的方法,例如将其打印到控制台: 如果我这样做,我会遇到编译错误: 我的解决方案是强制我的动物进入一个ArrayList 但是我不确定这是编写这种代码的最好方式。有没有更好的方式告

  • 我正在尝试编写一个android静态编程语言应用程序,但我得到了以下错误。我哪里出错了? 这是我如何声明我的HashMap: 错误: 类型推断失败。没有足够的信息来推断构造函数HashMap中的参数K。请明确说明