JDK8新特性--强大的Stream API

尚学堂之Jdk8学习笔记。学习视频链接(B站): https://www.bilibili.com/video/av68043832/?p=7

前言

Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询。也可以使用 Stream API 来并行执行操作。
简而言之,Stream API 提供了一种高效且易于使用的处理数据的方式。


什么是流(Stream)?

是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。
“集合讲的是数据,流讲的是计算!”

注意:
①Stream 自己不会存储元素。
②Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。
③Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。


三个步骤操作Stream

  • 创建 Stream

    一个数据源(如:集合、数组),获取一个流

  • 中间操作

    一个中间操作链,对数据源的数据进行处理

  • 终止操作(终端操作)

    一个终止操作,执行中间操作链,并产生结果

stream的操作流程


Stream的创建

  • 1.集合创建stream流
    Java8 中的 Collection 接口被扩展,提供了两个获取流的方法:
default Stream<E> stream() ; //返回一个顺序流
 default Stream<E> parallelStream() ; // 返回一个并行流

代码演示

	    // Collection接口中扩展了获取流的方法,因此集合可直接获取流.
        List<String> list = new ArrayList<>();
        Set<Integer> set = new HashSet<>();
        //获取串行流
        Stream<String> stream = list.stream();
        //获取并行刘
        Stream<Integer> parallelStream = set.parallelStream();
  • 2.数组获取流
    Java8 中的 Arrays 的静态方法 stream() 可以获取数组流:
static <T> Stream<T> stream(T[] array);//返回一个流

代码演示

	    //  对于数组,Arrays工具类中提供了获取流的方法
        Double[] doubles = new Double[]{};
        Stream<Double> doubleStream = Arrays.stream(doubles);
        
        String[] strings = new String[]{};
        Stream<String> stringStream = Arrays.stream(strings);
  • 3.Stream类的静态方法获取流

代码演示

        //3.通过Stream类的静态方法获取流
        //Stream.of方法 该方法可接受任意数量的参数
        //public static<T> Stream<T> of(T... values)
        Stream<String> stringStream = Stream.of("a", "b", "c");
        Stream<Integer> integerStream = Stream.of(1, 2, 3, 4);

        //Stream.iterate方法(迭代,获取的无限流)
        //public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f)
        //第一个参数为起始值,第二个参数为UnaryOperator<T>,函数形接口.
        Stream<Integer> iterate = Stream.iterate(0, x -> x + 2);


        //Stream.generate方法(生成,获取的无限流)
        //public static<T> Stream<T> generate(Supplier<T> s)
        Stream<Double> generate = Stream.generate(() -> Math.random());

stream的中间操作

  • 多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,否则中间操作不会执行任何的处理!而在终止操作时一次性全部处理,称为“惰性求值”。

为了方便演示,再此创建实体类(使用lombok简化代码),供后面调用:

package com.fx.demo.straem;
import lombok.*;
import java.io.Serializable;

@Data //生成get、set、toString方法
@EqualsAndHashCode  //重写equals和HashCode方法
@NoArgsConstructor //无参构造
@AllArgsConstructor //全参构造
public class Student implements Serializable {

    private String sno; //学号
    private String name; //姓名
    private Integer age; //年龄
    private Status status; //状态

    @Getter
    @ToString
    public enum Status {
        IN_SCHOOL, //在校生
        GRADUATION, //毕业生
        DROP_OUT;  //退学生
    }
}

创建一个学生集合,作为全局变量,供测试方法调用:

	private List<Student> students = Arrays.asList(
            new Student("114", "ZhangSan", 14, Student.Status.IN_SCHOOL),
            new Student("114", "ZhangSan", 14, Student.Status.IN_SCHOOL),
            new Student("114", "LiSi", 18, Student.Status.DROP_OUT),
            new Student("115", "WangWu", 20, Student.Status.GRADUATION)
    );

1. 筛选与切片

