MaV*_*aVo 9 java java-stream collectors
关于流和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));
Run Code Online (Sandbox Code Playgroud)
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;
}
}
Run Code Online (Sandbox Code Playgroud)
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());
Run Code Online (Sandbox Code Playgroud)
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());
Run Code Online (Sandbox Code Playgroud)
但是我不明白为什么这是错误的。
<deleted as of to be inacurate>
编辑:我更改了设置代码以反映我当前的问题。
有人知道我在做什么错吗?
这可能与JDK-8199234 代码在 java8 中编译但不在 java9 中相关:“不兼容的类型:java.lang.Object 无法转换...”,该问题被解析为“不是问题”并影响 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());
Run Code Online (Sandbox Code Playgroud)