Java 8流过滤器对收集方法的优化程度如何?

时间:2017-06-01 03:51:26

标签: java collections lambda java-8

例如,我有逗号分隔的字符串:

String multiWordString= "... , ... , ... ";

我想检查csv字符串中是否存在另一个字符串str。 然后我可以做两件事:

1

boolean contains = Arrays.asList(multiWordString.split(",")).contains(str);

2

boolean contains = Arrays.asList(multiWordString.split(",")).stream().filter(e -> e.equals(str)).findFirst();

编辑:示例字符串碰巧使用逗号作为分隔符。我应该使用更好的名称作为样本字符串,以避免混淆。 我更新了名字。在这个问题中,我试图找到使用Java 8流和循环/收集方法之间的性能差异。

3 个答案:

答案 0 :(得分:6)

没有测试就无法分辨,内部细节可以改变另一个解决方案的行为方式,因此最好的方法是衡量。据了解,流有点慢 - 它们背后有基础设施......

这是一个天真的简单测试(,数据很少):

@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Warmup(iterations = 5, time = 2, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 5, time = 2, timeUnit = TimeUnit.SECONDS)
@State(Scope.Benchmark)
public class CSVParsing {
    public static void main(String[] args) throws RunnerException {
        Options opt = new OptionsBuilder().include(CSVParsing.class.getSimpleName())
                .jvmArgs("-ea")
                .shouldFailOnError(true)
                .build();
        new Runner(opt).run();
    }

    @Param(value = { "a,e, b,c,d",
            "a,b,c,d, a,b,c,da,b,c,da,b,c,da,b,c,da,b,c,da,b,c,da,b,c,da,b,c,d, e",
            "r, m, n, t,r, m, n, tr, m, n, tr, m, n, tr, m, n, tr, m, n, tr, m, n, tr, m, n, t, e" })
    String csv;

    @Fork(1)
    @Benchmark
    public boolean containsSimple() {
        return Arrays.asList(csv.split(",")).contains("e");
    }

    @Fork(1)
    @Benchmark
    public boolean containsStream() {
        return Arrays.asList(csv.split(",")).stream().filter(e -> e.equals("e")).findFirst().isPresent();
    }

    @Fork(1)
    @Benchmark
    public boolean containsStreamParallel() {
        return Arrays.asList(csv.split(",")).stream().filter(e -> e.equals("e")).findFirst().isPresent();
    }
}

即使您不理解代码,结果也是可以比较的简单数字:

 CSVParsing.containsSimple   (first Parameter)    181.201 ±   5.390
 CSVParsing.containsStream                        255.851 ±   5.598
 CSVParsing.containsStreamParallel                295.296 ±  57.800

我不会显示其余结果(对于其他参数),因为它们在相同的范围内。

底线是它们确实不同,最多100 ns ;让我重复一遍:纳秒

确实存在差异;但如果你真的非常关心这个差异,那么csv解析可能首先是错误的选择。

答案 1 :(得分:2)

两个版本的工作量“相同”:需要创建一个列表,并且需要比较所有元素。

选项2增加了设置很多内容的开销。因此,与选项1相比,选项2消耗了更多的CPU周期。流不是免费的!

效率在这里有不同的方面。当您的csv输入相对简单时,正则表达式可能会正常(检查是否可以在csv字符串中找到某些模式。当您必须处理任意csv输入时(例如,包含带引号的逗号的值),那么用逗号简单拆分会导致错误的结果。

答案 2 :(得分:2)

注意,CSV通常比逗号的分隔字符串更复杂,也可以逃避逗号的担忧。我希望这是一个示例,或者不是导入的CSV格式。

您不应该首先从数组转换为列表,使用Arrays.stream或Stream.of()直接从数组转换到流

但是这些流是懒惰的,他们只做他们需要做的工作。

.contains(str)会在找到匹配后立即中止。

如果不进行测量就很难分辨性能,所以现在让程序正确且易于维护。

如果需要考虑性能问题,在完成一些工作后,分析并查看哪些内容可能更好,尝试替代方案,然后挑选获胜者。