筛选与切片
代码演示

   /**
     * 测试 Stream 的中间操作,筛选与切片
     * 筛选 filter(),去重 distinct(),截断 limit(long maxSize),跳过 skip(long n)
     */
    @Test
    public void test1() {
        //筛选 filter(),筛选出年龄小于20岁的学生
        students.stream()  					    //创建流
                .filter(s -> s.getAge() < 20)  //中间操作
                .forEach(System.out::println); //种植操作
       System.out.println("-------------------------");
		 /* 运行结果:
            Student(sno=114, name=ZhangSan, age=14, status=Student.Status.IN_SCHOOL)
			Student(sno=114, name=ZhangSan, age=14, status=Student.Status.IN_SCHOOL)
			Student(sno=114, name=LiSi, age=18, status=Student.Status.DROP_OUT)
			-------------------------
         */
      
        
        //去重 distinct()  注意:去重方式为hashcode和equals
        students.stream()
                .distinct()
                .forEach(System.out::println);
        System.out.println("-------------------------");
        /* 运行结果:
            Student(sno=114, name=ZhangSan, age=14, status=Student.Status.IN_SCHOOL)
			Student(sno=114, name=LiSi, age=18, status=Student.Status.DROP_OUT)
			Student(sno=115, name=WangWu, age=20, status=Student.Status.GRADUATION)
			-------------------------
         */
         
        //截断 limit(long maxSize),获取前 maxSize 个元素
        students.stream()
                .limit(3)
                .forEach(System.out::println);
        System.out.println("-------------------------");
        /* 运行结果:
            Student(sno=114, name=ZhangSan, age=14, status=Student.Status.IN_SCHOOL)
			Student(sno=114, name=ZhangSan, age=14, status=Student.Status.IN_SCHOOL)
			Student(sno=114, name=LiSi, age=18, status=Student.Status.DROP_OUT)
			-------------------------
         */

        //跳过 skip(long n),跳过前 n 个元素
        students.stream()
                .skip(2)
                .forEach(System.out::println);
          /* 运行结果:
            Student(sno=114, name=LiSi, age=18, status=Student.Status.DROP_OUT)
			Student(sno=115, name=WangWu, age=20, status=Student.Status.GRADUATION)
         */
    }

2. 映射

映射
代码演示

   /**
     * 测试映射
     * map-接收Lambda,将元素转换成其他形式或提取信息。接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
     * flatMap-接收一个函数作为参数,将流中的每个值都转换成另一个流,然后把所有流连接成一个流
     */
    @Test
    public void test2() {
        //map
        //<R> Stream<R> map(Function<? super T, ? extends R> mapper);
        students.stream()
                .map(Student::getName)
                .forEach(System.out::println);
        System.out.println("-------------------------");
        /* 运行结果:
	        ZhangSan
			ZhangSan
			LiSi
			WangWu
	        -------------------------
        */

        //flatMap
        //<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
        List<String> list = Arrays.asList("aa", "bb", "cc");
        list.stream()
            .flatMap(s -> toChar(s))
            .forEach(System.out::println);
        /* 运行结果
            a
			a
			b
			b
			c
			c
        */

    }
	/**
     * 将字符串转换为字节集合,并以Stream流的方式返回
     * @param s
     * @return
     */
    private Stream<Character> toChar(String s) {
        List<Character> list = new ArrayList<>();
        char[] chars = s.toCharArray();
        for (int i = 0; i < chars.length; i++) {
            list.add(chars[i]);
        }
        return list.stream();
    }

3.排序

排序
代码演示

@Test
    public void test3() {
        //自然排序
        List<Integer> list = Arrays.asList(16, 62, 50);
        list.stream()
                .sorted()
                .forEach(System.out::println);
        /*运行结果
            9
            16
            50
            62
         */

        //自定义排序
        students.stream()
                .sorted((s1,s2)->{
                    if(s1.getName().compareTo(s2.getName())!=0){
                        return s1.getName().compareTo(s2.getName());
                    }
                    return Integer.compare(s1.getAge(),s2.getAge()); })
                .forEach(System.out::println);
        /*运行结果
            Student(sno=114, name=LiSi, age=18, status=Student.Status.DROP_OUT)
            Student(sno=115, name=WangWu, age=20, status=Student.Status.GRADUATION)
            Student(sno=114, name=ZhangSan, age=14, status=Student.Status.IN_SCHOOL)
            Student(sno=114, name=ZhangSan, age=14, status=Student.Status.IN_SCHOOL)
         */
    }

Stream 的终止操作

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

1.查找与匹配

