Skip to content

StreamAPI


基本介绍

StreamAPI 说明


为什么要 StreamAPI

总结

(1)Stream 关注的是对数据的运算,与 CPU 打交道

(2)集合关注的是数据的存储,与内存打交道

什么是 Stream

总结

Stream 的作用就是对容器(数组 / 集合)计算

Stream 操作的三个步骤

⚠️ 注意点

(1)只有终止操作,中间操作才会生效(延迟执行)

(2)一旦终止操作后,Stream 流关闭,不可以再使用(会抛异常),如需再次使用,需要重新创建 Stream 流

Stream 实例化

通过集合

创建方法:集合对象 . stream()/ paralleStream()

流分类

(1)顺序流:stream()

(2)并行流:paralleStream()

java
@Test
public void test1(){
    List<Employee> employees = EmployeeData.getEmployees();

    // 顺序流
    Stream<Employee> stream = employees.stream();

    // 并行流
    Stream<Employee> parallelStream = employees.parallelStream();
}

通过数组

创建方法:Arrays . stream(数组)

java
@Test
public void test2(){
    int[] arr = new int[]{1, 2, 3, 4, 5, 6};  // 创建一个数组
    // 调用Arrays类的static <T> Stream<T> stream(T[] array) 方法:返回一个流
    IntStream stream = Arrays.stream(arr);

    Employee e1 = new Employee(id: 1001, name: "Tom");
    Employee e2 = new Employee(id: 1002, name: "Jerry");
    Employee[][] arr1 = new Employee[][]{e1, e2};
    Stream<Employee> stream1 = Arrays.stream(arr1);
}

自定义内容

创建方法:Stream . of()

java
@Test
public void test3(){
    Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6);
}

无限流

迭代

public static <T> iterate(final T seed, final UnaryOperator <T> f )

调用方法

Stream . iterate (seed , 操作条件) . forEach(终止操作)

java
@Test
public void test4() {
    // 遍历前十个偶数
    Stream.iterate(0, t -> t + 2).limit(10).forEach(System.out::println);
}

生成

