Java8 Stream 常用操作

Stream是Java8中的一大亮点,支持顺序和并行聚合操作的一系列元素,为了执行计算,流operations被组合成流管道 。 流管线由源(其可以是阵列,集合,生成函数,I / O通道等)组成,零个或多个中间操作 (其将流转换成另一个流,例如filter(Predicate) )以及终端操作 (产生结果或副作用,如count()forEach(Consumer)

Stream和集合的不同点

  1. 没有存储。 流不是存储元素的数据结构; 相反,它通过计算操作的流水线传送诸如数据结构,阵列,生成器功能或I / O通道的源的元件。
  2. 功能性质。 流上的操作产生结果,但不会修改其来源。 例如,过滤从Stream获得的Stream会生成新的Stream而不需要过滤的元素,而不是从源集合中删除元素。
  3. 懒惰寻求。 许多流操作(如过滤,映射或重复删除)可以懒惰地实现,从而暴露优化的机会。 例如,“找到具有三个连续元音的第一个String ”不需要检查所有的输入字符串。 流操作分为中间( Stream生产)操作和终端(价值或副作用生成)操作。 中级操作总是懒惰。
  4. 可能无限。 虽然集合的大小有限,但流不需要。 诸如limit(n)或findFirst()之类的limit(n) findFirst()可以允许无限流上的计算在有限的时间内完成。
  5. 消耗品流的元素只能在流的一生中访问一次。 像Iterator一样 ,必须生成一个新流来重新访问源的相同元素。

 Stream流的获取

  1. Collection通过stream()parallelStream()方法;
  2. 从数组通过Arrays.stream(Object[]) ;
  3. 从流类静态工厂的方法,如Stream.of(Object[])IntStream.range(int, int)Stream.iterate(Object, UnaryOperator) ;
  4. 文件的行可以从BufferedReader.lines()获取 ;
  5. 文件路径的流可以从Files中的方法获得;
  6. 随机数流可以从Random.ints()获得;
  7. JDK中其它的数据流的方法,包括BitSet.stream()Pattern.splitAsStream(java.lang.CharSequence)JarFile.stream()
        //1.定义Collection
        List<String> list = new ArrayList<>();
        //获取一个串行流
        Stream<String> stream = list.stream();
        //获取一个并行流-底层是forkJoin实现
        Stream<String> stringStream = list.parallelStream();

        //2. 使用Arrays 中的 stream() 方法,将数组转成流
        String[] array = new String[5];
        Stream<String> stream = Arrays.stream(array);

        //3.流类静态工厂的方法

        Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6);//1 2 3 4 5 6

        Stream<Integer> stream = Stream.iterate(0, (x) -> x + 2).limit(6);// 0 2 4 6 8 10

        Stream<Double> stream = Stream.generate(Math::random).limit(2);//随机的2个数字


        //4.使用 BufferedReader.lines() 方法,从文件中将每行内容转成流
        BufferedReader reader = new BufferedReader(new FileReader("D:\\milla_stream.txt"));
        Stream<String> lineStream = reader.lines();

        //5.文件路径的流可以从Files中的方法获得
        Stream<Path> stream = Files.list(Paths.get("D:\\"));

        //6.随机数流可以从Random.ints()获得;
        IntStream ints = new Random().ints();//是Stream的子类

        //7. 其他类中的方法
        IntStream stream1 = new BitSet().stream();//是Stream的子类

        Pattern pattern = Pattern.compile(",");
        Stream<String> text = pattern.splitAsStream("mila,love");

        Stream<JarEntry> stream2 = new JarFile("D:\\milla.jar").stream();

 流的中间操作

实体类

@Data
public class StudentVO {
    private String username;
    private String city;
    private String sex;
    private int age;
    public StudentVO(String username, String city, String sex, int age) {
        this.username = username;
        this.city = city;
        this.sex = sex;
        this.age = age;
    }
    public StudentVO() {
    }
}
@Data
public class TeacherVO {

    private String username;

    private String city;
}

 创建新的流

