繁体   English   中英

使用流收集时jdk8与jdk11的不同行为

[英]Different behaviour of jdk8 vs jdk11 when using stream collect

介绍

关于流和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> 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;
    }
  }

实现从容器中收集objectId值。 这对于jdk8的编译器来说是有效的。 但是jdk11在这里失败了。

    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());

将其更改为此实现使jdk11编译器感到高兴。

    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>

编辑 :我更改了设置代码,以反映我当前的问题。

谁知道我做错了什么?

这可能与JDK-8199234 java8中的代码编译有关,但java9中没有:“不兼容的类型:java.lang.Object无法转换...” ,它被解析为“非问题”并影响Java 9+。

根本原因是在您的示例map(List.class::cast)执行转换为原始类型List搞乱有关泛型的信息。 你试图用map(ObjectId.class::cast)来解决这个问题,但这不是一个好主意。 Streams很大程度上基于泛型,你应该避免手动转换,让编译器推断出类型。

您的代码可以简化为以下,适用于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());

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM