哪个更好,Stream或Iterator

时间:2017-03-15 14:43:17

标签: java-8

我正在使用Java * Stream API,我在Lagecy系统中使用了以下代码:

Iterator itr = configMap.entrySet().iterator();
        List<String> resultList = new ArrayList<String>();
        while(itr.hasNext()){
            Entry e = (Entry)itr.next();
            Config rc = (Config)e.getValue();

            if (rc != null && rc.getVisibleTo() != null && (rc.getVisibleTo().equalsIgnoreCase("0010") || rc.getVisibleTo().equalsIgnoreCase("0111") || rc.getVisibleTo().equalsIgnoreCase("0011"))){        
                resultList .add(rc.getName());
            }
        }

我写了以下代码的Stream Equivalent,如下所示:

List<String> resultList = configMap.entrySet()
                   .parallelStream()
                   .map(r -> r.getValue())
                   .filter(r -> r.getVisibleTo() != null)
                   .filter(r -> {return 
                              r.getVisibleTo().equalsIgnoreCase("0010")
                           || r.getVisibleTo().equalsIgnoreCase("0111")
                           || r.getVisibleTo().equalsIgnoreCase("0011");
                        })
                   .map(r -> r.getName())
                   .collect(Collectors.toList());

我获得所需结果的方式。我的问题是,在这种情况下,哪种表现明智是更好的写作方式?如果我选择任何一个而不是另一个,我真的会获得任何价值吗?地图中有大约1000个值。

3 个答案:

答案 0 :(得分:2)

首先,如果你关心表现,你应该根据事实来决定,所以测量,不要猜测(即使用JMH)。

对于简单的情况,迭代或经典循环往往比Streams更快。另一方面,流可以更快,并且通常可以通过并行性进一步加速(工作负载可以轻松并行化)。在大多数情况下,根据我的经验,它并不重要,因为数据集太小和/或使用它的代码不够性能。

关于可读性/可维护性,我倾向于采用流/功能方法来更好地分离关注点。但是for-each循环也可以改善你的迭代代码。所以没有简单的是/否答案,这完全取决于上下文。

答案 1 :(得分:2)

由于您将此作为并行流编写,尝试多线程并分割工作,因此您可能会看到管理线程的开销导致性能下降,因为您的工作有点小。这里的另一个陷阱是,由于您正在使用CommonForkJoinPool(此默认线程池),因此阻止使用任务会降低整个应用程序的性能(这虽然不是非常相关),但这不是一个很好的选择。对于你工作的小规模,要记住这一点。

话虽如此,您是否要使用单线程configMap.entrySet().stream(),我会说性能差异可能会稍微慢一些,但可读性可以弥补它。因此,选择成为稍快的代码或更好的可读性之间的决定,这完全取决于您(但我会亲自选择流)。

答案 2 :(得分:2)

我只是略微重写sream示例:

List<String> resultList = configMap.entrySet()
        .parallelStream()
        .map(Map.Entry::getValue)
        .filter(Objects::nonNull) // value might be a null
        .filter(r ->
                ((Predicate<String>) "0010"::equals)
                        .or("0111"::equals) // null-save equivalent to  "0111".equals(value)
                        .or("0011"::equals)
                        .test(r.getVisibleTo())
        )
        .map(Config::getName)
        .collect(Collectors.toList());

并将使用它。 有关详细的效果说明,请参阅这些问题Java 8: performance of Streams vs CollectionsIterator versus Stream of Java 8

正如@ 4castle在下面的评论中所建议的那样,我们可以使用configMap.values()代替configMap.entrySet()来缩短它:

List<String> resultList = configMap.values()
        .parallelStream()
        .filter(Objects::nonNull)
        .filter(r ->
                ((Predicate<String>) "0010"::equals)
                        .or("0111"::equals) // null-save equivalent to  "0111".equals(value)
                        .or("0011"::equals)
                        .test(r.getVisibleTo())
        )
        .map(Config::getName)
        .collect(Collectors.toList());