//生程流对象
   Stream<StudentVO> stream = Stream.of(
                new StudentVO("AA", "上海", "女", 22),
                new StudentVO("BB", "南京", "男", 20),
                new StudentVO("BB", "杭州", "女", 19),
                new StudentVO("CC", "杭州", "男", 20),
                new StudentVO("DD", "南京", "女", 22),
                new StudentVO("DD", "上海", "女", 23),
                new StudentVO("DD", "北京", "男", 22),
                new StudentVO("EE", "杭州", "男", 23),
                new StudentVO("FF", "上海", "女", 24));

 

映射-转换

  • map: - 接收函数中的参数,根据业务将它变成一个新的元素
  • flatMap:- 接收函数中的参数,将每个值都进行业务替换,形成一个新的流
        //获取所有学生的姓名-集合
        List<String> usernameList = list.stream().map(StudentVO::getUsername).collect(Collectors.toList());
        List<String> usernameList2 = list.stream().collect(Collectors.mapping(studentVO ->
             studentVO.getUsername(), Collectors.toList()));
        System.out.println("学生姓名集合:" + usernameList);
        System.out.println("学生姓名集合:" + usernameList2);


        //数据转换
        List<TeacherVO> collect1 = list.stream().flatMap((e) -> {
            TeacherVO teacher = new TeacherVO();
            teacher.setUsername(e.getUsername());
            teacher.setCity(e.getCity());
            return Stream.of(teacher);
        }).collect(Collectors.toList());
        System.out.println(collect1);


排序

  • sorted()  - 返回由此流的元素组成的流,根据自然顺序排序
  • sorted(Comparator<? super T> comparator) -  返回由该流的元素组成的流,根据提供的 Comparator进行排序。
 //按照年龄和姓名排序-正序
        List<StudentVO> sortedList = list.stream().sorted(
            Comparator.comparingInt(StudentVO::getAge)
            .thenComparing(StudentVO::getUsername)
            .reversed()).collect(Collectors.toList());
        System.out.println("按照年龄排序:" + sortedList);

筛选 - 截取

  • filter(Predicate<? super T> predicate); - 过滤,指定过滤条件
  • limit(n) - 获取n个元素
  • skip(n) - 丢弃流的第一个 n元素后,返回由该流的 n元素组成的流,和 limit(n) 协作可实现分页
  • distinct - 去除重复数据(根据equals() 和 hashCode()方法)
//地址在杭州的学生数量
Stream<StudentVO> voStream = list.stream().filter(stu -> stu.getCity().equals("杭州")).distinct().limit(5).skip(2);

 消费

  • peek(Consumer<? super T> action)  - 得到每个元素并对其进行操作,与map的区别不需要返回操作的元素,与forEch的区别是该方法返回流对象能继续流式操作
//中间操作不执行,只有终端操作的时候才会执行打印
        list.stream().peek(stu -> {
            System.out.println("学生对象:  " + stu);
        }).count();

 流的终止操作

        allMatch  -   接收一个 Predicate 函数,当流中每个元素都符合该断言时才返回true,否则返回false
        noneMatch  -   接收一个 Predicate 函数,当流中每个元素都不符合该断言时才返回true,否则返回false
        anyMatch  -   接收一个 Predicate 函数,只要流中有一个元素满足该断言则返回true,否则返回false
        findFirst  -   返回流中第一个元素
        findAny  -   返回流中的任意元素
        count  -   返回流中元素的总个数
        max  -   返回流中元素最大值
        min  -   返回流中元素最小值

