关于流和collect方法,jdk11(及更高版本)的行为确实存在问题。
我确实想获取流化资源的参数化容器的值,并以.collect(Collectors.toSet())
最后收集值。
当我使用jdk8
编译代码时,它可以很好地工作。但是由于我们还必须支持jdk11
,所以我运行了编译,但由于Error:(136, 17) java: incompatible types: java.lang.Object cannot be converted to java.util.Set<org.bson.types.ObjectId>
(对于openJdk11同样适用)而失败了
想象一下以下情况。我有一个基本上是数据容器的类。该容器可以容纳单个值或值列表。
在我的应用程序的某些部分中,我确实有此容器类的列表(它也可以包含列表作为值),并且我确实希望通过列表进行流传输,以将容器中的所有值作为平面列表获得。
在此示例中,我选择使用objectIds列表。
// preparation
List<ObjectId> innerObjects = new ArrayList<>();
innerObjects.add(new ObjectId());
innerObjects.add(new ObjectId());
List<Diamond<Object>> diamonds = new ArrayList<>();
diamonds.add(new Diamond<Object>().value(innerObjects));
public static class Diamond<T> {
private T value;
public Diamond<T> value(T value) {
this.value = value;
return this;
}
public T getValue() {
return this.value;
}
}
Set<ObjectId> objectIdSet = diamonds
.stream()
.filter(diamond -> diamond.getValue() instanceof List)
.map(Diamond::getValue)
.map(List.class::cast)
.flatMap(Collection::stream)
.map(ObjectId.class::cast)
.collect(Collectors.toSet());
Stream<ObjectId> idStream = diamonds
.stream()
.filter(diamond -> diamond.getValue() instanceof List)
.map(Diamond::getValue)
.map(List.class::cast)
.flatMap(Collection::stream)
.map(ObjectId.class::cast);
Set<ObjectId> objectIds = idStream.collect(Collectors.toSet());
但是我不明白为什么这是错误的。
<deleted as of to be inacurate>
编辑: 我更改了设置代码,以反映出我当前的问题。
有人知道我在做什么错吗?
答案 0 :(得分:4)
这可能与JDK-8199234 Code compiles in java8 but not in java9 : "incompatible types: java.lang.Object cannot be converted ..."有关,该问题已解决为“不是问题”并影响Java 9 +。
根本原因是,在您的示例中,map(List.class::cast)
对原始类型List
进行了强制转换,弄乱了有关泛型的信息。您稍后尝试使用map(ObjectId.class::cast)
纠正此问题,但这不是一个好主意。流在很大程度上基于泛型,因此应避免进行手动强制转换,并让编译器推断类型。
您的代码可以简化为以下代码,可在Java 11上运行:
Set<ObjectId> objectIdSet = diamonds.stream()
.filter(Objects::nonNull) // potentially redundant but instanceof was doing it
.map(Diamond::getValue)
.flatMap(Collection::stream)
.collect(Collectors.toSet());