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

Java 8 Streams:为什么Collectors.toMap对于带有通配符的泛型有不同的表现?

经骁
2023-03-14
问题内容

假设您有一个List数字。中的值List可以是类型IntegerDouble等等。List声明时,可以使用通配符(?)声明,也可以不使用通配符。

final List<Number> numberList = Arrays.asList(1, 2, 3D);
final List<? extends Number> wildcardList = Arrays.asList(1, 2, 3D);

所以,现在我想streamListcollect它所有的Map使用Collectors.toMap(显然下面的代码只是为了说明问题的例子)。让我们开始流式传输numberList

final List<Number> numberList = Arrays.asList(1, 2, 3D, 4D);

numberList.stream().collect(Collectors.toMap(
        // Here I can invoke "number.intValue()" - the object ("number") is treated as a Number
        number -> Integer.valueOf(number.intValue()),
        number -> number));

但是,我不能在wildcardList:上执行相同的操作

final List<? extends Number> wildCardList = Arrays.asList(1, 2, 3D);
wildCardList.stream().collect(Collectors.toMap(
        // Why is "number" treated as an Object and not a Number?
        number -> Integer.valueOf(number.intValue()),
        number -> number));

编译器在调用时抱怨number.intValue()以下消息:

Test.java:找不到符号
symbol:方法intValue()
位置:java.lang.Object类型的变量编号

从编译器错误中可以明显看出number,将lambda中的视为Object而不是Number

所以,现在我的问题是:

  • 收集的通配符版本时List,为什么不能像的非通配符版本那样工作List
  • 为什么numberlambda中的变量被认为是a Object而不是a Number

问题答案:

这是类型推断无法正确实现的原因。如果您明确提供type参数,则它可以按预期工作:

List<? extends Number> wildCardList = Arrays.asList(1, 2, 3D);
wildCardList.stream().collect(Collectors.<Number, Integer, Number>toMap(
                                  number -> Integer.valueOf(number.intValue()),
                                  number -> number));

这是一个已知的javac错误:推理不应将捕获变量映射到其上限。根据Maurizio
Cimadamore的说法,

尝试修复,然后因为在8中打破案例而退出,所以我们在8中进行了更保守的修复,而在9中完成了全部操作

显然,该修复程序尚未推出。



 类似资料:
  • 问题内容: 下列类定义了两种方法,它们在直观上都具有相同的功能。每个函数都有两个类型和一个布尔值的列表来调用,该值指定应将这些列表中的哪个分配给局部变量。 根据,有效而无效。它抱怨: 我知道查找包含三元运算符()的表达式类型的规则非常复杂,但是据我了解,它选择了最具体的类型,第二个和第三个参数都可以转换为该类型,而无需显式投。在这里,应该是,但不是。 我想解释一下为什么不是这种情况,最好参考 Ja

  • 问题内容: 直到几天前,我才听说过野车,在读完我的老师的Java书籍后,我仍然不确定它的用途以及为什么需要使用它。 比方说,我有一个超类和几个子类都,,,等…现在我需要有动物名单,我首先想到的会是这样的: 相反,我的同事们建议采取以下措施: 为什么要使用通配符而不是简单的泛型? 假设我需要一个get / set方法,应该使用前一种还是后一种?它们有何不同? 问题答案: 声明局部变量时,通配符没有多

  • null 编译,我真的不明白为什么。基本上与第1行相同的问题。是的超类,如何将超类的成员放入此中? 编译。与第1行相同的问题。

  • 在试图理解java泛型类型和通配符“?”的用法时,我尝试了以下方法: 我得到以下编译错误(使用Oracle JDeveloper作为IDE): 为什么上面的代码不能编译,而赋值却可以呢?另外,如果我想调用,什么是可接受的参数值?

  • 问题内容: 我知道Java的泛型类型有各种各样的违反直觉的属性。特别是我不理解的一个,希望有人可以向我解释。为类或接口指定类型参数时,可以对其进行绑定,以使其必须使用来实现多个接口。但是,如果要实例化实际对象,则此方法不再起作用。很好,但是无法编译。考虑以下完整代码段: 似乎应该明确定义的语义-我想通过允许两种类型(而不只是一种类型)的交集,不会损失类型安全性。我敢肯定有一个解释。有谁知道它是什么

  • 这是我试图理解的编译器行为的一个过度简化版本: 在上面的代码片段中,是一个类型范围比HouseCat接口允许的类型范围更广的引用,即: 如果我尝试执行类似的操作,编译器会告诉我不满足类型参数的约束。那么,,至少是潜在的。 编译器不会让我创建违反类型参数约束的实例,但我对它使用作为引用上限的行为感到困惑。在(,)之间有一个无效的类型范围,那么编译器为什么不拒绝这个引用定义呢? 澄清:我的问题不是关于