JDK中给出的Collectors的常用操作

    //获取用户的名称组成中集合
   List<String> list = people.stream().map(Person::getName).collect(Collectors.toList());

   //将名称变成set返回-有序
   Set<String> set = people.stream().map(Person::getName).collect(Collectors.toCollection(TreeSet::new));

   //使用逗号连接符连接
   String joined = things.stream()
                         .map(Object::toString)
                         .collect(Collectors.joining(", "));

   //计算元算的工资总和
   int total = employees.stream()
                        .collect(Collectors.summingInt(Employee::getSalary)));

   //根据部门分组
   Map<Department, List<Employee>> byDept
       = employees.stream()
                  .collect(Collectors.groupingBy(Employee::getDepartment));

   //根据部门分组并计算各个部分的工资总和
   Map<Department, Integer> totalByDept
       = employees.stream()
                  .collect(Collectors.groupingBy(Employee::getDepartment,
                                                 Collectors.summingInt(Employee::getSalary)));

   //根据条件-满足条件的分组
   Map<Boolean, List<Student>> passingFailing =
       students.stream()
               .collect(Collectors.partitioningBy(s -> s.getGrade() >= PASS_THRESHOLD));

 

 常用获取对象集合操作

       Stream<StudentVO> stream = Stream.of(
                new StudentVO("AA", "上海", "女", 22),
                new StudentVO("BB", "南京", "男", 20),
                new StudentVO("BB", "杭州", "女", 19),
                new StudentVO("CC", "杭州", "男", 20),
                new StudentVO("DD", "南京", "女", 22),
                new StudentVO("DD", "上海", "女", 23),
                new StudentVO("DD", "北京", "男", 22),
                new StudentVO("EE", "杭州", "男", 23),
                new StudentVO("FF", "上海", "女", 24));
        //将学生对象变成集合
        List<StudentVO> list = stream.collect(Collectors.toList());
        System.out.println("学生集合: " + list);
        //获取所有学生的姓名-集合
        List<String> usernameList = list.stream().map(StudentVO::getUsername).collect(Collectors.toList());
        List<String> usernameList2 = list.stream().collect(Collectors.mapping(studentVO -> studentVO.getUsername(), Collectors.toList()));
        System.out.println("学生姓名集合:" + usernameList);
        System.out.println("学生姓名集合:" + usernameList2);
        //合并学生的姓名-连接程字符串
        String usernameJoin = list.stream().map(StudentVO::getUsername).collect(Collectors.joining("-"));
        System.out.println("学生姓名连接: " + usernameJoin);
        //地址在杭州的学生数量
        Stream<StudentVO> voStream = list.stream().filter(stu -> stu.getCity().equals("杭州")).distinct().limit(5).skip(2);


        long countHz = list.stream().filter(stu -> stu.getCity().equals("杭州")).count();
        System.out.println("杭州学生的个数:" + countHz);
        //按照所在城市分组
        Map<String, List<StudentVO>> groupByList = list.stream().collect(Collectors.groupingBy(studentVO -> studentVO.getCity()));
        System.out.println("按照城市分组:" + groupByList);
        //按照年龄和姓名排序-正序
        List<StudentVO> sortedList = list.stream().sorted(Comparator.comparingInt(StudentVO::getAge).thenComparing(StudentVO::getUsername).reversed()).collect(Collectors.toList());
        System.out.println("按照年龄排序:" + sortedList);
        //学生姓名作为key转变成map->如果有有重复的key,需要做个取舍-否则会报错
        Map<String, StudentVO> usernameKey = list.stream().collect(Collectors.toMap(studentVO -> studentVO.getUsername(), studentVO -> studentVO, (one, two) -> {
            //可以根据业务保留第一个元素或者是第二个元素
            return one;
        }));
        Map<String, String> usernameKey2 = list.stream().collect(Collectors.mapping(stu -> stu.getUsername(), Collectors.toMap(stu -> stu, stu -> stu, (one, two) -> one)));
        System.out.println("将学生姓名作为key: " + usernameKey);
        System.out.println("将学生姓名作为key: " + usernameKey2);
        //根据城市分组,然后再按照学生名变成map-所有变成map的操作都需要考虑重复元素的问题
        Map<String, Map<String, StudentVO>> collect = list.stream().collect(Collectors.groupingBy(stu -> stu.getCity(), Collectors.toMap(stu -> stu.getUsername(), studentVO -> studentVO)));
        System.out.println(collect);

        //数据转换
        List<TeacherVO> collect1 = list.stream().flatMap((e) -> {
            TeacherVO teacher = new TeacherVO();
            teacher.setUsername(e.getUsername());
            teacher.setCity(e.getCity());
            return Stream.of(teacher);
        }).collect(Collectors.toList());
        System.out.println(collect1);

        StudentVO studentVO = list.parallelStream().findAny().get();
        System.out.println(studentVO);


        //中间操作不执行,只有终端操作的时候才会执行打印
        list.stream().peek(stu -> {
            System.out.println("学生对象:  " + stu);
        }).count();

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章