我最近开始使用collectionAndThen,发现与我用来执行类似任务的其他编码过程相比,它花费了一些时间。
这是我的代码:
System.out.println("CollectingAndThen");
Long t = System.currentTimeMillis();
String personWithMaxAge = persons.stream()
.collect(Collectors.collectingAndThen(
Collectors.maxBy(Comparator.comparing(Person::getAge)),
(Optional<Person> p) -> p.isPresent() ? p.get().getName() : "none"
));
System.out.println("personWithMaxAge - "+personWithMaxAge + " time taken = "+(System.currentTimeMillis() - t));
Long t2 = System.currentTimeMillis();
String personWithMaxAge2 = persons.stream().sorted(Comparator.comparing(Person::getAge).reversed())
.findFirst().get().name;
System.out.println("personWithMaxAge2 : "+personWithMaxAge2+ " time taken = "+(System.currentTimeMillis() - t2));
这是输出:
CollectingAndThen
personWithMaxAge - Peter time taken = 17
personWithMaxAge2 : Peter time taken = 1
这表明collectionAndThen相较之下花费的时间更长。
所以我的问题是-我应该继续收集AndThen还是有其他建议?
最佳答案
collectingAndThen
添加一个仅在集合末尾执行的操作。
所以
String personWithMaxAge = persons.stream()
.collect(Collectors.collectingAndThen(
Collectors.maxBy(Comparator.comparing(Person::getAge)),
(Optional<Person> p) -> p.isPresent() ? p.get().getName() : "none"
));
与...没有什么不同
Optional<Person> p = persons.stream()
.collect(Collectors.maxBy(Comparator.comparing(Person::getAge)));
String personWithMaxAge = p.isPresent() ? p.get().getName() : "none";
在您将结果收集器用作另一个收集器(例如,收集器)的输入时,显示了在收集器中指定操作的实际优势。
groupingBy(f1, collectingAndThen(collector, f2))
。由于这是一个简单的操作,仅在最后执行一次,因此对性能没有影响。此外,对于任何非平凡的输入,基于
sorted
的解决方案都不可能比maxBy
操作快。您只是在使用破坏基准,违反了“ How do I write a correct micro-benchmark in Java?”中列出的一些规则。最值得注意的是,您正在测量Stream框架的首次使用的初始初始化开销。只需交换两个操作的顺序,您将获得完全不同的结果。
仍然不需要使操作不必要地复杂。如前所述,收集器镜像现有Stream操作的优点是它们可以与其他收集器组合。如果不需要这种组合,只需使用简单代码
String personWithMaxAge = persons.stream()
.max(Comparator.comparing(Person::getAge))
.map(Person::getName).orElse("none");
它比Collector的用法更简单,并且比基于
sorted
的解决方案更有效。关于java - collectionAndThen方法足够有效吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/47810524/