Java8 Stream流详解

概念和特点

Java中的Stream是用于处理集合数据的功能强大且灵活的API。Stream 是 Java 8 引入的一个新特性,它允许以函数式编程的方式来处理集合数据。通过使用 Stream可以写出更简洁、意图明确的代码,并且可以利用多核处理器的优势来并行处理数据,提高程序性能。

在这里插入图片描述

基本流程

  1. 首先需要将集合转换为 Stream, 可以从很多种数据源中创建Stream,例如List、Set或者任何其他实现了Iterable接口的类。创建方式很简单,使用stream()或parallelStream()方法即可。
  2. 然后通过中间操作对 Stream 进行一系列的处理。常用的Stream操作包括:过滤、映射、排序、去重、计数、归约等等。
  3. 最终通过终止操作得到处理结果。

常见操作

常用的Stream操作包括:过滤、映射、排序、去重、计数、归约等等。

在这里插入图片描述

过滤(filter)

根据条件筛选出符合条件的元素,过滤方法filter用于对Stream中的元素进行筛选,只保留符合指定条件的元素。其函数式接口为Predicate,其方法为boolean test(T t),接受一个T类型的对象,并返回一个boolean类型值。当该方法返回true时,说明该元素符合条件,将被保留在Stream中.

映射(map)

将 Stream 中的每个元素转换成另一种形式。映射方法map用于将Stream中的元素根据指定规则进行转换。其函数式接口为Function<T, R>,其方法为R apply(T t),接受一个T类型的对象,并返回一个R类型的对象。实质上,map方法就是对Stream中各元素做一个同类型的映射

收集(collect)

将 Stream 中的元素收集到如 List、Set 或 Map 等集合中。

归约(reduce)

将 Stream 中的元素组合起来生成一个值。

扁平映射(flatMap)

将 Stream 中的每个元素转换为另一个 Stream,然后合并为一个 Stream。

java案例详解

package cn.hyperchain.liststream;

import org.junit.jupiter.api.Test;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * @author zhu
 * @Date 2022/1/7 11:14 AM
 * JAVA8 新特性:stream流操作集合
 * 案例:查询集合中age<20的学生,并且根据年龄进行排序,得到学生的姓名,生成新的集合
 */
//@SpringBootTest
public class ListStreamTest {
    private static List<Student> students = null;

    static {
        students = new ArrayList<>();
        students.add(new Student(1, "张三", "M", 19));
        students.add(new Student(2, "李四", "M", 18));
        students.add(new Student(3, "王武", "F", 21));
        students.add(new Student(4, "赵六", "F", 20));

        students.add(new Student(1, "张三", "M", 19));
        students.add(new Student(2, "李四", "M", 18));
        students.add(new Student(3, "王武", "F", 21));
        students.add(new Student(4, "赵六", "F", 20));
    }

    /**
     * 0. List stream流基本操作
     */
    @Test
    public void testStream() {
        // 案例一:
        List<String> res = students.stream()
                .filter(student -> student.getAge() < 20)       // 集合中age<20
                .distinct()                                     // 对象去重
                .sorted(Comparator.comparing(Student::getAge))  // 根据年龄进行排序
                .map(Student::getName)                          // 得到学生的姓名[可以有多个字段,但是需要封装]
                .collect(Collectors.toList());                  // 生成新的集合
        System.out.println("res = " + res);

        // 案例二:
        List<Integer> list = Arrays.asList(1, 1, 3, 43, 12, 43, 32, 1, 42, 3, 32, 43);
        List<Integer> result = list.stream()    // 1, 1, 3, 43, 12, 43, 32, 1, 42, 3, 32, 43
                .distinct()             // 去重           1,3,43,12,32,42
                .limit(5)               // 集合大小为5     1,3,43,12,32
                .skip(2)                // 跳过前2个元素    43,12,32
                .collect(Collectors.toList());
        System.out.println("result = " + result);
    }

    /**
     * 1. List stream流快速取集合元素某一个属性或多个属性,并转为List、Map、Set
     */
    @Test
    public void testMap() {
        // 1. List快速取一个字段为List
        List<Integer> ids = students.stream().map(Student::getId).collect(Collectors.toList());
        ids.forEach(System.out::println);

        // 2. List快速取多个字段组成一个Entity为List
        List<StudentDTO> dtos = students.stream()
                .map(new Function<Student, StudentDTO>() {  // 封装students的某些属性,函数式编程,Function已声明为@FunctionalInterface,此时作为参数传递,主要进行类型转换
                    @Override
                    public StudentDTO apply(Student student) {
                        return StudentDTO.builder()
                                .id(student.getId())
                                .name(student.getName())
                                .build();
                    }
                })
                .collect(Collectors.toList());
        System.out.println("dtos = " + dtos);

        // 3. List快速取Map
        Map<Integer, Student> map = students.stream().collect(Collectors.toMap(Student::getId, Function.identity())); // Function.identity() 表示直接返回对应的 DeviceExtendDto 对象作为 Value

        // 4. List快速取Set:值不可重复,List值可重复
        Set<Integer> set = students.stream().map(Student::getId).collect(Collectors.toSet());
        System.out.println("set = " + set);

        // 5. 分组为Map
//        Map<AttrTypeEnum, List<T2>> attrMap = attrs.stream().filter(t -> AttrTypeEnum.DEVICE != t.getType()).collect(Collectors.groupingBy(T2::getType));
    }

    /**
     * 2. List stream流快速判断Predicate
     */

    @Test
    public void testMatch() {
        // 写法一:testAnyMatch[判断集合任一个元素满足要求]
        boolean b1 = students.stream()
                .distinct()
                .anyMatch(new Predicate<Student>() {  // 匹配 anyMatch
                    @Override
                    public boolean test(Student student) {
                        return student.getName().equals("张三");
                    }
                });
        System.out.println("b1 = " + b1);

        // 写法二:testAnyMatch
        boolean b2 = students.stream()
                .distinct()
                .anyMatch(student -> student.getName().equals("张三"));
        System.out.println("b2 = " + b2);
    }

    @Test
    public void testFind() {
        Optional<Student> studentOptional = students.stream()
                .distinct()
//                .findAny();     // 随机获取一个元素
                .findFirst();     // 获取第一个元素
        if (studentOptional.isPresent()) {
            Student student = studentOptional.get();
            System.out.println("student = " + student);
        }
    }
}

注意事项

Stream 不会自己存储元素,也不会改变源对象。它会返回一个新的 Stream,这个新的 Stream 持有之前所有操作的结果。
Stream 的操作是延迟执行的,只有在真正需要结果的时候才会执行这些操作。

  • 22
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mr朱墨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值