stream流map 多个字段_Stream 流实践

Stream 流

看之前:需要一些Lambda语法知识,可以查看参考资料中的文章:万字详解,JDK1.8的Lambda、Stream和日期的使用详解。

正文

Java8 API Stream 允许你以声明性方式处理数据集合或数组(通过查询语句来表达。

Stream 的特点:

  • Stream 自己不会存储数据

  • Stream 不会改变源对象,他们会返回一个持有结果的新对象

  • Stream 操作是延迟执行的,意味着他们只会在需要结果的时候才会执行。

  • Stream 只能消费一次,消费完毕之后就会关闭。

Stream流的使用分三步:创建流、中间操作、终端操作;Stream流是延迟执行的,只有终端操作才能触发整个流的执行。

1、流的操作步骤

1.1 创建流

流的操作:

  • 创建流:新建一个流

  • 中间操作:在一个或者多个步骤中将初始 stream 转化为另一个 stream

  • 终端操作:使用一个终端操生成一个结果,该操作会强制它之前的延迟操作立即执行,在这之后 stream 就无法再次使用了。

1.2 中间操作:

中间操作会返回另一个流,多个中间操作可以连接起来可以形成一个查询。重要的是,除非流水线上触发一个终端操作,否则中间操作不会执行任何处理。

ba77aa91d913993e4e17b39c691a7ae7.png

1.3 终端操作

终端口操作会从流的流水线生成结果。其结果是任何不是流的值,比如List、 Integer,甚至void。

c1a301d7b690f2cb7f7e407369a21914.png

默认收集器Collectors,Collectors是一个工具类,是JDK预实现Collector的工具类,它内部提供了多种Collector用来帮我们生成结果集合,主要的方法如下:

3129c46dd8f3d65bfc0f506af375ee22.png

2、Stream 的使用示例

学生类:

 1public class StudentBO {
2    /** 学生id **/
3    Integer id;
4
5    /** 学生姓名 **/
6    String name;
7
8    /** 班级id **/
9    Integer classId;
10
11    /** 学生年龄 **/
12    Integer age;
13
14    /** 分数 **/
15    Integer score;
16
17    /**身高 cm **/
18    Integer height;
19
20    /** 体重 kg**/
21    Integer weight;
22
23    /**24     * 获取学生的身体质量指数25     * @return26     */
27    public Double getStudentBMI() {
28        return (weight * 10000.0 / (height * height));
29    }
30
31    /**32     * 根据id大小对学生进行比较33     * @param s134     * @param s235     * @return36     */
37    public static int compare(StudentBO s1, StudentBO s2) {
38        return (s1.getId().compareTo(s2.id));
39    }
40
41    @Override
42    public boolean equals(Object o) {
43        if (this == o) return true;
44        if (o == null || getClass() != o.getClass()) return false;
45        StudentBO studentBO = (StudentBO) o;
46        return Objects.equals(id, studentBO.id);
47    }
48
49    @Override
50    public int hashCode() {
51        return Objects.hash(id, name, age, score);
52    }
53    //省略属性的get和set方法
54}

先预加载需要操作的集合:

 1public class StreamDemoTest {
2    private List studentBOList = new ArrayList(); 3    @Before 4    public void initTest() { 5        StudentBO studentA = new StudentBO(); 6        StudentBO studentB = new StudentBO(); 7        StudentBO studentC = new StudentBO(); 8        StudentBO studentD = new StudentBO(); 910        studentA.setId(1);11        studentA.setAge(20);12        studentA.setName("Tom");13        studentA.setScore(100);14        studentA.setHeight(175);15        studentA.setWeight(60);1617        studentB.setId(2);18        studentB.setAge(19);19        studentB.setName("Ken");20        studentB.setScore(60);21        studentB.setHeight(180);22        studentB.setWeight(60);2324        studentC.setId(3);25        studentC.setAge(19);26        studentC.setName("Bob");27        studentC.setScore(70);28        studentC.setHeight(175);29        studentC.setWeight(80);3031        studentBOList.add(studentA);32        studentBOList.add(studentB);33        studentBOList.add(studentC);34        studentBOList.add(studentD);35    }36}

2.1 创建流

1、直接通过集合对象的 stream() 方法创建
2、通过Arrays类的 stream()方法创建
3、通过Stream接口的 of()、 generate()、 iterator() 方法创建
4、通过 IntStream、LongStream、DubboStream 接口中的 of、range、rangeClosed 方法创建

2.2 中间操作

filter

filter 方法用于过滤符合条件的元素:

 1    @Test
2    public void testFilter() {
3        //筛选id不为空的元素
4        List reuslt1 = studentBOList.stream().filter(studentBO -> studentBO.getId() != null).map(studentBO -> { 5            Integer res = studentBO.getScore() * studentBO.getScore(); 6            return res; 7        }).collect(Collectors.toList()); 8 9        System.out.println(reuslt1);1011        //筛选score的平方大于 700的学生,并返回 score的平方12        List reuslt2 = studentBOList.stream().filter(studentBO -> {13            if (studentBO.getId() == null) {14                return false;15            }16            Integer score2 = studentBO.getScore() * studentBO.getScore();17            return score2 > 7000;18        }).map(studentBO -> {19            Integer res = studentBO.getScore() * studentBO.getScore();20            return res;21        }).collect(Collectors.toList());22        System.out.println(reuslt2);2324        //筛选年龄大于18岁的学生集合25        List sudentList26                = studentBOList.stream().filter(bo -> bo.getAge() > 18).collect(Collectors.toList());27    }

limit

limit 方法用于截断流:按照出现顺序保留N个。

1    @Test
2    public void testLimit() {
3        List  list = Arrays.asList(1, 2, 2, 3, 4, 5, 5);4        List result = list.stream().limit(5).collect(Collectors.toList());5        // 结果:[1, 2, 2, 3, 4]6        System.out.println(result);7    }

map

map 方法用于映射每个元素到对应的结果,一对一。

 1    @Test
2    public void testMapA() {
3        /** 4         * 求平方 5         */
6        List  list = Arrays.asList(1,2,3,4,5); 7        List result1 = list.stream().map(n -> n * n).collect(Collectors.toList()); 8        System.out.println(result1); 910        /**11         * 筛选id不为空的学生id12         */13        List reuslt2 = studentBOList.stream()14                .filter(studentBO -> studentBO.getId() != null)15                .map(studentBO -> {16                    Integer res = studentBO.getScore() * studentBO.getScore();17                    return res;18                }).collect(Collectors.toList());19        System.out.println(reuslt2);20    }

skip

按遇到的顺序丢弃前N个元素,如果少于N个元素,就返回空的stream。

1    @Test
2    public void testSkip() {
3        List  list = Arrays.asList(1, 2, 2, 3, 4, 5, 5);4        List result = list.stream().skip(5).collect(Collectors.toList());5        // [5, 5]6        System.out.println(result);7    }

distinct

使用java8新特性stream进行List去重,使用steam的distinct()方法返回一个由不同数据组成的流,通过对象的equals()方法进行比较,所以如果使用 distinct 方法,则需要重写List 中对象的 equals 方法。

 1    @Test
2    public void testDistinct() {
3        /** 4         * 对数字去重 5         */
6        List  list = Arrays.asList(1, 2, 2, 3, 4, 5, 5); 7        List result = list.stream().sorted().distinct().collect(Collectors.toList()); 8        System.out.println(result); 910        /**11         * 对学生集合去重12         */13        StudentBO studentE = new StudentBO();14        studentE.setId(3);15        studentE.setAge(19);16        studentE.setName("Bob");17        studentE.setScore(70);18        studentBOList.add(studentE);19        List list1 = studentBOList.stream().distinct().collect(Collectors.toList());20    }

sorted

sorted 是有状态的中间操作,返回由该流的元素组成的流,并根据自然顺序排序。

如果此流的元素不可比较,则在执行终端操作时可能会引发 java.lang.ClassCastException 异常。

对于有序流,排序是稳定的。对于无序流,不保证稳定性。

可以使用自然排序,或者自己实现排序方法:

1// 自然排序
2Stream sorted();
3// 自定义排序规则
4Stream sorted(Comparator super T> comparator);

代码示例:

 1    @Test
2    public void testSorted() {
3        // 自然排序
4        List  list = Arrays.asList(1, 2, 5, 4, 3); 5        List integers = list.stream().sorted().collect(Collectors.toList()); 6 7        // 按年龄排序 8        List result = studentBOList.stream() 9                .filter(studentBO -> studentBO.getId() != null)10                .sorted((s1, s2) -> {11                    return s1.getAge().compareTo(s2.getAge());12                }).collect(Collectors.toList());13        System.out.println(result);14    }

2.3 终端操作

max 和 min

max 和 min 操作可以获取最大值和最小值

 1    @Test
2    public void testMaxMIn() {
3        /** 4         * 获取id最大的学生 5         */
6        StudentBO max
7                = studentBOList
8                .stream()
9                .filter( bo -> bo.getId() != null)
10                .max(StudentBO::compare).get();
11        /**12         * 获取id最小的学生13         */
14        StudentBO min
15                = studentBOList
16                .stream()
17                .filter( bo -> bo.getId() != null)
18                .min(StudentBO::compare).get();
19
20        /**21         * 获取年龄最大的学生22         */
23        StudentBO max2
24                = studentBOList
25                .stream()
26                .filter( bo -> bo.getId() != null)
27                .max(Comparator.comparing(StudentBO::getAge)).get();
28
29        /**30         * for 循环实现:获取分数最大的学生31         */
32        boolean seen = false;
33        StudentBO best = null;
34        for (StudentBO bo : studentBOList) {
35            if (bo.getId() != null) {
36                if (!seen || bo.getScore().compareTo(best.getScore()) > 0) {
37                    seen = true;
38                    best = bo;
39                }
40            }
41        }
42        StudentBO max3
43                = (seen ? Optional.of(best) : Optional.empty()).get();4445        /**46         * stream 实现获取分数最大的学生47         */48        StudentBO max449                = studentBOList50                .stream()51                .filter( bo -> bo.getId() != null)52                .max((s1, s2) -> {return s1.getScore().compareTo(s2.getScore());}).get();5354    }

count

对流中的元素进行统计。

 1    @Test
2    public void testCount() {
3        //parallelStream 是流并行处理程序的代替方法。
4        List integers = Arrays.asList(1, 1, 2, 3, 4, 5, 6, 7, 8, 9); 5        //统计1的个数 6        long count1 = integers.parallelStream().filter(i -> {return i.equals(1);}).count(); 7 8        //统计其平方大于16的个数 9        long count2 = integers.parallelStream().filter( i -> {return i * i > 16;}).count();10    }

reduce

reduce 操作等价于:依次对流中的元素进行某种持续操作,降低了数据竞争的风险。

1T reduce(T identity, BinaryOperator accumulator);
2
3T result = identity;
4for (T element : this stream)
5    result = accumulator.apply(result, element)
6    return result;

利用reduce实现累加:

1    @Test
2    public void testReduce() {
3        List integers = Arrays.asList(1, 1, 2, 3, 4, 5, 6, 7, 8, 9);4        //求和的两种方式5        long sum1 = integers.stream().reduce(0, (a,b)->(a+b));6        long sum2 = integers.stream().reduce(0, Integer::sum);7    }

collect

对元素进行收集操作:

 1    @Test
2    public void testCollectors() {
3        /** 4         * 返回包含学生id和其BMI系数的map 5         */
6        Map result1 7                = studentBOList.stream() 8                .filter( bo -> bo.getId() != null) 9                .collect(Collectors.toMap(StudentBO::getId,StudentBO::getStudentBMI));1011        /**12         * 返回包含学生id和其对象的map13         */14        Map result2 = studentBOList.stream()15                .filter( bo -> bo.getId() != null)16                .collect(Collectors.toMap(StudentBO::getId, bo -> {17            return bo;18        }));1920        /**21         * 根据某个属性进行分类22         */23        Map> result3 = studentBOList.stream()24                .filter(bo -> bo.getId() != null)25                .collect(Collectors.groupingBy(StudentBO::getScore));2627        /**28         * 根据某个条件进行区分,29         * 条件为true or false30         */31        Map> result4 = studentBOList.stream()32                .filter(bo -> bo.getId() != null)33                .collect(Collectors.partitioningBy(bo -> {34                    return bo.getScore() > 60;35                }));3637        //计算所有学生的分数之和38        Integer sum1 = studentBOList.stream()39                .filter(bo -> bo.getId() != null)40                .collect(Collectors.summingInt(StudentBO::getScore));4142        /**43         * 将学生按照班级分类44         */45        Map> classStudentMap = studentBOList.stream()46                .filter(bo -> bo.getId() != null )47                .collect(Collectors48                        .groupingBy(49                                StudentBO::getClassId,50                                TreeMap::new,51                                Collectors.toList()52                        )53                );54        //{1=[StudentBO{id=1, name='Tom', age=20, score=100}], 2=[StudentBO{id=2, name='Ken', age=19, score=60}, StudentBO{id=3, name='Bob', age=19, score=70}]}55        System.out.println(classStudentMap);56    }

foreach

对所有的元素进行某种操作:

1    @Test
2    public void testForeach() {
3        List integers = Arrays.asList(1, 1, 2, 3, 4, 5, 6, 7, 8, 9);4        //打印所有的元素5        integers.stream().forEach(System.out::print);6    }

有不足或写的不好的地方,希望大家能不吝赐教!


菜鸟的Redis实战

参考资料

[1] 利用stream流对po与vo进行相互转换
[2] Java8 Stream终端操作使用详解
[3] 菜鸟:Java 8 Stream
[4] java箭头函数,lambda表达式
[5] 万字详解,JDK1.8的Lambda、Stream和日期的使用详解
[6] 本文代码地址:https://github.com/hustuhao/StreamDemo

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值