当前位置: 首页 > 知识库问答 >
问题:

流中间操作排序

宰父桐
2023-03-14
List<String> list = Arrays.asList("a", "b", "c");
List<String> modified = list.parallelStream()
        .map(s -> s + "-" + s)                 //"a-a", "b-b", "c-c"
        .filter(s -> !s.equals("b-b"))         //"a-a", "c-c"
        .map(s -> s.substring(2))              //"a", "c"
        .collect(toList());

共有1个答案

吴才俊
2023-03-14

实际上,在原始问题中嵌入了几个关于排序的问题。

Holger的回答涵盖了流水线内流操作的排序。对于一个特定的流元素,管道操作必须按照程序中所写的方式执行,因为一般来说,类型必须匹配,而且,以其他方式执行也没有意义。从最初的示例开始,streams库不能像编写操作一样重新排序操作,

List<String> modified = list.parallelStream()
    .filter(s -> !s.equals("b-b")) // these two operations are swapped
    .map(s -> s + "-" + s)         // compared to the original example
    .map(s -> s.substring(2))
    .collect(toList());

因为这样的结果将是[a,b,c]。这不会发生的。

List<String> list = Arrays.asList("c", "b", "a");
List<String> modified = list.parallelStream()
    .map(s -> s + "-" + s)                 //"c-c", "b-b", "a-a"
    .filter(s -> !s.equals("b-b"))         //"c-c", "a-a"
    .map(s -> s.substring(2))              //"c", "a"
    .collect(toList());

正如我们所料,输出是[c,a]。现在让我们在一个集合而不是列表上运行流:

List<String> list = Arrays.asList("c", "b", "a");
Set<String> set = new HashSet<>(list);
List<String> modified = set.parallelStream()
    .map(s -> s + "-" + s)
    .filter(s -> !s.equals("b-b"))
    .map(s -> s.substring(2))
    .collect(toList());

这一次,结果是[a,c]。流水线操作(map、filter、map)没有更改顺序,但是由于集合中元素的相遇顺序未定义,结果以与以前结果不同的某种顺序出现在目标列表中。

(我不得不更改原始列表中值的顺序,因为碰巧HashSet的迭代顺序与元素的hashcode相关,这里给出的简单字符串示例具有连续的hashcode。)

List<Integer> list1 = Collections.synchronizedList(new ArrayList<>());
List<Integer> list2 =
    IntStream.range(0, 10)
        .parallel()
        .boxed()
        .peek(i -> list1.add(i))
        .collect(toList());
System.out.println(list1);
System.out.println(list2);

在我的系统上,输出是:

[5, 6, 2, 3, 4, 8, 9, 7, 0, 1]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

在清单2中,源的遭遇顺序保留到输出,但清单1的顺序通常不同。事实上,list1中元素的顺序因运行而异,而list2中元素的顺序总是相同的。

总之,这里显示了三种不同的排序:

    null
 类似资料:
  • 问题内容: 是否可以保证在使用流时,中间操作将按程序顺序执行?我怀疑是这种情况,否则会导致非常细微的错误,但我找不到确切的答案。 例: 是否保证总是返回或?(如果最后一次映射操作在第一次映射操作之前执行,则可能会引发异常- 类似地,如果过滤器在第二次映射操作之后执行,则“ b”将保留在最终列表中) 问题答案: 之所以出现这个问题,是因为您正在从一种类型映射到同一类型。如果您考虑要执行的正式操作,那

  • 我一直试图理解和展示Java流如何在引擎盖下实现一种类型的循环融合,从而可以将几个操作融合到一个pass中。 这里的第一个例子是: 具有以下输出(对每一个元素的单一传递融合相当清楚): 所以我的问题是,在调用distinct时,我认为因为它是一个“有状态”的中间操作,所以它不允许在(所有操作的)一次传递过程中单独处理单个元素,这是正确的吗。此外,因为sorted()状态操作需要处理整个输入流以产生

  • 我有一个对象,“item”,字段为:int:id string:prices 字符串prices包含一个或多个由逗号分隔的价格值。 getStoresaIntList()从对象中的字符串价格返回价格值列表。 以上当然不是我想要的。

  • 注册 点击首页右上角 注册 ,注册成功后 自动登录并跳转至平台"我的场景"; [首页] [注册] [我的场景] 登录 登录成功后获取 当前用户信息并跳转至首页获取 公开场景列表 [登录] [首页] 创建/编辑/预览场景 场景功能: 场景信息:设置场景基本信息,场景名称、场景描述、场景封面、场景视角、场景LOGO、首页展示和场景分享; 图层管理:场景中底图、素材和标绘都会在图层管理中展示,并可编辑删

  • 我试图找出如何在Java8 Stream上实现自定义中间操作。似乎我被锁在外面了:( 具体地说,我想获取一个流,并返回每个条目,包括第一个具有特定值的条目。我想在那之后停止发电,让它短路。 它正在对输入数据进行一系列验证检查。如果有第一个错误,我想停止,但我想在途中整理警告。而且因为这些验证检查可能很昂贵——例如,涉及数据库查找——我只想运行所需的最小集。 所以代码应该是这样的: 看来我应该可以用