public static <T> Stream <T> generate ( Supplier <T> s

注意点

Supplier <T> s 接口有 T get( ) 方法,如符合返回类型和参数类型一致,可以使用方法引用

java
@Test
public void test4() {
    // 生成十个范围在 0 <= x < 1 的随机数
    Stream.generate(Math::random).limit(10).forEach(System.out::println);
}

中间操作

筛选与切片

alt text

filter 是 Predicate 接口,对应的抽象方法是 boolean test(T t )

distinct 去重的前提是基于重写 equals() 和 hashcode()方法

代码示例

java
package practise;

import java.util.ArrayList;
import java.util.stream.Stream;

public class pra {
    public static void main(String[] args) {
        ArrayList<Employee> employees = new ArrayList<>();
        employees.add(new Employee("jack", 18));
        employees.add(new Employee("tom", 23));
        employees.add(new Employee("lucy", 25));
        employees.add(new Employee("bob", 26));
        employees.add(new Employee("jack", 18));
        employees.add(new Employee("jack", 18));

        // 过滤
        Stream<Employee> stream1 = employees.stream();
        System.out.println("执行过滤:打印年龄大于 20 岁的员工");
        stream1.filter(employee -> employee.getAge() > 20).forEach(System.out::println);

        System.out.println();

        // 去重
        Stream<Employee> stream2 = employees.stream();
        System.out.println("执行去重");
        stream2.distinct().forEach(System.out::println);

        System.out.println();

        // 只查看前两名员工信息
        System.out.println("只查看前两名员工信息");
        employees.stream().limit(2).forEach(System.out::println);

        System.out.println();

        // 跳过前两名员工的信息
        System.out.println("跳过前两名员工的信息");
        employees.stream().distinct().skip(2).forEach(System.out::println);
    }
}

class Employee {
    String name;
    int age;

    public Employee() {

    }

    public Employee(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Employee{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;  // 如果是同一个对象,直接返回 true
        }
        if (obj == null || getClass() != obj.getClass()) {
            return false;  // 如果类型不同,返回 false
        }

        Employee employee = (Employee) obj;  // 将 obj 转换为 Employee
        return age == employee.age && name.equals(employee.name);  // 比较 name 和 age
    }

    @Override
    public int hashCode() {
        return 31 * name.hashCode() + age;  // 使用 name 和 age 来计算哈希值
    }
}

映射


快速应用:map (传入值 --> 返回值)

map 就是映射,简单理解就是一个 函数,通过 某种规则的对应,接收参数,按照规则处理,然后返回结果

Function 接口,对应的抽象方法为 R apply(T t)

flatMap() 接口可以处理流里面放流的情况,不是存放一个流而是直接把内容取出

类比集合:[ 1, 2, 3, [4, 5, 6] ] ( flatMap 处理 )--> [ 1, 2, 3, 4, 5, 6 ]

(1)Integer 映射为 int

java
mapToInt(Integer::intValue)

(2)Integer 映射为 doubleValue

java
mapToDouble(Integer::doubleValue)

(3)Integer 映射为 longValue

java
mapToLong(Integer::longValue)

(4)map 与 flatMap

java
public class Test {
    public static void main(String[] args) {
        List<String> list = Arrays.asList("aa", "bb", "cc", "dd");

        // map 映射为大写字母
        list.stream().map(s -> s.toUpperCase()).forEach(System.out::print);

        System.out.println();

        // 使用 map 处理嵌套 Stream
        Stream<Stream<Character>> streamStream = list.stream().map(Tool::fromStringToStream);
        streamStream.forEach(s -> {
            s.forEach(System.out::print);
        });

        System.out.println();

        // 使用 map 处理嵌套 Stream
        /*
            flatMap(Function f) —— 接收一个函数作为参数,
            将流中的每个值都转换成另一个流,
            然后把所有流合并成一个流。
         */
        Stream<Character> characterStream = list.stream().flatMap(Tool::fromStringToStream);
        characterStream.forEach(System.out::print);
    }
}

class Tool {
    public static Stream<Character> fromStringToStream(String str) {
        ArrayList<Character> list = new ArrayList<>();
        for (Character c : str.toCharArray()) {
            list.add(c);
        }
        return list.stream();
    }
}

排序

alt text

如果是定制排序,需要实现 Comparator 接口的抽象方法

java
public void test4() {

    // 自然排序
    List<Integer> list = Arrays.asList(12, 43, 65, 34, 87, 0, -98, 7);
    list.stream().sorted().forEach(System.out::println);

    // sorted(Comparator com) —— 定制排序
    List<Employee> employees = EmployeeData.getEmployees();
    employees.stream().sorted((e1, e2) -> {
        int ageValue = Integer.compare(e1.getAge(), e2.getAge());
        if(ageValue != 0){
            return ageValue;
        } else {
            // 默认按照年龄排序,如果年龄相同按照薪水排序
            return Double.compare(e1.getSalary(), e2.getSalary());
        }
    }).forEach(System.out::println)

}

终止操作

匹配与查找


java
@Test
public void test1(){
    List<Employee> employees = EmployeeData.getEmployees();

    // allMatch(Predicate p) — 检查是否所有员工的年龄都大于18
    boolean allMatch = employees.stream().allMatch(e -> e.getAge() > 18);
    System.out.println(allMatch);

    // anyMatch(Predicate p) — 检查是否存在员工的工资大于10000
    boolean anyMatch = employees.stream().anyMatch(e -> e.getSalary() > 10000);
    System.out.println(anyMatch);

    // noneMatch(Predicate p) — 检查是否没有匹配的元素
    // 检查是否存在员工姓名以“雷”字开头
    boolean noneMatch = employees.stream().noneMatch(e -> e.getName().startsWith("雷"));
    System.out.println(noneMatch);

    // findFirst — 返回第一个元素
    Optional<Employee> employee = employees.stream().findFirst();
    System.out.println(employee);

    // findAny — 返回当前流中的任意元素
    Optional<Employee> employee1 = employees.parallelStream().findAny();
    System.out.println(employee1);

}

统计


java
@Test
public void test2(){
    List<Employee> employees = EmployeeData.getEmployees();

    // count — 计算工资大于5000的员工数量
    long count = employees.stream().filter(e -> e.getSalary() > 5000).count();
    System.out.println(count);

    // max(Comparator c) — 返回流中最大值
    Stream<Double> salaryStream = employees.stream().map(e -> e.getSalary());
    Optional<Double> maxSalary = salaryStream.max(Double::compare);
    System.out.println(maxSalary);

    // min(Comparator c) — 返回流中最小值
    // 返回最低工资的员工信息
    Optional<Employee> employeeMin = employees.stream().min((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
    System.out.println(employeeMin);

    // forEach(Consumer c) — 内部迭代
    employees.stream().forEach(System.out::println);
}

归约(求和)

alt text

java
@Test
public void test3(){
    // reduce(T identity, BinaryOperator) — 可以将流中元素反复结合起来,得到一个值。返回一个自然数的和
    // 计算 1 - 10 的自然数的和
    List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
    Integer sum = list.stream().reduce(0, Integer::sum);
    System.out.println(sum);

    // reduce(BinaryOperator) — 可以将流中元素反复结合起来,得到一个值。返回公司所有员工工资的总和
    // 计算公司所有员工工资的总和
    List<Employee> employees = EmployeeData.getEmployees();
    Stream<Double> salaryStream = employees.stream().map(Employee::getSalary);
    Optional<Double> sumMoney = salaryStream.reduce(Double::sum);
    System.out.println(sumMoney);
}

收集

alt text

方法调用: collect ( Collectors . 调用方法名



java
public class Test {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
        List<Integer> collect = list.stream().filter(n -> n > 3).collect(Collectors.toList());
        System.out.println(collect);
    }
}

⭐ 定制排序

alt text

对象数组转换

(1)int [ ] 转 Integer [ ]

boxed()方法:将每个 int 元素装箱成 Integer

toArray(Integer [ ] :: new) 方法:构建 Integer 数组

java
import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        int[] arr = {1, 2, 3, 4, 5};

        // 使用 Arrays.stream() 和 boxed() 将 int[] 转换为 Integer[]
        Integer[] objArr = Arrays.stream(arr)       // 将 int[] 转换为 IntStream
                                 .boxed()          // 将每个 int 元素装箱成 Integer
                                 .toArray(Integer[]::new); // 转换为 Integer[] 数组

        System.out.println(Arrays.toString(objArr)); // 输出 [1, 2, 3, 4, 5]
    }
}

(2)Integer [ ] 转 int [ ]

mapToInt(Integer::intValue):将 Integer 转换为 int

java
import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        Integer[] objArr = {1, 2, 3, 4, 5};

        // 使用 Arrays.stream() 和 mapToInt() 将 Integer[] 转换为 int[]
        int[] arr = Arrays.stream(objArr)    // 将 Integer[] 转换为 Stream<Integer>
                          .mapToInt(Integer::intValue)  // 将 Integer 转换为 int
                          .toArray();        // 转换为 int[] 数组

        System.out.println(Arrays.toString(arr)); // 输出 [1, 2, 3, 4, 5]
    }
}

