Java8 新特性之Stream流学习与见解

Java8之Stream流

因为公司使用到了Stream流,所以学习了一手,以下是我的见解,欢迎交流学习。


一、什么是Stream流?

1、Stream的特性

  1. 对stream的操作可以分为两类,中间操作(intermediate operations)结束操作(terminal operations)
  2. Stream流不是一种数据结构,不保存数据,它只是在原数据集上定义了一组操作。
  3. 这些操作是惰性的,即每当访问到流中的一个元素,才会在此元素上执行这一系列操作。
  4. Stream不保存数据,故每个Stream流只能使用一次。

2、与collections比较

  1. 无存储。stream不是一种数据结构,它只是某种数据源的一个视图,数据源可以是一个数组,Java容器或I/O channel等。
  2. 为函数式编程而生。对stream的任何修改都不会修改背后的数据源,比如对stream执行过滤操作并不会删除被过滤的元素,而是会产生一个不包含被过滤元素的新stream。
  3. 惰式执行。stream上的操作并不会立即执行,只有等到用户真正需要结果的时候才会执行。
  4. 可消费性。stream只能被“消费”一次,一旦遍历过就会失效,就像容器的迭代器那样,想要再次遍历必须重新生成。

二、Stream流的常用方法

1.模拟Student实体类 创建Test类实现

代码如下(示例):

1.实体类

/**
 * @Author xhw
 * @Date 2021/3/29 17:02
 * @description: Student实体类
 * @Version
 */
 
@Data
@AllArgsConstructor //所有参数构造
@NoArgsConstructor //无参构造
//@Data注解是Lombok插件的方法  用于实现SET GET
public class Student {
    private String name;
    private String sex;
    private Integer age;
    private String address;
}

2.测试类

/**
 * @Author xhw
 * @Date 2021/3/29 17:03
 * @description:测试类
 * @Version
 */
public class Test {
    public static void main(String[] args) {
		//创建测试集合
        List<Student> list = Arrays.asList(
                new Student("张三",18,"男","武汉"),
                new Student("张三",18,"男","武汉"),
                new Student("张一",19,"男","武汉"),
                new Student("张二",20,"男","武汉"),
                new Student("李四",20,"男","长沙"),
                new Student("王五",22,"女","上海"),
                new Student("赵六",24,"女","北京"),
                new Student("周七",26,"男","广州"),
                new Student("吴八",28,"女","武汉"),
                new Student("正九",30,"男","武汉"),
                new Student("王十",32,"女","武汉")
        );
    }
}

2.Stream获取方式

代码如下(示例):

  		// 1、数组
        String[] arr = new String[]{"ab", "cd", "ef"};
        Stream<String> arrStream = Arrays.stream(arr);
        // 2、集合
        List<String> newList = Arrays.asList("ab", "cd", "ef");
        Stream<String> colStream = newList.stream();
        // 3、值
        Stream<String> stream = Stream.of("ab", "cd", "ef");
        //4、Int数组转集合
        int [] num = new int[]{1,2,3,4,5};
        List<Integer> list1 = Arrays.stream(num).boxed().collect(Collectors.toList());

3.Stream流实现方法

1.forEach() 循环

	    // java 8 前
        System.out.println("java 8 前");
        for(Student stu: list){
            System.out.println(stu);
        }
        // java 8 lambda
        System.out.println("java 8 lambda");
        list.forEach(stu -> System.out.println(stu));

        // java 8 stream lambda
        System.out.println("java 8 stream lambda");
        list.stream().forEach(stu -> System.out.println(stu));

2.sorted() 单值排序与多值排序

        // java 8 前
        System.out.println("java 8 前");
        Collections.sort(list, new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
                return o1.getAge().compareTo(o2.getAge());
            }
        });
        for (Student stu : list) {
            System.out.println(stu);
        }
        // java 8 stream 方法引用
        System.out.println("java 8 stream 方法引用(正序)");
        list.stream().sorted(Comparator.comparing(Student::getAge)).forEach(stu -> System.out.println(stu));

 		System.out.println("java 8 stream 方法引用(倒序)");
 		list.stream().sorted(Comparator.comparing(Student::getAge).reversed()).forEach(stu -> System.out.println(stu));
 		
 		 System.out.println("Stream流 多值排序(正序)");
 		 list.stream().sorted(Comparator.comparing(Student::getAge)
 		 		.thenComparing(Student::getName)).forEach(stu -> System.out.println(stu));
 		 		
 		 System.out.println("Stream流 多值排序(倒序)");
 		 list.stream().sorted(Comparator.comparing(Student::getAge,Comparator.reverseOrder())
 		 .thenComparing(Student::getName,Comparator.reverseOrder())).forEach(stu -> System.out.println(stu));