查找与匹配查找与匹配2
代码演示

    @Test
    public void test4() {
        //allMatch(Predicate<? super T> predicate)  流中元素是否全部满足条件
        boolean allMatch = students.stream()
                .allMatch(student -> student.getAge() < 30);
        System.out.println(allMatch);
        System.out.println("-------------------------");
        //运行结果: true

        //anyMatch(Predicate<? super T> predicate) 流中是否有满足条件的元素
        boolean anyMatch = students.stream()
                .anyMatch(student -> student.getAge() == 18);
        System.out.println(anyMatch);
        System.out.println("-------------------------");
        //运行结果: true

        //noneMatch(Predicate<? super T> predicate) 流中是否全部不满足条件
        boolean noneMatch = students.stream()
                .noneMatch(student -> student.getStatus().equals(Student.Status.DROP_OUT));
        System.out.println(noneMatch);
        System.out.println("-------------------------");
        //运行结果: false

        //long count() 流中元素的个数 
        long count = students.stream()
                .filter(student -> student.getStatus().equals(Student.Status.GRADUATION))
                .count();
        System.out.println(count);
        System.out.println("-------------------------");
        //运行结果: 1

        //Optional<T> max(Comparator<? super T> comparator) 取出流中最大值
        students.stream()
                .map(Student::getAge)
                .max(Integer::compareTo);
        System.out.println(max.get());
        System.out.println("-------------------------");
		//运行结果: 20
		
        //Optional<T> min(Comparator<? super T> comparator) 取出流中最小值
        Optional<Student> min = students.stream()
                .min((s1, s2) -> {
                    if (s1.getName().compareTo(s2.getName())!=0) {
                        return s1.getName().compareTo(s2.getName());
                    }
                        return s1.getAge().compareTo(s2.getAge());
                });
        System.out.println(min.get());
        System.out.println("-------------------------");
       //运行结果: Student(sno=114, name=LiSi, age=18, status=Student.Status.DROP_OUT)
       
        //findFirst 取出第一个元素
        Optional<Student> first = students.stream()
                .findFirst();
        System.out.println(first.get());
        System.out.println("-------------------------");
		//运行结果: Student(sno=114, name=ZhangSan, age=14, status=Student.Status.IN_SCHOOL)
		
        //findAny() 取出任意一个元素(需要使用并行流)
        for (int i = 0 ; i<5;i++){
            Optional<Student> any = students.parallelStream().findAny();
            System.out.println(any.get());
        }
        /*运行结果
        Student(sno=114, name=LiSi, age=18, status=Student.Status.DROP_OUT)
		Student(sno=114, name=ZhangSan, age=14, status=Student.Status.IN_SCHOOL)
		Student(sno=114, name=LiSi, age=18, status=Student.Status.DROP_OUT)
		Student(sno=114, name=LiSi, age=18, status=Student.Status.DROP_OUT)
		Student(sno=114, name=LiSi, age=18, status=Student.Status.DROP_OUT)
        */
    }

2.归约

规约
代码演示

    @Test
    public void test5() {
        //reduce 按照某种规则,规约计算出结果
        //如:取出年龄最小的学生
        Optional<Integer> min = students.stream()
                .map(Student::getAge)
                .reduce(Integer::min);
        System.out.println(min.get());
        //运行结果 14
    }

3.收集

收集

Collector 接口中方法的实现决定了如何对流执行收集操作(如收集到 List、Set、Map)。
但是 Collectors 实用类提供了很多静态方法,可以方便地创建常见收集器实例,具体方法与实例如下表:

Collectors静态方法
Collectors静态方法2
代码演示

    @Test
    public void test6() {
        //1.将流转为List(也可转化为Set、Collection)
        Integer[] integers = new Integer[]{1,6,8,45,14};
        List<Integer> collect = Arrays.stream(integers).collect(Collectors.toList());
        System.out.println(collect);
        System.out.println("-------------------------");
		//运行结果 [1, 6, 8, 45, 14]
		
        //2.计算流中个数
        Long num = students.stream().collect(Collectors.counting());
        System.out.println(num);
        System.out.println("-------------------------");
      	//运行结果 4
      
        //求和
        Integer sum = students.stream()
                .collect(Collectors.summingInt(Student::getAge));
        System.out.println(sum);
        System.out.println("-------------------------");
        //运行结果 66

        //平均值
        Double avg = students.stream().collect(Collectors.averagingInt(Student::getAge));
        System.out.println(avg);
        System.out.println("-------------------------");
        //运行结果 16.5

        //连接
        List<String> list1 = Arrays.asList("a","b","c");
        String s = list1.stream().collect(Collectors.joining());
        System.out.println(s);
        System.out.println("-------------------------");
        //运行结果 abc

        //分组
        Map<Student.Status, List<Student>> map = students.stream()
                .collect(Collectors.groupingBy(Student::getStatus));
            //遍历map
        Set<Student.Status> keySet = map.keySet();
        for (Student.Status status : keySet) {
            System.out.print(status.toString()+":");
            List<Student> students = map.get(status);
            System.out.println(students);
        }
        System.out.println("-------------------------");
        /* 运行结果
         Student.Status.IN_SCHOOL:[Student(sno=114, name=ZhangSan, age=14, status=Student.Status.IN_SCHOOL), Student(sno=114, name=ZhangSan, age=14, status=Student.Status.IN_SCHOOL)]
	     Student.Status.DROP_OUT:[Student(sno=114, name=LiSi, age=18, status=Student.Status.DROP_OUT)]
         Student.Status.GRADUATION:[Student(sno=115, name=WangWu, age=20, status=Student.Status.GRADUATION)]
        */

        //分区(根据boolean值)
        Map<Boolean, List<Student>> booleanMap = students.stream()
                .collect(Collectors.partitioningBy(student -> student.getAge() > 18));
        System.out.println(booleanMap);
        /* 运行结果
        {false=[Student(sno=114, name=ZhangSan, age=14, status=Student.Status.IN_SCHOOL), Student(sno=114, name=ZhangSan, age=14, status=Student.Status.IN_SCHOOL), Student(sno=114, name=LiSi, age=18, status=Student.Status.DROP_OUT)], true=[Student(sno=115, name=WangWu, age=20, status=Student.Status.GRADUATION)]}
        */
    }
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值