JDK8中stream中常用方法

文章目录


前言

JDK 1.8 引入的 Stream API 是 Java 函数式编程的核心特性之一,它提供了一种高效、声明式的方式来处理集合数据(如 List、Set 等),支持链式操作、并行处理和惰性求值。

什么是 Stream?

  • Stream 不是数据结构,不存储元素,而是对数据源(如集合、数组)进行计算的一系列操作(操作数据的管道)。
  • 不可变:不会修改原始数据源。
  • 惰性求值(Lazy Evaluation):中间操作(如 filter、map)不会立即执行,只有遇到终端操作(如 collect、forEach)才会触发整个流水线。
  • 可并行处理(ParallelStream):提高大数据处理效率

Stream API 的基本概念

数据源:可以是任何实现了 Collection 接口的数据结构,或者是数组、迭代器等。

中间操作:一系列按需惰性处理数据的管道操作,如过滤、映射、排序等。

终止操作:执行计算并返回结果的操作,如收集、聚合等。一旦执行了终止操作,流就会被消费掉,不能再被重复使用。

中间操作

中间操作可以链接起来形成流水线,常见的中间操作有:

filter(Predicate):过滤元素

map(Function):映射转换

flatMap(Function):扁平化映射(将流中的每个元素转为流,再合并)

distinct():去重

sorted() / sorted(Comparator):排序

peek(Consumer):调试用,对每个元素执行操作但不改变流

limit(long):截取前 N 个

skip(long):跳过前 N 个

java 复制代码
public static void main(String[] args) {
    List<String> list = Arrays.asList("apple", "banana", "orange", "avocado","apple");

    // 过滤
    List<String> list1 = list.stream()
            .filter(s -> s.startsWith("a"))
            .filter(s -> s.length() > 5).collect(Collectors.toList());
    System.out.println(list1);//[avocado]

    // 映射
    // 将字符串映射为对应的长度
    List<Integer> list2 = list.stream().map(String::length).collect(Collectors.toList());
    System.out.println(list2);//[5, 6, 6, 7, 5]
    // 将字符串映射为大写
    List<String> list3 = list.stream().map(String::toUpperCase).collect(Collectors.toList());
    System.out.println(list3);//[APPLE, BANANA, ORANGE, AVOCADO, APPLE]
    // 映射为指定字符串
    List<String> list4 = list.stream().map(item->item+"z").collect(Collectors.toList());
    System.out.println(list4);//[applez, bananaz, orangez, avocadoz, applez]

    // 去重
    List<String> list5 = list.stream().distinct().collect(Collectors.toList());
    System.out.println(list5);//[apple, banana, orange, avocado]

    // 排序
    List<String> list6 = list.stream().sorted().collect(Collectors.toList());
    System.out.println(list6);//[apple, apple, avocado, banana, orange]
    List<String> list7 = list.stream()
            .sorted((s1, s2) -> s2.compareTo(s1)).collect(Collectors.toList());
    System.out.println(list7);//[orange, banana, avocado, apple, apple]


    // 限制和跳过
    // 取前3个
    List<String> list8 = list.stream()
            .limit(3).collect(Collectors.toList());
    System.out.println(list8);//[apple, banana, orange]
    // 跳过第1个
    List<String> list9 = list.stream()
            .skip(1).collect(Collectors.toList());
    System.out.println(list9);//[banana, orange, avocado, apple]
}

终止操作

终止操作会触发流的执行,并且返回结果。常见的终止操作包括:

forEach(Consumer):遍历

collect(Collector):聚合成集合、字符串等(最常用)

reduce(BinaryOperator):归约(如求和、拼接)

count():元素个数

min() / max(Comparator):最值

anyMatch(Predicate) / allMatch / noneMatch:匹配检查

findFirst() / findAny():查找元素(Optional)

