Java8中使用stream进行分组统计和普通实现的分组统计的性能对比

栏目: 编程语言 · Java · 发布时间: 6年前

内容简介:在ImportNew上面看到一篇文章:Java8通过流对集合的分组操作,让分组功能实现起来就非常容易了,我就想对其性能做一下比较,看看这二者之间是否有差距。我把ImportNew上面的示例做了一下扩充,在原来的Article对像中增加了国家和省份两个,后续的示例就根据国家和省份进行二维分组统计,然后比较一下性能和效率。

在ImportNew上面看到一篇文章: http://www.importnew.com/14841.html ,说的是使用 Java 8的对集合采用流操作的新特性,替代旧的使用循环对集合操作的方式,使用Java8的流操作功能对集合进行分组,以及对相应的内容进行去重等操作等,使用Java8编写的代码可读性和理解性都有了非常大的提高,是非常值得称称赞的。

Java8通过流对集合的分组操作,让分组功能实现起来就非常容易了,我就想对其性能做一下比较,看看这二者之间是否有差距。

我把ImportNew上面的示例做了一下扩充,在原来的Article对像中增加了国家和省份两个,后续的示例就根据国家和省份进行二维分组统计,然后比较一下性能和效率。

Article对像:

/**
 * ClassName:Article <br/>
 * Date: 2018年5月8日 上午10:31:03 <br/>
 * 
 * @author fenglibin
 * @version
 * @see
 */
public class Article {

    private final String       title;
    private final String       author;
    private final List<String> tags;
    private final String       countryCode;
    private final String       province;

    public Article(String title, String author, List<String> tags, String countryCode, String province){
        this.title = title;
        this.author = author;
        this.tags = tags;
        this.countryCode = countryCode;
        this.province = province;
    }

    public String getTitle() {
        return title;
    }

    public String getAuthor() {
        return author;
    }

    public List<String> getTags() {
        return tags;
    }

    public String getCountryCode() {
        return countryCode;
    }

    public String getProvince() {
        return province;
    }

}

准备一些测试数据:

private static List<Article> articles = new ArrayList<Article>();

    static {
        Article a1 = new Article("Hello World", "Tom", Arrays.asList("Hello", "World", "Tom"), "CN", "GD");
        Article a2 = new Article("Thank you teacher", "Bruce", Arrays.asList("Thank", "you", "teacher", "Bruce"), "CN",
                                 "GX");
        Article a3 = new Article("Work is amazing", "Tom", Arrays.asList("Work", "amazing", "Tom"), "CN", "GD");
        Article a4 = new Article("New City", "Lucy", Arrays.asList("New", "City", "Lucy", "Good"), "US", "OT");
        articles.add(a1);
        articles.add(a2);
        articles.add(a3);
        articles.add(a4);
    }

使用普通的分组方式进行分组:

/**
     * 通过for循环逻辑,编程上会麻烦点,但是效率上高很多
     */
    private static void groupByCountryAndProvince_byNormal() {
        Map<String, Map<String, List<Article>>> result = new HashMap<String, Map<String, List<Article>>>();
        for (Article article : articles) {
            Map<String, List<Article>> pMap = result.get(article.getCountryCode());
            if(pMap==null) {
                pMap = new HashMap<String, List<Article>>();
                result.put(article.getCountryCode(), pMap);
            }
            List<Article> list = pMap.get(article.getProvince());
            if(list==null) {
                list = new ArrayList<Article>();
                pMap.put(article.getProvince(), list);
            }
            list.add(article);
        }
        result.forEach((cc, map) -> {
            System.out.println("Country Code is:" + cc);
            map.forEach((pc, list) -> {
                System.out.println("    Province Code is:" + pc);
                list.forEach((article) -> {
                    System.out.println("        Article titile is:" + article.getTitle() + ",author is:"
                                       + article.getAuthor());
                });
            });
        });
    }

使用串行流的方式进行分组:

/**
     * 以串行流的方式,通过Collectors做多维度的分组,非常方便,但是性能上很差
     */
    private static void groupByCountryAndProvince() {
        Map<String, Map<String, List<Article>>> result = articles.stream()
                .collect(Collectors.groupingBy(Article::getCountryCode,
                                                Collectors.groupingBy(Article::getProvince)));
        result.forEach((cc, map) -> {
            System.out.println("Country Code is:" + cc);
            map.forEach((pc, list) -> {
                System.out.println("    Province Code is:" + pc);
                list.forEach((article) -> {
                    System.out.println("        Article titile is:" + article.getTitle() + ",author is:"
                                       + article.getAuthor());
                });
            });
        });
    }

使用并行流的方式进行分组:

/**
     * 以并行流的方式,通过Collectors做多维度的分组,性能上比串行流的效率就高很多了
     * 实现方式也很简单,只需要将stream()修改为parallelStream()实现。
     */
    private static void groupByCountryAndProvinceParallel() {
        Map<String, Map<String, List<Article>>> result = articles.parallelStream()
                .collect(Collectors.groupingBy(Article::getCountryCode,
                                                    Collectors.groupingBy(Article::getProvince)));
        result.forEach((cc, map) -> {
            System.out.println("Country Code is:" + cc);
            map.forEach((pc, list) -> {
                System.out.println("    Province Code is:" + pc);
                list.forEach((article) -> {
                    System.out.println("        Article titile is:" + article.getTitle() + ",author is:"
                                       + article.getAuthor());
                });
            });
        });
    }

加入以下代码执行:

public static void main(String[] args) {
        long start = System.currentTimeMillis();
        groupByCountryAndProvince();
        long end = System.currentTimeMillis();
        System.out.println("串行流分组使用时长(毫秒):" + (end - start)+"\n");
        
        start = System.currentTimeMillis();
        groupByCountryAndProvinceParallel();
        end = System.currentTimeMillis();
        System.out.println("并行流分组使用时长(毫秒):" + (end - start)+"\n");
        
        start = System.currentTimeMillis();
        groupByCountryAndProvince_byNormal();
        end = System.currentTimeMillis();
        System.out.println("普通分组使用时长(毫秒):" + (end - start));
    }

得到的结果如下:

Country Code is:CN
    Province Code is:GX
        Article titile is:Thank you teacher,author is:Bruce
    Province Code is:GD
        Article titile is:Hello World,author is:Tom
        Article titile is:Work is amazing,author is:Tom
Country Code is:US
    Province Code is:OT
        Article titile is:New City,author is:Lucy
串行流分组使用时长(毫秒):70


Country Code is:CN
    Province Code is:GX
        Article titile is:Thank you teacher,author is:Bruce
    Province Code is:GD
        Article titile is:Hello World,author is:Tom
        Article titile is:Work is amazing,author is:Tom
Country Code is:US
    Province Code is:OT
        Article titile is:New City,author is:Lucy
并行流分组使用时长(毫秒):5


Country Code is:CN
    Province Code is:GX
        Article titile is:Thank you teacher,author is:Bruce
    Province Code is:GD
        Article titile is:Hello World,author is:Tom
        Article titile is:Work is amazing,author is:Tom
Country Code is:US
    Province Code is:OT
        Article titile is:New City,author is:Lucy
普通分组使用时长(毫秒):1

执行多次也基本上是类似的效果,因此通过以上示例可以看出,在代码的编写上确实优化了不少,但即使通过并行流的方式,性能上的差距也不少,在真实的应用场景中特别是高并发的场景中,使用的时候还是需要多考虑,毕竟鱼和熊掌不可兼容了。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

娱乐至死

娱乐至死

[美] 尼尔·波兹曼 / 章艳 / 广西师范大学出版社 / 2011-6 / 29.80元

《娱乐至死》是对20世纪后半叶美国文化中最重大变化的探究和哀悼:印刷术时代步入没落,而电视时代蒸蒸日上;电视改变了公众话语的内容和意义;政治、宗教、教育和任何其他公共事务领域的内容,都不可避免的被电视的表达方式重新定义。电视的一般表达方式是娱乐。一切公众话语都日渐以娱乐的方式出现,并成为一种文化精神。一切文化内容都心甘情愿地成为娱乐的附庸,而且毫无怨言,甚至无声无息,“其结果是我们成了一个娱乐至死......一起来看看 《娱乐至死》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

MD5 加密
MD5 加密

MD5 加密工具