Java中Stream流的用法

流是从支持数据处理操作的源生成的元素序列,源可以是数组、文件、集合、函数。流不是集合元素,它不是数据结构并不保存数据,它的主要目的在于计算

一、生成流的方式

1.通过集合

List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5);
Stream<Integer> stream = integerList.stream();

2.通过数组产生

int[] intArr = new int[]{1, 2, 3, 4, 5};
IntStream stream = Arrays.stream(intArr);

3.通过值生成

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

 通过Stream的of方法生成流,通过Stream的empty方法可以生成一个空流

4.通过文件生成

Stream<String> lines = Files.lines(Paths.get("data.txt"), Charset.defaultCharset());

 通过Files.line方法得到一个流,并且得到的每个流是给定文件中的一行

5.通过函数生成

提供了iterate和generate两个静态方法从函数中生成流

5.1 iterate
Stream<Integer> stream = Stream.iterate(0, n -> n + 2).limit(5);

 iterate方法接受两个参数,第一个为初始化值,第二个为进行的函数操作,因为iterator生成的流为无限流,通过limit方法对流进行了截断,只生成5个偶数

5.2 generate
Stream<Double> stream = Stream.generate(Math::random).limit(5);

generate方法接受一个参数,方法参数类型为Supplier,由它为流提供值。generate生成的流也是无限流,因此通过limit对流进行了截断。

二、流的操作

1.中间操作

1.1 Filter(过滤)
List<Integer> integerList = Arrays.asList(1, 1, 2, 3, 4, 5);
Stream<Integer> stream = integerList.stream().filter(i -> i > 3);

 保留数值大于3的元素

1.2 Map(转换)

 List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
        List<Integer> collect = numbers.stream().map(n ->
        {
            n = n * 2;
            return n;
        }).collect(Collectors.toList());

 通过map方法对数字列表中的每个元素进行乘以 2 

1.3 flatMap流转换

将一个流中的每个值都转换为另一个流。

List<String> wordList = Arrays.asList("Hello", "World");
List<String> strList = wordList.stream()
    .map(w -> w.split(""))
    .flatMap(Arrays::stream)
    .distinct()
    .collect(Collectors.toList());

 map(w -> w.split(“”))的返回值为Stream<String[]>,我们想获取Stream,可以通过flatMap方法完成Stream ->Stream的转换

1.3 Sorted(排序)

sorted()方法可对流进行排序。它可以接受一个Comparator参数,也可以使用自然排序Ordering.natural()。默认排序是按升序排序。

// 简单排序
List<Integer> list = Arrays.asList(1, 2, 3, 7, 5, 6, 6, 4);
    List<Integer> res = list.stream().sorted().collect(Collectors.toList());
    System.out.println(res);
// 指定字段正序排序
List<pre> res=list.stream().sorted(Comparator.comparing(pre::getAge)).collect(Collectors.toList());
     System.out.println(res);    
// 指定字段倒序排序
List<pre> sortReverseRlt=list.stream().sorted(Comparator.comparing(pre::getAge).reversed()).collect(Collectors.toList());
    System.out.println(res);
1.4 Distinct(去重)
List<Integer> integerList = Arrays.asList(1, 1, 2, 3, 4, 5);
Stream<Integer> stream = integerList.stream().distinct();

 通过distinct方法快速去除重复的元素

1.5 Limit(限制)
List<Integer> integerList = Arrays.asList(1, 1, 2, 3, 4, 5); 
Stream<Integer> stream = integerList.stream().limit(3);
// 1,1,2

 通过limit方法指定返回流的个数,结果打印为 1,1,2 limit的参数值必须>=0,否则将会抛出异常

1.6 Skip(跳过)
List<Integer> integerList = Arrays.asList(1, 1, 2, 3, 4, 5);
Stream<Integer> stream = integerList.stream().skip(2);
// 2,3,4,5

 通过skip方法跳过流中的元素,上述例子跳过前两个元素,所以打印结果为2,3,4,5,skip的参数值必须>=0,否则将会抛出异常

1.7 Peek(展示)

peek()方法可以用于在Stream流中获取元素同时执行一些操作,如打印、调试、观察等。通常会与其他的方法联合使用。

List<String> names = Arrays.asList("Alex", "Brian", "Charles", "David");
List<String> filteredNames = names.stream()
    .peek(System.out::println)
    .filter(name -> name.startsWith("C"))
    .peek(name -> System.out.println("Filtered value: " + name))
    .collect(Collectors.toList());
System.out.println("-----------------------------------------------------------------");
System.out.println(filteredNames);