java 复制代码
public static void main(String[] args) {
    List<String> list = Arrays.asList("a", "b", "c", "a");

    // 遍历
    list.stream().forEach(System.out::println);

    // 转换为数组
    String[] array = list.stream().toArray(String[]::new);
    System.out.println(array);//["a", "b", "c", "a"]

    // 聚合操作
    Optional<String> first = list.stream().findFirst();
    System.out.println(first.get());//a
    // 检查列表中是否存在以字母"a"开头的字符串
    boolean anyMatch = list.stream().anyMatch(s -> s.startsWith("a"));
    System.out.println(anyMatch);//true
    // 检查列表中所有字符串的长度是否都等于1
    boolean allMatch = list.stream().allMatch(s -> s.length() == 1);
    System.out.println(allMatch);//true
    // 检查列表中是否没有任何空字符串
    boolean noneMatch = list.stream().noneMatch(s -> s.isEmpty());
    System.out.println(noneMatch);//true

    // 计数
    long count = list.stream().count();
    System.out.println(count);//4


    List<Integer> list2 = Arrays.asList(4,5,6,7);

    // 最值
    // 获取最大值
    Integer max = list2.stream().max(Integer::compareTo).orElse(0);
    System.out.println("最大值: " + max);//最大值: 7
    int max2 = list2.stream().mapToInt(Integer::intValue).max().orElse(0);
    System.out.println("最大值: " + max2);//最大值: 7
    // 获取最小值
    Integer min = list2.stream().min(Integer::compareTo).orElse(0);
    System.out.println("最小值: " + min);//最小值: 4
    int min2 = list2.stream().mapToInt(Integer::intValue).min().orElse(0);
    System.out.println("最小值: " + min2);//最小值: 4

    // 平均值
    double avg = list2.stream().mapToInt(Integer::intValue).average().orElse(0.0);
    System.out.println("平均数: " + avg);//平均数: 5.5

    //求和
    int sum = list2.stream().mapToInt(Integer::intValue).sum();
    System.out.println("累计总和: " + sum);//累计总和: 22

    // 或者使用reduce方法计算总和
    Integer sum2 = list2.stream().reduce(Integer::sum).orElse(0);
    System.out.println("使用reduce计算总和: " + sum2);//使用reduce计算总和: 22

    //orElse()方法,主要作用是提供默认值。
    List<Integer> list3 = new ArrayList<>();
    Integer max3 = list3.stream().max(Integer::compareTo).orElse(999);
    System.out.println("最大值: " + max3);//最大值: 999

    IntSummaryStatistics stats = list2.stream()
            .collect(Collectors.summarizingInt(Integer::intValue));

    System.out.println("计数: " + stats.getCount());      // 计数: 4
    System.out.println("总和: " + stats.getSum());        // 总和: 22
    System.out.println("平均值: " + stats.getAverage());  // 平均值: 5.5
    System.out.println("最大值: " + stats.getMax());      // 最大值: 7
    System.out.println("最小值: " + stats.getMin());      // 最小值: 4
}

集合元素为类的处理

java 复制代码
public static void main(String[] args) {
    List<Person> person = Arrays.asList(
            new Person("John", 25, "北京"),
            new Person("Jane", 30, "深圳"),
            new Person("Bob", 30, "上海"),
            new Person("Mike", 20, "深圳"),
            new Person("Lucy", 20, "深圳")
    );

    //toMap
    Map<String, Person> personMap = person.stream().collect(Collectors.toMap(Person::getName, item -> item));
    System.out.println(JSON.toJSONString(personMap));//{"Mike":{"age":20,"city":"深圳","name":"Mike"},"Bob":{"age":30,"city":"上海","name":"Bob"},"John":{"age":25,"city":"北京","name":"John"},"Lucy":{"age":20,"city":"深圳","name":"Lucy"},"Jane":{"age":30,"city":"深圳","name":"Jane"}}

    //处理key值冲突,当有冲突时保留上一个
    Map<Integer, Person> personMap2 = person.stream().collect(Collectors.toMap(Person::getAge, item -> item, (k1, k2) -> k1));
    System.out.println(JSON.toJSONString(personMap2));//{20:{"age":20,"city":"深圳","name":"Mike"},25:{"age":25,"city":"北京","name":"John"},30:{"age":30,"city":"深圳","name":"Jane"}}


    //分组
    Map<String, List<Person>> groupingMap = person.stream()
            .collect(Collectors.groupingBy(Person::getCity));
    System.out.println(JSON.toJSONString(groupingMap));//{"上海":[{"age":30,"city":"上海","name":"Bob"}],"深圳":[{"age":30,"city":"深圳","name":"Jane"},{"age":20,"city":"深圳","name":"Mike"},{"age":20,"city":"深圳","name":"Lucy"}],"北京":[{"age":25,"city":"北京","name":"John"}]}

    // 多级分组
    Map<String, Map<Integer, List<Person>>> multiGroupingMap = person.stream()
            .collect(Collectors.groupingBy(
                    Person::getCity,
                    Collectors.groupingBy(Person::getAge)
            ));
    System.out.println(JSON.toJSONString(multiGroupingMap));//{"上海":{30:[{"age":30,"city":"上海","name":"Bob"}]},"深圳":{20:[{"age":20,"city":"深圳","name":"Mike"},{"age":20,"city":"深圳","name":"Lucy"}],30:[{"age":30,"city":"深圳","name":"Jane"}]},"北京":{25:[{"age":25,"city":"北京","name":"John"}]}}


    // 分区(分成true/false两组)
    Map<Boolean, List<Person>> partition = person.stream()
            .collect(Collectors.partitioningBy(p -> p.getAge() > 25));
    System.out.println(JSON.toJSONString(partition));//{false:[{"age":25,"city":"北京","name":"John"},{"age":20,"city":"深圳","name":"Mike"},{"age":20,"city":"深圳","name":"Lucy"}],true:[{"age":30,"city":"深圳","name":"Jane"},{"age":30,"city":"上海","name":"Bob"}]}

}

