标签: java-stream

Java Stream API:为什么区分顺序和并行执行模式?

来自Stream javadoc:

流管道可以顺序执行或并行执行.此执行模式是流的属性.通过初始选择的顺序或并行执行来创建流.

我的假设:

  1. 顺序/并行流之间没有功能差异.输出永远不会受执行模式的影响.
  2. 由于性能的提高,在给定适当数量的内核和问题大小以证明开销合理的情况下,并行流总是更可取的.
  3. 我们想编写一次代码并在任何地方运行而不必关心硬件(毕竟这是Java).

假设这些假设是有效的(对于一些元假设没有错误),在api中暴露执行模式的价值是什么?

看起来您应该只能声明一个Stream,并且顺序/并行执行的选择应该在下面的层中自动处理,可以通过库代码或JVM本身作为运行时可用核心的函数来处理,大小问题等

当然,假设并行流也可以在单个核心机器上运行,也许只是总是使用并行流来实现这一点.但这真的很难看 - 为什么我的代码中的并行流显式引用它是默认选项?

即使存在您故意想要对顺序流进行硬编码的情况 - 为什么不仅仅是SequentialStream为此目的的子接口,而不是Stream使用执行模式切换进行污染?

java parallel-processing java-8 java-stream

18
推荐指数
2
解决办法
1万
查看次数

如何在Java 8中以相反的顺序从列表中获取有序流

是否有一种理智的方式从列表中获取有序流(具体来说,数组列表,但它应该无关紧要)流式元素与它们在原始列表中的方式相反?

我正在寻找一种不涉及缓冲数据的解决方案(收集器,另一个列表,数组等,因为它们复制了浪费的容器),或者使用Collections.reverse(因为它修改了列表).

到目前为止,我在这里看到的最干净的方法之一是实现我自己的版本的Spliterator这ORDERED和在列表中反向前进,或实施Iterator反向迭代是,并使用Spliterators.spliteratorUnknownSize(iterator,ORDERED)它.

注意这个问题不同于Java 8流逆序:其他问题询问如何反转流(一般情况下这是不可能的),并且答案提供了以某种方式反转源(我不想这样做),然后传输反向源.逆转源的成本是O(N),如果可能的话我想完全避免它.

java java-8 java-stream

18
推荐指数
5
解决办法
1万
查看次数

Java流排序2变量升序/取消发送

我想排序seq1升序和seq2降序所以我这样做:

list = list.stream().sorted(comparing(AClass::getSeq1).thenComparing(        
   AClass::getSeq2).reversed()).collect(toList());
Run Code Online (Sandbox Code Playgroud)

但结果出来了,因为seq1和seq2都按降序排序.

我可以这样做以使seq1升序和seq2降序:

sorted(comparing(AClass::getSeq1)
   .reversed().thenComparing(AClass::getSeq2).reversed()
Run Code Online (Sandbox Code Playgroud)

这是真正的正确方法吗?

java sorting comparator java-8 java-stream

18
推荐指数
1
解决办法
1万
查看次数

Java 8:通过检查所有Stream元素来停止减少操作

我试图了解是否有办法终止还原操作而不检查整个流,我无法找到方法.

用例大致如下:让一长串的Integers需要折叠成一个Accumulator.每个元素检查都可能很昂贵,所以在内部Accumulator,我对传入进行检查Accumulator,看看我们是否需要执行昂贵的操作 - 如果我们不这样做,那么我只需返回累加器.

对于小(呃)列表来说,这显然是一个很好的解决方案,但是巨大的列表会产生我不想要的不必要的流元素访问成本.

这是一个代码草图 - 仅假设连续减少.

class Accumulator {
    private final Set<A> setA = new HashSet<>;
    private final Set<B> setB = new HashSet<>;
}

class ResultSupplier implements Supplier<Result> {

    private final List<Integer> ids;

    @Override
    public Result get() {
        Accumulator acc = ids.stream().reduce(new Accumulator(), f(), (x, y) -> null);

        return (acc.setA.size > 1) ? Result.invalid() : Result.valid(acc.setB);
    }

    private static BiFunction<Accumulator, Integer, Accumulator> f() {
        return (acc, element) -> {
            if …
Run Code Online (Sandbox Code Playgroud)

java reduce fold java-8 java-stream

18
推荐指数
2
解决办法
3170
查看次数

通过Java Stream汇总ArrayList <Double>

我试图弄清楚如何总结'ArrayList'的所有元素.

我已经尝试过了:

 double totalevent = myList.stream().mapToDouble(f -> f).sum();
Run Code Online (Sandbox Code Playgroud)

虽然myList是一个ArrayList<Double>.

没有无用的mapToDouble功能有没有办法做到这一点?

double java-8 java-stream

18
推荐指数
1
解决办法
2万
查看次数

在Java中,我如何有效和优雅地流式传输树节点的后代?

假设我们有一个由唯一Strings 标识的对象集合,以及一个Tree定义它们层次结构的类.该类使用Mapfrom节点(由其ID表示)到Collection其各自子节点的s来实现.

class Tree {
  private Map<String, Collection<String>> edges;

  // ...

  public Stream<String> descendants(String node) {
    // To be defined.
  }
}
Run Code Online (Sandbox Code Playgroud)

我想启用流式节点的后代.一个简单的解决方案是:

private Stream<String> children(String node) {
    return edges.getOrDefault(node, Collections.emptyList()).stream();
}

public Stream<String> descendants(String node) {
    return Stream.concat(
        Stream.of(node),
        children(node).flatMap(this::descendants)
    );
}
Run Code Online (Sandbox Code Playgroud)

在继续之前,我想对此解决方案做出以下断言.(我对这些是正确的吗?)

  1. 从Stream返回的descendants消耗资源(时间和内存) - 相对于树的大小 - 以与手动编码递归相同的复杂度顺序行走.特别地,表示迭代状态(Streams,Spliterators,...)的中间对象形成堆栈,因此在任何给定时间的存储器要求与树的深度具有相同的复杂度.

  2. 据我所知此,只要我在执行终止操作Stream从返回descendants,根级别调用flatMap将导致所有包含Stream秒-一个用于每个(递归)呼叫descendants-被立即实现.因此,结果Stream …

java algorithm java-8 java-stream

18
推荐指数
2
解决办法
3060
查看次数

手动链接GroupBy收藏家

我想把一个人的名单分组.一个人有一些属性,如姓名,国家,城镇,邮政编码等.我写了静态代码,非常有效:

Object groupedData = data.stream().collect(groupingBy(Person::getName, Collectors.groupingBy(Person::getCountry, Collectors.groupingBy(Person::getTown))));
Run Code Online (Sandbox Code Playgroud)

但问题是,这不是动态的.有时我想按名称和城镇分组,有时候按属性分组.我怎样才能做到这一点?非Java 8解决方案也是受欢迎的.

java grouping java-8 java-stream collectors

18
推荐指数
2
解决办法
837
查看次数

Java 8 Streams - 超时?

我想循环一个庞大的数组并做一组复杂的指令需要很长时间.但是,如果超过30秒,我希望它放弃.

恩.

final long start = System.currentTimeMillis();
myDataStructure.stream()
    .while(() -> System.currentTimeMillis() <= start + 30000)
    .forEach(e ->
    {
      ...
    });
Run Code Online (Sandbox Code Playgroud)

如果满足某个条件,我想避免return在forEach通话中说话.

java java-8 java-stream

18
推荐指数
4
解决办法
3735
查看次数

什么时候认为Java 8 Stream被消费了?

我的理解是,Stream一旦执行终端操作(例如forEach()或)count(),就认为Java 8 被消耗.

但是,multipleFilters_separate下面的测试用例抛出一个IllegalStateException即使filter是一个懒惰的中间操作,只是作为两个语句调用.然而,我可以将两个过滤操作链接到一个语句中并且它可以工作.

@Test(expected=IllegalStateException.class)
public void multipleFilters_separate() {
    Stream<Double> ints = Stream.of(1.1, 2.2, 3.3);
    ints.filter(d -> d > 1.3);
    ints.filter(d -> d > 2.3).forEach(System.out::println);
}

@Test
public void multipleFilters_piped() {
    Stream<Double> ints = Stream.of(1.1, 2.2, 3.3);
    ints.filter(d -> d > 1.3)
        .filter(d -> d > 2.3)
        .forEach(System.out::println);
}
Run Code Online (Sandbox Code Playgroud)

从这开始,我假设Stream在第一个使用它的语句之后被认为是消耗的,无论该语句是否调用终端操作.听起来不错吗?

java java-8 java-stream

18
推荐指数
2
解决办法
2030
查看次数

限制和无序流的内部更改

基本上这是在试图回答另一个问题时出现的.假设这段代码:

AtomicInteger i = new AtomicInteger(0);
AtomicInteger count = new AtomicInteger(0);
IntStream.generate(() -> i.incrementAndGet())
        .parallel()
        .peek(x -> count.incrementAndGet())
        .limit(5)
        .forEach(System.out::println);

System.out.println("count = " + count);
Run Code Online (Sandbox Code Playgroud)

我理解这IntStream#generate是一个无序的无限流的事实,并且要完成它必须有一个短路操作(limit在这种情况下).我也明白,在Supplier达到该限制之前,Stream实现的次数可以自由调用.

在java-8下运行它会count一直打印512(可能并不总是,但在我的机器上是这样).

在对比运行中,这在java-10下很少超过5.所以我的问题是内部发生了什么变化,短路发生得更好(我试图通过拥有源并试图做一些差异来解决这个问题......)

java java-8 java-stream java-10

18
推荐指数
1
解决办法
263
查看次数