2.终止操作

2.1 forEach(循环)

forEach()方法可将给定的方法应用于流中的每个元素。该方法是一种消费流的方式,不会返回值

List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5);
integerList.stream().forEach(System.out::println);
2.2 Collect(收集)

collect()方法可以将流中的元素收集到一个集合中。一般与其他方法配合使用

List<String> strings = menu.stream().map(Dish::getName).collect(Collectors.toList());
Set<String> sets = menu.stream().map(Dish::getName).collect(Collectors.toSet());

 通过joining拼接流中的元素

String result = menu.stream().map(Dish::getName).collect(Collectors.joining(", "));

 进阶通过groupingBy进行分组

//通过性别对学生进行分组
        Map<String, List<Student>> collect = students.stream().collect(Collectors.groupingBy(Student::getSex));
结果  {
    F=[Student{id=1, age=21, name='王五', sex='F', isPass=true}, Student{id=1, age=20, name='赵六', sex='F', isPass=false}],
    M=[Student{id=1, age=19, name='张三', sex='M', isPass=true}, Student{id=1, age=18, name='李四', sex='M', isPass=false}]
}

复杂分组

//现根据是否通过考试对学生分组,在根据性别分组     
Map<String, Map<Boolean, List<Student>>> collect1 = students.stream().collect(Collectors.groupingBy(Student::getSex, Collectors.groupingBy(Student::getPass)));
结果: {
    F={
        false=[Student{id=1, age=20, name='赵六', sex='F', isPass=false}],
        true=[Student{id=1, age=21, name='王五', sex='F', isPass=true}]
    }, 
    M={
        false=[Student{id=1, age=18, name='李四', sex='M', isPass=false}], 
        true=[Student{id=1, age=19, name='张三', sex='M', isPass=true}]}
}

 多级分组变形

//根据年龄进行分组,获取并汇总人数
        Map<Integer, Long> collect2 = students.stream().collect(Collectors.groupingBy(Student::getAge, Collectors.counting()));
        System.out.println(collect2);
​
结果:{18=1, 19=1, 20=1, 21=1}
//要根据年龄与是否及格进行分组,并获取每组中年龄的学生
        Map<Integer, Map<Boolean, Student>> collect3 = students.stream().collect(Collectors.groupingBy(Student::getAge, Collectors.groupingBy(Student::getPass,
                Collectors.collectingAndThen(Collectors.maxBy(Comparator.comparing(Student::getAge)), Optional::get))));
        System.out.println(collect3.toString());
结果:{
    18={false=Student{id=1, age=18, name='李四', sex='M', isPass=false}},
    19={true=Student{id=1, age=19, name='张三', sex='M', isPass=true}},
    20={false=Student{id=1, age=20, name='赵六', sex='F', isPass=false}}, 
    21={true=Student{id=1, age=21, name='王五', sex='F', isPass=true}}}

 进阶通过partitioningBy进行分区:

分区是特殊的分组,它分类依据是true和false,所以返回的结果最多可以分为两组

Map<Boolean, List<Dish>> result = menu.stream().collect(Collectors.partitioningBy(Dish::isVegetarian));

 等同于

Map<Boolean, List<Dish>> result = menu.stream().collect(Collectors.groupingBy(Dish::isVegetarian));

这个例子可能并不能看出分区和分类的区别,甚至觉得分区根本没有必要,换个明显一点的例子: 

List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5);
Map<Boolean, List<Integer>> result = integerList.stream().collect(Collectors.partitioningBy(i -> i < 3));

 返回值的键仍然是布尔类型,但是它的分类是根据范围进行分类的,分区比较适合处理根据范围进行分类。

2.3 Count(计数)

count()方法可以返回流中的元素数

List<String> names = Arrays.asList("Alex", "Brian", "Charles", "David");
long count = names.stream().count();
System.out.println(count);
2.4 Reduce(聚合)

reduce()方法可以将流元素聚合为单个结果。它接受一个BinaryOperator参数作为累加器

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> sum = numbers.stream().reduce((a, b) -> a + b);
System.out.println(sum);
//Optuibal[15]
//最终得到的结果 15 被包装成 Optional 类型的对象并打印输出到控制台。

 一行就可以完成,还可以使用方法引用简写成:

int sum = integerList.stream().reduce(0, Integer::sum);
2.5 AnyMatch(任意匹配)

anyMatch()方法如果至少有一个元素与给定的谓词匹配,则返回true

List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5);
if (integerList.stream().anyMatch(i -> i > 3)) {
    System.out.println("存在大于3的值");
}
2.6 AllMatch(全部匹配)

