我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Java8函数式编程之收集器怎么应用

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Java8函数式编程之收集器怎么应用

这篇文章主要介绍“Java8函数式编程之收集器怎么应用”,在日常操作中,相信很多人在Java8函数式编程之收集器怎么应用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java8函数式编程之收集器怎么应用”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

    收集器

    收集器是一种通用的、从流生成复杂值的结构。可以使用它从流中生成List、Set、Map等集合。 收集器都是在流的collect方法中调用,并且都在 Collectors类中。

    java 的标准类库提供了很多有用的收集器,当然了,也可以自己自定义(这个对于使用者的要求很高)。

    下面提供一个代码,用于测试接下里要说的收集器:

    提供了一个简单的测试数据

    学号 姓名 性别 语文 数学 英语 物理 政治 总分
    09509002 节强 男 86 90 90 93 90
    09509003 杨青 女 90 90 82 91 92
    09509006 徐刚 男 78 92 83 90 87
    09509111 马力 男 77 88 99 90 88
    09509001 武向丽 女 90 78 83 94 94
    09509007 张文静 女 85 90 79 94 88
    09509005 徐小红 女 78 85 88 93 92
    09509009 李姝 女 92 80 75 90 88
    09509004 李文华 男 68 59 70 85 90
    09509008 夏婧 女 87 65 73 91 95
    09509010 王洪 男 66 48 89 70 57

    Student 实体类封装数据

    package com.cdragon;public class Student implements Comparable<Student> {    private String number;    private String name;    private String sex;    private Integer chinese;    private Integer math;    private Integer english;    private Integer physics;    private Integer politics;//省略getter和setter方法,这个使用IDE自动生成特别方便。//省略toString方法,同上。@Override    public int compareTo(Student s) {        return s.getNumber().compareTo(this.getNumber());    }}

    LoadData 类加载数据到内存

    package com.cdragon;import java.io.*;import java.util.ArrayList;import java.util.List;public class LoadData {    public static List<Student> readFromFile(File file) {        List<Student> students = new ArrayList<>();        try (BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file)))) {            String record = null;            String header = br.readLine();            //对于数据的第一行头,暂时不做处理。            while ((record = br.readLine() ) != null) {                Student s = resolveLineToStudent(record);                students.add(s);            }        } catch (FileNotFoundException e) {            e.printStackTrace();        } catch (IOException e) {            e.printStackTrace();        }        return students;    }    private static Student resolveLineToStudent(String record) {        String[] array = record.split("\\s+");  // \\s 和 \\s+ 还是有区别的!        Student s = new Student();        s.setNumber(array[0]);        s.setName(array[1]);        s.setSex(array[2]);        s.setChinese(Integer.parseInt(array[3]));        s.setMath(Integer.parseInt(array[4]));        s.setEnglish(Integer.parseInt(array[5]));        s.setPhysics(Integer.parseInt(array[6]));        s.setPolitics(Integer.parseInt(array[7]));        return s;    }}

    收集器应用

    将流转换成其他集合

    使用收集器是可以生成其他集合的,例如生成List、Set 和 Map等,下面来分别举例:

    //生成 List        List<Student> studentList = students.stream().collect(Collectors.toList());        //生成 Set        Set<Student> studentSet = students.stream().collect(Collectors.toSet());        //生成指定集合        TreeSet<Student> studentTreeSet = students.stream().collect(Collectors.toCollection(TreeSet::new));        //生成 Map         Map<String, Student> studentMap = students.stream().collect(Collectors.toMap(Student::getNumber, s->s));        studentMap.forEach((no, s)->{            System.out.println(no + "->" + s);        });

    说明:通常的 toList() 和 toSet() 方法是不指定生成集合的具体类型,这是由系统来选择最合适的类型,但是有时候我们必须返回特定的类型集合,这就用到了 toCollection() 方法,这个方法可以指定需要生成的集合的类型,这是使用方法引用进行简化代码:TreeSet::new

    测试结果:

    Java8函数式编程之收集器怎么应用

    注意:生成 Map 的方式较为复杂,因为需要同时指定键和值。

    转换成值

    使用收集器生成一个值。

    最大值和最小值

    Collectors 类中的 maxBy 和 minBy 允许用户按照某种特定顺序生成一个值。它们的作用就如同它们的名字一样,分别是寻找最大值和最小值。

    我写成一个方法,这样调用比较方便。

    public static Optional<Student> minOrMaxSubject(List<Student> students, Comparator<? super Student> comparator) {    return students.stream().collect(Collectors.maxBy(comparator));}

    说明:使用 maxBy 或者 minBy 必须传入一个 Comparator 对象作为参数,即参数为一个比较器。

    测试代码

    //这个文件的路径应该使用自己指定的List<Student> students = LoadData.readFromFile(new File("class="lazy" data-src/grade.txt"));//获取数学最高分学生Optional<Student> s1 = TestStream.minOrMaxSubject(students, Comparator.comparing(Student::getMath));//获取英语最高分Optional<Student> s2 = TestStream.minOrMaxSubject(students, Comparator.comparing(Student::getEnglish));System.out.println(s1.get());System.out.println(s2.get());

    测试结果

    Java8函数式编程之收集器怎么应用

    说明:如果想要测试最低分,只要把上面的 maxBy 改成 minBy 就行了,或者直接更进一步,修改参数为collect里面传入的函数,不过那样就会显得格外复杂,而且不止可以查最高分和最低分了。

    平均值

    上面看过了最大值和最小值,现在来看看平均值。 下面这个方法是用来求单科平均分的。

     public static double averageScore(List<Student> students, ToIntFunction<? super Student> mapper) {     return students.stream().collect(Collectors.averagingInt(mapper)); }

    测试代码

    List<Student> students = LoadData.readFromFile(new File("class="lazy" data-src/grade.txt"));double math = TestStream.averageScore(students, Student::getMath);System.out.println("数学的单科平均分:" + math);

    测试结果

    Java8函数式编程之收集器怎么应用

    数据分块

    数据分块是指收集器将流分为两个集合,注意分块是只能分成两块。这里标准类库提供了一个收集器 partitioningBy,它接受一个流,并将其分为两个部分。返回的结果为一个 Map,键只有两种:true 或者 false,值是满足对应条件的集合。

    例如我想知道某们成绩 90分以上和一下的学生分别是哪些。

     public static Map<Boolean, List<Student>> splitScore(List<Student> students, Predicate<? super Student> predicate) {     return students.stream().collect(Collectors.partitioningBy(predicate)); }

    说明:partitioningBy的参数为一个 Predicate 对象,这个和过滤器的很相似,功能上可以对比学习。

    测试代码

    //数学成绩以90分来划分学生Map<Boolean, List<Student>> booleanListMap = TestStream.splitScore(students, stu->stu.getMath()>=90);booleanListMap.forEach((bool, list)->{    System.out.println("数学成绩大于90分:" + bool);    list.forEach(System.out::println);    System.out.println("========================");});

    测试结果

    Java8函数式编程之收集器怎么应用

    数据分组

    数据分组是一种更为自然的分割数据操作,与将数据分成true和false两部分不同,可以使用任意值对数据分组。比如使用性别对学生进行分组。这很像SQL中的 groupBy 操作。

    public static Map<String, List<Student>> groupBy(List<Student> students) {    return students.stream().collect(Collectors.groupingBy(Student::getSex));}

    测试代码

    Map<String, List<Student>> stringListMap = TestStream.groupBy(students);stringListMap.forEach((sex, list)->{    System.out.println("性别:" + sex);    list.forEach(System.out::println);    System.out.println("============");});

    测试结果

    Java8函数式编程之收集器怎么应用

    字符串

    收集流中的数据最后生成一个字符串,这是一个很平常的操作。 例如一个所有学生的姓名列表,使用传统的迭代列表操作代码如下:

      public static String nameStr1(List<Student> students) {     StringBuilder builder = new StringBuilder("[");     for (Student stu : students) {         if (builder.length() > 1){             builder.append(",");         }         String name = stu.getName();         builder.append(name);     }     builder.append("]");     return builder.toString(); }

    然后是使用收集器进行操作,代码如下: 这里我添加一些细节处理,学生的排名按照学生的总成绩从高到底排列,这是很符合习惯的。

    public static String nameStr2(List<Student> students) {    return students.stream()            .sorted(Comparator.comparing(s -> {                return s.getChinese() + s.getMath() + s.getEnglish()                        + s.getPhysics() + s.getPolitics();            }, Comparator.reverseOrder()))  //(sum1, sum2)-> sum2.compareTo(sum1)            .map(Student::getName)            .collect(Collectors.joining(",","[","]"));}

    说明:这里的 sorted 需要传入一个 Comparator 对象,但是可以使用静态方法 Compring 进行简化,但是它只是指定需要排序的标准,并没有说是从小到大还是从大到小,后来才发现,这个是默认的:大小到大排序。但是我需要的是使用从大到小,然后发现原来 compring 还有重载方法,具有两个参数,另一个参数是可以指定大小顺序的,所以第二个参数我传入了一个 Lambda 表达式:

    (sum1, sum2)-> sum2.compareTo(sum1)

    但是如果这样使用的话,还不如直接使用 Lambda 表达式创建 Comparator 对象方便呢,后来发现这个 IDE 比较智能,它指出这句代码,可以被替换为:

    Comparator.reverseOrder();// 看意思就知道是 反序的意思。

    这样看来使用 Comparator 静态的 comparing 方法还是比直接创建 Comparator 对象简单一些。

    注意:如果不需要排序的话,就只有一个map方法和join方法了。这个map方法的作用是映射(我一开始把它和map集合总是搞混了),将Student对象映射为name字符串,然后使用 join 方法进行连接。

    组合收集器

    收集器还可以组合起来使用,这个和 SQL 感觉更像了,几乎具有函数式编程的语言,都有SQL那种处理数据的方式,例如最大值、最小值和分组等操作。 考虑对于学生按照性别分组,然后再分别统计男女生的人数。(这个在 SQL 里面也是一个基本的练习。)

    public static Map<String, Long> combination(List<Student> students) {    return students.stream().collect(Collectors.groupingBy(Student::getSex, Collectors.counting()));}

    测试代码

    Map<String, Long> stringLongMap = TestStream.combination(students);stringLongMap.forEach((sex, count)->{    System.out.println("性别:" + sex + ", 人数:" + count);});

    测试结果

    Java8函数式编程之收集器怎么应用

    使用流的其他操作

    对于流的使用,应该达到一个较为熟练的地步,但是由于没有什么机会实践,还是比较陌生。下面介绍几个我写的方法,来看看流的操作:

    //通过过滤器选择特定的学生,过滤器用于过滤,然后选择第一个学生。//这里应该加一个排序操作比较好。public static Optional<Student> selectStudent(List<Student> students, Predicate<?  super Student> pre) {        return students.stream().filter(pre).findFirst();    }public static List<Student> orderBy(List<Student> students, Comparator<? super Student> comparator) {    if (comparator != null){        return students.stream().sorted(comparator).collect(Collectors.toList());    } else {        return students.stream().sorted().collect(Collectors.toList());    }}//获取一列数据。不是一行学生记录,是一列。public static List<?> getAColumn(List<Student> students, Function<? super Student, ?> mapper) {    return students.stream().map(mapper).collect(Collectors.toList());}public static Map<String, Integer> getSum(List<Student> students) {    return students.stream().collect(Collectors.toMap(Student::getNumber, stu->{        return stu.getChinese() + stu.getEnglish() + stu.getMath() + stu.getPhysics() + stu.getPolitics();    }));}public static List<Student> addScore1(List<Student> students, Consumer<? super Student> action) {    return students.stream().peek(action).collect(Collectors.toList());}public static void addScore2(List<Student> students, Consumer<? super Student> action) {    students.stream().forEach(action);}//指定返回类型为 LinkedList,这时一个测试,并不是说需要这样写。//多数情况下,我们还是应该使用 ArrayListpublic static List<Student> addScore3(List<Student> students, Consumer<? super Student> action) {    return students.stream().peek(action).collect(Collectors.toCollection(LinkedList::new));}

    对于其中的几个进行测试(不是全部方法,如果感兴趣,可以自己尝试。):

    //对于学生进行排序,参数为一个比较器,参数为空的话,使用默认的 sorted 排序。//测试代码 按照学号排序(默认从小到大)TestStream.orderBy(students,Comparator.comparing(Student::getNumber)).forEach(System.out::println);//按照学号排序(从大到小)TestStream.orderBy(students,Comparator.comparing(Student::getNumber, Comparator.reverseOrder())).forEach(System.out::println);//使用默认的排序TestStream.orderBy(students).forEach(System.out::println);//获取一列学生的记录,例如这里是英语成绩,这里返回值我使用通配符应该没有错吧//因为返回数据可能为 String 也可能是 IntegerTestStream.getAColumn(students,Student::getEnglish).forEach(System.out::println);//测试学生的总分TestStream.getSum(students).forEach((no, stu)->{    System.out.println(no + " -> " + stu);});

    到此,关于“Java8函数式编程之收集器怎么应用”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注编程网网站,小编会继续努力为大家带来更多实用的文章!

    免责声明:

    ① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

    ② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

    Java8函数式编程之收集器怎么应用

    下载Word文档到电脑,方便收藏和打印~

    下载Word文档

    猜你喜欢

    Java8函数式编程之收集器怎么应用

    这篇文章主要介绍“Java8函数式编程之收集器怎么应用”,在日常操作中,相信很多人在Java8函数式编程之收集器怎么应用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java8函数式编程之收集器怎么应用”的疑
    2023-07-06

    详解Java8函数式编程之收集器的应用

    这篇文章主要介绍了详解Java8函数式编程之收集器的应用,收集器是一种通用的、从流生成复杂值的结构。可以使用它从流中生成List、Set、Map等集合,需要的朋友可以参考下
    2023-05-15

    Java函数式编程怎么应用

    今天小编给大家分享一下Java函数式编程怎么应用的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。Java 根据常用需求场景的用
    2023-07-04

    JavaScript中的函数式编程怎么应用

    本文小编为大家详细介绍“JavaScript中的函数式编程怎么应用”,内容详细,步骤清晰,细节处理妥当,希望这篇“JavaScript中的函数式编程怎么应用”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。JavaS
    2023-06-27

    怎么在Java8项目中实现一个函数式编程

    这期内容当中小编将会给大家带来有关怎么在Java8项目中实现一个函数式编程,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。函数式的思考命令式编程一般我们实现一个系统有两种思考方式,一种专注于如何实现,比如下
    2023-05-31

    Java响应式编程之handle怎么使用

    这篇文章主要介绍“Java响应式编程之handle怎么使用”,在日常操作中,相信很多人在Java响应式编程之handle怎么使用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java响应式编程之handle怎
    2023-07-04

    Golang函数式编程在机器学习中的应用

    函数式编程在机器学习中的优势:不可变性:确保数据在算法执行过程中不会受到破坏,避免难以跟踪的错误。模块性:通过闭包和 lambda 表达式轻松创建和组合函数,使算法易于维护和可重用。并发性和并行性:利用 goroutine 和 channe
    Golang函数式编程在机器学习中的应用
    2024-04-13

    Java中的函数式编程怎么使用

    本文小编为大家详细介绍“Java中的函数式编程怎么使用”,内容详细,步骤清晰,细节处理妥当,希望这篇“Java中的函数式编程怎么使用”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。概述背景函数式编程的理论基础是阿隆
    2023-07-05

    怎么使用JS函数式编程实现XDM

    这篇文章主要讲解了“怎么使用JS函数式编程实现XDM”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“怎么使用JS函数式编程实现XDM”吧!FP 概览重要性函数式编程(FP),不是一个新的概念,
    2023-07-02

    函数式编程在Golang中的最佳应用场景是什么?

    函数式编程在 go 中的最佳应用场景是:并发和并行计算:fp 不可变数据和无副作用函数确保并发任务不会相互干扰。事件处理:fp 重点是不可变性,适合处理事件而无需担心副作用。数据转换和管道:go 的 first-class function
    函数式编程在Golang中的最佳应用场景是什么?
    2024-04-13

    Python中怎么利用toolz库实现函数式编程

    本篇文章给大家分享的是有关Python中怎么利用toolz库实现函数式编程,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。使用 toolz 库来构建。 这个库具有操作此类函数的函
    2023-06-17

    怎么在ABAP里用函数式编程思想打印出非波拉契Fibonacci

    小编给大家分享一下怎么在ABAP里用函数式编程思想打印出非波拉契Fibonacci,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!在ABAP里也有很多种方式实现这个
    2023-06-02

    编程热搜

    • Python 学习之路 - Python
      一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
      Python 学习之路 - Python
    • chatgpt的中文全称是什么
      chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
      chatgpt的中文全称是什么
    • C/C++中extern函数使用详解
    • C/C++可变参数的使用
      可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
      C/C++可变参数的使用
    • css样式文件该放在哪里
    • php中数组下标必须是连续的吗
    • Python 3 教程
      Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
      Python 3 教程
    • Python pip包管理
      一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
      Python pip包管理
    • ubuntu如何重新编译内核
    • 改善Java代码之慎用java动态编译

    目录