3.groupingBy()单值分组与多值分组

	 List<Student> list = new ArrayList(); //DataSource
	 
     System.out.println("Stream流 单值分组");
     //根据学生年龄进行分组
	 Map<String, List<Student>> studentMap = 
	 			list.parallelStream().collect(Collectors.groupingBy(Student::getAge));
	 			
	 System.out.println("Stream流 多值分组");
	 //根据班级、学生年龄进行分组  根据不同班级、不同年龄的学生给予特定编号 
	 
	           //因为入参为HashMao,为保证线程安全用AtomicReference转换迭代器
                AtomicReference<Integer> groupId = new AtomicReference<>(0);
                list.parallelStream()
                        .collect(Collectors.groupingBy(Student::getClassID, HashMap::new,
                                Collectors.groupingBy(Student::getAge))).forEach((k, v) -> {
                            //k => 班级编码
                            // v => 班级下所有学生信息  k1 => 年龄  v1 => 班级+年龄分组后 所有数据
                            v.forEach((k1, v1) -> {
                                //根据班级+年龄 分组ID迭代
                                groupId.getAndSet(groupId.get() + 1);
                                v1.forEach(s -> {
                                    //特定编号
                                    s.setStudentID(s.getClassID() + s.getAge() + "-" + groupId.get());
                                });
                            });
                        });
	 			

4.filter():使用该方法拦截

        // 拦截小于24岁的人
        System.out.println("-----过滤前-----");
        list.forEach(stu-> System.out.println(stu));
        System.out.println("-----过滤后-----");
        // java 8 前
        System.out.println("java 8 前");
        for(Student stu: list){
           if (stu.getAge() > 25) {
                System.out.println(stu);
            }
        }
        // java 8 stream
        System.out.println("java 8 stream");
        list.stream().filter((Student stu) -> stu.getAge() >24).forEach(stu-> System.out.println(stu));

输出:
在这里插入图片描述
由上可见,此方法可以拦截24岁之前的Student,且包括24岁;

5.limit():使用该方法截取

		// 从第一个开始截取,只取3个
        System.out.println("-----截断前-----");
        list.forEach(stu -> System.out.println(stu));
        System.out.println("-----截断后-----");
        // java 8 前
        System.out.println("java 8 前");
        for (int i = 0; i < 3; i++) {
            System.out.println(list.get(i));
        }
        // java 8 stream
        System.out.println("java 8 stream");
        list.stream().limit(3).forEach(stu -> System.out.println(stu));

输出:

在这里插入图片描述

6.skip():与limit互斥,使用该方法跳过元素

  		// 跳过前8个元素,从第9个开始输出
        System.out.println("-----跳过前-----");
        list.forEach(stu -> System.out.println(stu));
        System.out.println("-----跳过后-----");
        // java 8 前
        System.out.println("java 8 前");
        for (int i = 8; i < list.size(); i++) {
            System.out.println(list.get(i));
        }
        // java 8 stream
        System.out.println("java 8 stream");
        list.stream().skip(8).forEach(stu -> System.out.println(stu));

输出:
在这里插入图片描述

7.distinct():使用该方法去重

        // 因为Arrays.asList() 返回的是Arrays的内部类ArrayList,操作remove,add会报错
        // 为list去除重复数据
        System.out.println("-----去重前-----");
        list.forEach(stu -> System.out.println(stu));
        System.out.println("-----去重后-----");
        // java 8 前
        System.out.println("java 8 前");
        for (int i = 0; i < list.size() - 1; i++) {
            for (int j = list.size() - 1; j > i; j--) {
                if (list.get(j).getAge().equals(list.get(i).getAge()) && list.get(j).getName()
                        .equals(list.get(i).getName())) {
                    list.remove(i);
                }
            }
        }
        for (Student stu : list) {
            System.out.println(stu);
        }
        // java 8 stream
        System.out.println("java 8 stream");
        list.stream().distinct().forEach(stu -> System.out.println(stu));

注意:必须重写对应泛型的hashCode()和equals()方法,且参数一定要所有列对应,否则去重无效果。

输出:
在这里插入图片描述

8.max,min,sum,avg,count

    IntSummaryStatistics num = list.stream().mapToInt(stu -> stu .getAge())
        .summaryStatistics();
    System.out.println("总共人数:" + num.getCount());
    System.out.println("平均年龄:" + num.getAverage());
    System.out.println("最大年龄:" + num.getMax());
    System.out.println("最小年龄:" + num.getMin());
    System.out.println("年龄之和:" + num.getSum());