allMatch()方法如果所有元素都与给定谓词匹配,则返回true

List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5);
if (integerList.stream().allMatch(i -> i > 3)) {
    System.out.println("值都大于3");
}
2.7 NoneMatch(无匹配)

noneMatch()方法,如果没有任何元素与给定谓词匹配,则返回true

List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5);
if (integerList.stream().noneMatch(i -> i > 3)) {
    System.out.println("值都小于3");
}
2.8 findFirst(查找第一个)
List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> result = integerList.stream().filter(i -> i > 3).findFirst();
 2.9 findAny(随机查找一个)
List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> result = integerList.stream().filter(i -> i > 3).findAny();
 2.10 max(获取最大值)
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
    Integer max = list.stream().max(Integer::compareTo).get();
    System.out.println(max);
 2.11 min(获取最小值)
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
    Integer min = list.stream().min(Integer::compareTo).get();
    System.out.println(min);
2.12 计算
ArrayList<Student> students = new ArrayList<>();
        students.add(new Student(1,19,"张三","M",true));
        students.add(new Student(1,18,"李四","M",false));
        students.add(new Student(1,21,"王五","F",true));
        students.add(new Student(1,20,"赵六","F",false));

        //通过counting()统计集合总数  方法一
        Long collect = students.stream().collect(Collectors.counting());
        System.out.println(collect);
        //结果 4

        //通过count()统计集合总数  方法二
        long count = students.stream().count();
        System.out.println(count);
        //结果 4

        //通过maxBy求最大值
        Optional<Student> collect1 = students.stream().collect(Collectors.maxBy(Comparator.comparing(Student::getAge)));
        if(collect1.isPresent()){
            System.out.println(collect1);
        }
        //结果 Optional[Student{id=1, age=21, name='王五', sex='F', isPass=true}]

        //通过max求最大值
        Optional<Student> max = students.stream().max(Comparator.comparing(Student::getAge));
        if(max.isPresent()){
            System.out.println(max);
        }
        //结果  Optional[Student{id=1, age=21, name='王五', sex='F', isPass=true}]

        //通过minBy求最小值
        Optional<Student> collect2 = students.stream().collect(Collectors.minBy(Comparator.comparing(Student::getAge)));
        if(collect2.isPresent()){
            System.out.println(collect2);
        }
        //结果  Optional[Student{id=1, age=18, name='李四', sex='M', isPass=false}]

        //通过min求最小值
        Optional<Student> min = students.stream().min(Comparator.comparing(Student::getAge));
        if(min.isPresent()){
            System.out.println(min);
        }
        //结果  Optional[Student{id=1, age=18, name='李四', sex='M', isPass=false}]

        //通过summingInt()进行数据汇总
        Integer collect3 = students.stream().collect(Collectors.summingInt(Student::getAge));
        System.out.println(collect3);
        //结果 78

        //通过averagingInt()进行平均值获取
        Double collect4 = students.stream().collect(Collectors.averagingInt(Student::getAge));
        System.out.println(collect4);
        //结果 19.5

        //通过joining()进行数据拼接
        String collect5 = students.stream().map(Student::getName).collect(Collectors.joining());
        System.out.println(collect5);
        //结果 张三李四王五赵六
        
        //复杂结果的返回
        IntSummaryStatistics collect6 = students.stream().collect(Collectors.summarizingInt(Student::getAge));
        double average = collect6.getAverage();
        long sum = collect6.getSum();
        long count1 = collect6.getCount();
        int max1 = collect6.getMax();
        int min1 = collect6.getMin();
2.13 获取元素中最大值最小值
 List<Integer> integers = Arrays.asList(1, 2, 3, 4, 4, 5, 5, 6, 7, 8, 2, 2, 2, 2);
 
        /**
         * 获取集合中的最大值
         */
        //方法一
        Optional<Integer> max1 = integers.stream().reduce(Integer::max);
        if(max1.isPresent()){
            System.out.println(max1);
        }
        //方法二
        Optional<Integer> max2 = integers.stream().max(Integer::compareTo);
        if(max2.isPresent()){
            System.out.println(max2);
        }

        /**
         * 获取集合中的最小值
         */
        //方法一 
        Optional<Integer> min1 = integers.stream().reduce(Integer::min);
        if(min1.isPresent()){
            System.out.println(min1);
        }

        //方法二
        Optional<Integer> min2 = integers.stream().min(Integer::compareTo);
        if(min2.isPresent()){
            System.out.println(min2);
        }

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值