Java 8:计算 lambda 迭代次数的首选方法?

2022-08-31 09:57:15

我经常遇到同样的问题。我需要计算 lambda 的运行次数,以便在 lambda 之外使用。

例如:

myStream.stream().filter(...).forEach(item -> { ... ; runCount++});
System.out.println("The lambda ran " + runCount + "times");

问题是 runCount 需要是 ,所以它不能是 .它不能是,因为它是不可变的。我可以让它成为类级变量(即一个字段),但我只需要在这个代码块中使用它。finalintInteger

我知道有多种方法,我只是好奇您的首选解决方案是什么?
是否使用数组引用或其他方式?AtomicInteger


答案 1

为了便于讨论,让我重新格式化一下您的示例:

long runCount = 0L;
myStream.stream()
    .filter(...)
    .forEach(item -> { 
        foo();
        bar();
        runCount++; // doesn't work
    });
System.out.println("The lambda ran " + runCount + " times");

如果您确实需要从 lambda 中递增计数器,则典型的方法是将计数器设置为 or,然后对其调用其中一个递增方法。AtomicIntegerAtomicLong

您可以使用单元素或数组,但如果流并行运行,则会产生争用条件。intlong

但请注意,流以 结尾,这意味着没有返回值。您可以将 更改为 a ,这会传递项目,然后对它们进行计数:forEachforEachpeek

long runCount = myStream.stream()
    .filter(...)
    .peek(item -> { 
        foo();
        bar();
    })
    .count();
System.out.println("The lambda ran " + runCount + " times");

这有点好,但仍然有点奇怪。原因是,并且只能通过副作用来完成他们的工作。Java 8 新兴的函数式风格是避免副作用。我们通过提取计数器的增量到流上的操作中来做到这一点。其他典型的副作用是将项目添加到集合中。通常,这些可以通过使用收集器来替换。但是,在不知道你试图做什么实际工作的情况下,我不能提出任何更具体的建议。forEachpeekcount


答案 2

作为同步hassling AtomicInteger的替代方法,可以使用整数数组来代替。只要对数组的引用没有分配另一个数组(这就是重点),它就可以用作最终变量,而字段的值可以任意更改

    int[] iarr = {0}; // final not neccessary here if no other array is assigned
    stringList.forEach(item -> {
            iarr[0]++;
            // iarr = {1}; Error if iarr gets other array assigned
    });

推荐