输出:
在这里插入图片描述

9.map():接收一个方法作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素

 		// 只输出所有人的年龄
        list.stream().forEach(stu -> System.out.println(stu));
        System.out.println("映射后----->");
        List<Integer> ages = list.stream().map(stu -> stu.getAge()).collect(Collectors.toList());
        ages.forEach(age -> System.out.println(age));

        // 小写转大写
        List<String> words = Arrays.asList("aaa", "vvvv", "cccc");
        System.out.println("全部大写---->");
        List<String> collect = words.stream().map(s -> s.toUpperCase()).collect(Collectors.toList());
        collect.forEach(s -> System.out.println(s));

输出:
在这里插入图片描述

10.flatMap():对每个元素执行mapper指定的操作,并用所有mapper返回的Stream中的元素组成一个新的Stream作为最终返回结果,通俗易懂就是将原来的stream中的所有元素都展开组成一个新的stream

    //创建一个 装有两个泛型为integer的集合
    Stream<List<Integer>> stream = Stream.of(Arrays.asList(1, 2, 3), Arrays.asList(4, 5));
    // 将两个合为一个
    Stream<Integer> integerStream = stream.flatMap(
        (Function<List<Integer>, Stream<Integer>>) integers -> integers.stream());
    // 为新的集合
    List<Integer> collect = integerStream.collect(toList());
    System.out.println("新stream大小:"+collect.size());
    System.out.println("-----合并后-----");
    collect.forEach(o -> System.out.println(o));

输出:
在这里插入图片描述

11.使用 toList 接收处理完成的数据

    List<String> list = new ArrayList<>();
    list.add("1");
    list.add("1");
    list.add("2");
    list.add("4");
    list.add("4");
    list.add("6");
    List<String> collect = list.stream().distinct().collect(Collectors.toList());
    System.out.println(list);  // [1, 1, 2, 4, 4, 6]
    System.out.println(collect); // [1, 2, 4, 6]

三、使用Stream流的常见问题

1.使用sorted()排序后groupingBy()进行分组导致排序失效

		List<Student> list = new ArrayList(); //DataSource
		//先进行排序后 入参为LinkedHashMap 变为有序集合  避免排序混乱
		Map<String, List<Student>> collect =
		                	list.stream()
		                        .sorted(Comparator.comparing(Student::getClassID)
		                                .thenComparing(Student::getAge)
		                                .thenComparing(Student::getName)
		                                .thenComparing(Student::getId))
		                        .collect(Collectors.groupingBy
		                        	(Student::getClassId,LinkedHashMap::new, Collectors.toList()));

练习题

  1. 找到不是武汉年龄小于25岁的男生,去重后根据年龄顺序,取前三
		list.stream()
                .distinct()
                .filter(stu ->stu.getAge() <25)
                .filter(stu ->!stu.getAddress().equals("武汉"))
                .sorted(Comparator.comparing(Student::getAge))
                .limit(3).forEach(stu -> System.out.println(stu));
  1. 去重后计算出 list总记录数 age的平均 最大 最小值 以及年龄总和
		//去重后转换成新数组进行接收
		List<Student> newList =
               list.stream().distinct().collect(Collectors.toList());
        IntSummaryStatistics num = newList.stream().mapToInt(s -> s.getAge())
                .summaryStatistics();
        System.out.println("长度:"+newList.size());
        System.out.println("最大年龄:" + num.getMax());
        System.out.println("最小年龄:" + num.getMin());
        System.out.println("年龄之和:" + num.getSum());
        System.out.println("平均年龄:" + num.getAverage());
  1. 给你一个有序数组 nums,请你删除重复出现的元素,使每个元素只出现一次且倒序输出,最后返回删除后数组的新长度
public static int removeDuplicates(int[] nums){
        List<Integer> list =
                //将数组转为List进行stream流操作
               Arrays.stream(nums).boxed().collect(Collectors.toList());
        List<Integer> newList
                //去重  排序倒序   转成集合储存
                =list.stream().distinct().sorted(Comparator.reverseOrder()).collect(Collectors.toList());
        //输出结果
        newList.stream().forEach(plt -> System.out.println(plt));
    }
    public static void main(String[] args) {
        int [] nums = {1,1,1,2,2,3,4,5};
        int i = removeDuplicates(nums);
        System.out.println(i);
    }
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值