代码示例

对 int 数组按绝对值从小到大排序

(1)使用 Arrays . sort()方法,结合 Comparator 接口

java
public class Main {
    public static void main(String[] args) {
        int[] arr = {-5, 3, -1, 4, -2, 6};

        // 将 int[] 转换为 Integer[],以便使用 Comparator
        Integer[] arrObj = Arrays.stream(arr)
                                  .boxed()
                                  .toArray(Integer[]::new);

        // 使用 Arrays.sort() 和自定义 Comparator 按绝对值排序
        Arrays.sort(arrObj, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return Integer.compare(Math.abs(o1), Math.abs(o2));
            }
        });

        // 将排序后的 Integer[] 转换回 int[]
        arr = Arrays.stream(arrObj)
                    .mapToInt(Integer::intValue)
                    .toArray();

        // 输出排序后的数组
        System.out.println(Arrays.toString(arr));
    }
}

(2)使用 Stream API 中的 sorted()方法(一步到位

java
import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        int[] arr = {-5, 3, -1, 4, -2, 6};

        // 使用 IntStream 和 sorted() 直接按绝对值排序
        arr = Arrays.stream(arr)  // 将 int[] 转换为 IntStream
                    .boxed()      // 将 IntStream 转换为 Stream<Integer>
                    .sorted((a, b) -> Integer.compare(Math.abs(a), Math.abs(b))) // 按绝对值排序
                    .mapToInt(Integer::intValue)  // 转换回 IntStream
                    .toArray();  // 转换为 int[] 数组

        // 输出排序后的数组
        System.out.println(Arrays.toString(arr)); // 输出 [-1, -2, 3, 4, -5, 6]
    }
}