// 静态内部类
static class Person {
    private String name;
    private Integer age;
    private String city;

    public Person(String name, Integer age, String city) {
        this.name = name;
        this.age = age;
        this.city = city;
    }

    public String getName() { return name; }
    public Integer getAge() { return age; }
    public String getCity() { return city; }

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

并行流

java 复制代码
public static void main(String[] args) {
    List<Person> list = new ArrayList<>();
    for (int i = 0; i < 50000; i++) {
        int j = i % 30;
        Person person = new Person("用户"+i, j, "test"+i);
        list.add(person);
    }


    long startTime = System.currentTimeMillis();
    List<Person> test1 = list.stream().filter(item -> item.getAge() > 20).map(item -> {
        item.setAge(item.getAge() * 2);
        return item;
    }).collect(Collectors.toList());
    long endTime = System.currentTimeMillis();
    System.out.println("执行时间: " + (endTime - startTime) + " 毫秒");//执行时间: 63 毫秒

    long startTime2 = System.currentTimeMillis();
    List<Person> test2 = list.parallelStream().filter(item -> item.getAge() > 20).map(item -> {
        item.setAge(item.getAge() * 2);
        return item;
    }).collect(Collectors.toList());
    long endTime2 = System.currentTimeMillis();
    System.out.println("执行时间: " + (endTime2 - startTime2) + " 毫秒");//执行时间: 19 毫秒
}

// 静态内部类
static class Person {
    private String name;
    private Integer age;
    private String city;

    public Person(String name, Integer age, String city) {
        this.name = name;
        this.age = age;
        this.city = city;
    }

    public String getName() { return name; }
    public Integer getAge() { return age; }
    public String getCity() { return city; }

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

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

    public void setCity(String city) {
        this.city = city;
    }

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

相关推荐
小旭95272 小时前
【Java 基础】泛型<T>
java·开发语言·intellij-idea
她说..2 小时前
FIND_IN_SET()方法
xml·java·spring boot
花间相见2 小时前
【JAVA开发】—— Maven核心用法与实战指南
java·python·maven
爱吃的强哥2 小时前
Springboot 使用 SSE推送消息到客户端(Electron)
java·spring boot·electron
Elias不吃糖2 小时前
Java Stream 流(Stream API)详细讲解
java·stream·
寻星探路2 小时前
【全景指南】JavaEE 深度解析:从 Jakarta EE 演进、B/S 架构到 SSM 框架群实战
java·开发语言·人工智能·spring boot·ai·架构·java-ee
七夜zippoe2 小时前
微服务架构演进实战 从单体到微服务的拆分原则与DDD入门
java·spring cloud·微服务·架构·ddd·绞杀者策略
洛_尘2 小时前
JAVA EE初阶8:网络原理 - HTTP_HTTPS(重要)
java·http·java-ee
独断万古他化2 小时前
【Java 网络编程全解】Socket 套接字与 TCP/UDP 通信实战全解
java·网络编程·socket