Java中set集合常用的stream方法,你了解哪几种?

哈喽,各位小伙伴们,你们好呀,我是喵手。运营社区:掘金/C站/腾讯云/阿里云/华为云/51CTO(全网同号);欢迎大家常来逛逛,互相学习。

今天我要给大家分享一些自己日常学习到的一些知识点,并以文字的形式跟大家一起交流,互相学习,一个人虽可以走的更快,但一群人可以走的更远。

我是一名后端开发爱好者,工作日常接触到最多的就是Java语言啦,所以我都尽量抽业余时间把自己所学到所会的,通过文章的形式进行输出,希望以这种方式帮助到更多的初学者或者想入门的小伙伴们,同时也能对自己的技术进行沉淀,加以复盘,查缺补漏。

小伙伴们在批阅的过程中,如果觉得文章不错,欢迎点赞、收藏、关注哦。三连即是对作者我写作道路上最好的鼓励与支持!

前言

在日常Java开发中,我们都知道SetCollection 接口的一个子接口,它表示一个不允许重复元素的集合。Set接口的常见实现类有 HashSetLinkedHashSetTreeSet。而在Java 8 起,引入了 Stream API,使得对集合的操作更加简洁和高效。对于 Set 集合,可以利用 Stream API 提供的各种方法来进行数据过滤、转换、排序等操作。

下面是一些常用的 Set 集合与 Stream 方法的示例和用法,看看你们都有用过那几种?

正文

1. 将 Set 转换为 Stream

首先,您需要将 Set 转换为 Stream,然后才能使用 Stream 提供的各种操作。

java 复制代码
/**
 * @Author 喵手
 */
public class SetStreamExample {
    public static void main(String[] args) {
        Set<String> set = new HashSet<>(Arrays.asList("Java", "Python", "JavaScript", "Ruby"));

        // 将 Set 转换为 Stream
        set.stream().forEach(System.out::println);
    }
}

输出结果:

json 复制代码
Java
Python
JavaScript
Ruby

实际运行结果展示如下:

2. filter():过滤元素

filter() 方法用于过滤集合中的元素,可以根据指定的条件进行筛选。

java 复制代码
import java.util.*;

/**
 * @Author 喵手
 * @date: 2025-04-14
 */
public class SetStreamFilterExample {
    public static void main(String[] args) {
        Set<String> set = new HashSet<>(Arrays.asList("Java", "Python", "JavaScript", "Ruby"));

        // 使用 filter 过滤包含 "Java" 的元素
        set.stream()
                .filter(e -> e.contains("Java"))
                .forEach(System.out::println);
    }
}

输出结果:

json 复制代码
Java
JavaScript

实际运行结果展示如下:

3. map():转换元素

map() 方法用于将集合中的元素转换为其他类型或修改元素的内容。

java 复制代码
import java.util.*;

/**
 * @Author 喵手
 * @date: 2025-04-14
 */
public class SetStreamMapExample {
    public static void main(String[] args) {
        Set<String> set = new HashSet<>(Arrays.asList("java", "python", "javascript", "ruby"));

        // 将所有元素转换为大写
        set.stream()
                .map(String::toUpperCase)  // 使用 map 转换为大写
                .forEach(System.out::println);
    }
}

输出结果:

json 复制代码
JAVA
PYTHON
JAVASCRIPT
RUBY

实际运行结果展示如下:

4. distinct():去重

虽然 Set 本身保证元素唯一,但在某些情况下,您可能在流操作中希望去除重复的元素。distinct() 方法用于返回流中不重复的元素。

java 复制代码
import java.util.*;

/**
 * @Author 喵手
 * @date: 2025-04-14
 */
public class SetStreamDistinctExample {
    public static void main(String[] args) {
        Set<String> set = new HashSet<>(Arrays.asList("Java", "Python", "Java", "Ruby", "Python"));

        // 使用 distinct 去除重复元素
        set.stream()
                .distinct()
                .forEach(System.out::println);
    }
}

输出结果:

json 复制代码
Java
Python
Ruby

实际运行结果展示如下:

5. sorted():排序

sorted() 方法用于对集合中的元素进行排序。默认是按照元素的自然顺序进行排序,也可以使用自定义的比较器来排序。

普通排序

java 复制代码
import java.util.*;

/**
 * @Author 喵手
 * @date: 2025-04-14
 */
public class SetStreamSortedExample {
    public static void main(String[] args) {
        Set<String> set = new HashSet<>(Arrays.asList("Java", "Python", "JavaScript", "Ruby"));

        // 使用 sorted() 进行排序(按字母升序)
        set.stream()
                .sorted()  // 默认排序
                .forEach(System.out::println);
    }
}

输出结果:

json 复制代码
Java
JavaScript
Python
Ruby

实际运行结果展示如下:

代码解析:

如上这段示例代码的目的是演示如何通过 Java 的流(Stream)API对集合进行排序,并输出排序后的元素。以下是详细的解析,仅供参考:

  1. 创建集合

    java 复制代码
    Set<String> set = new HashSet<>(Arrays.asList("Java", "Python", "JavaScript", "Ruby"));

    这行代码创建了一个 HashSet 集合,并用 Arrays.asList() 方法初始化了几个字符串元素。这里的元素是 "Java", "Python", "JavaScript", "Ruby"。HashSet 是一个无序集合,元素的顺序是不确定的。

  2. 流的操作

    java 复制代码
    set.stream()
        .sorted()  // 默认排序
        .forEach(System.out::println);
    • set.stream():将集合 set 转换为流。流(Stream)是 Java 8 引入的一种新方式,它可以更简洁、声明性地处理集合数据。

    • sorted():这是一个中间操作,用于对流中的元素进行排序。默认情况下,sorted() 方法会按元素的自然顺序(即字母顺序,对于字符串来说就是字典序)对元素进行升序排序。

    • forEach(System.out::println):这是一个终止操作,用于遍历流中的每个元素,并执行 System.out::println 方法来输出每个元素。

  3. 注意事项

    • HashSet 本身是不保证元素顺序的,但流(Stream)可以对元素进行排序,因此这里使用 stream()sorted() 来实现排序功能。
    • 由于 sorted() 是一个返回新流的操作,因此它不会修改原始的 set,而是返回一个排序后的新流。

总结来说,这段代码演示了如何使用 Java 8 的流式操作对集合中的元素进行排序并输出,使用的是默认的字母升序排序。

自定义排序

如果你想按照自定义规则进行排序,可以使用 Comparator

java 复制代码
import java.util.*;

/**
 * @Author 喵手
 * @date: 2025-04-14
 */
public class SetStreamSortedCustomExample {
    public static void main(String[] args) {
        Set<String> set = new HashSet<>(Arrays.asList("Java", "Python", "JavaScript", "Ruby"));

        // 使用自定义的 Comparator 进行排序(按字符串长度升序)
        set.stream()
                .sorted(Comparator.comparingInt(String::length))
                .forEach(System.out::println);
    }
}

输出结果:

json 复制代码
Ruby
Java
Python
JavaScript

实际运行结果展示如下:

6. collect():收集结果

collect() 方法用于将流的元素收集到一个容器中,如集合或列表。它是 Stream API 中最常用的方法之一。

java 复制代码
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author 喵手
 * @date: 2025-04-14
 */
public class SetStreamCollectExample {
    public static void main(String[] args) {
        Set<String> set = new HashSet<>(Arrays.asList("Java", "Python", "JavaScript", "Ruby"));

        // 将流的结果收集到一个 List 中
        List<String> list = set.stream()
                .collect(Collectors.toList());

        System.out.println(list);
    }
}

输出结果:

json 复制代码
[Java, Python, JavaScript, Ruby]

实际运行结果展示如下:

7. reduce():聚合元素

reduce() 方法用于对流中的元素进行聚合。你可以使用它来做加法、乘法等聚合操作。

java 复制代码
import java.util.*;

/**
 * @Author 喵手
 * @date: 2025-04-14
 */
public class SetStreamReduceExample {
    public static void main(String[] args) {
        Set<Integer> set = new HashSet<>(Arrays.asList(1, 2, 3, 4, 5));

        // 使用 reduce() 计算所有元素的总和
        int sum = set.stream()
                .reduce(0, (a, b) -> a + b);

        System.out.println("Sum: " + sum);
    }
}

输出结果:

json 复制代码
Sum: 15

实际运行结果展示如下:

8. anyMatch()allMatch()noneMatch():匹配操作

这几个方法用于检查流中是否有元素满足给定条件。

  • anyMatch():检查是否有任何元素满足条件。
  • allMatch():检查是否所有元素都满足条件。
  • noneMatch():检查是否没有任何元素满足条件。
java 复制代码
import java.util.*;

/**
 * @Author 喵手
 * @date: 2025-04-14
 */
public class SetStreamMatchExample {
    public static void main(String[] args) {
        Set<String> set = new HashSet<>(Arrays.asList("Java", "Python", "JavaScript", "Ruby"));

        // 使用 anyMatch 判断是否有元素包含 'Java'
        boolean anyMatch = set.stream()
                .anyMatch(e -> e.contains("Java"));
        System.out.println("Contains 'Java': " + anyMatch);

        // 使用 allMatch 判断是否所有元素包含 'a'
        boolean allMatch = set.stream()
                .allMatch(e -> e.contains("a"));
        System.out.println("All contain 'a': " + allMatch);
    }
}

输出结果:

json 复制代码
Contains 'Java': true
All contain 'a': false

实际运行结果展示如下:

归纳:常用的Stream方法

方法 作用 示例应用
filter() 过滤元素,根据条件筛选 过滤掉不符合条件的元素
map() 转换元素,进行映射操作 将元素转换为另一种类型或值
distinct() 去重 去掉集合中重复的元素
sorted() 排序 按照自然顺序或自定义规则排序元素
collect() 收集流中的元素到集合 将流收集到ListSet等集合中
reduce() 聚合操作,通过二元操作合并流中的元素 计算集合元素的总和、最大值等
anyMatch() 判断是否有元素符合条件 判断集合中是否有元素满足某条件
allMatch() 判断是否所有元素符合条件 判断集合中是否所有元素满足某条件
noneMatch() 判断是否没有元素符合条件 判断集合中是否没有元素满足某条件
forEach() 遍历集合中的元素并执行操作 对集合中的每个元素执行操作

通过利用这些常用的Stream方法,我们可以简洁而高效地处理Java集合数据,完成常见的数据操作,如过滤、转换、排序和聚合等。

接下来,我们来扒拉下上述每个方法的源码,进行深度理解,学习其底层原理。

源码剖析

1. filter()

filter() 方法的源码是通过 AbstractStream 类实现的。其核心逻辑是通过 Predicate 过滤流中的元素。

java 复制代码
@Override
public Stream<T> filter(Predicate<? super T> predicate) {
    Objects.requireNonNull(predicate);
    return new StreamSpliterators.FilterOp<>(this, predicate);
}
  • filter() 方法会返回一个新的流,该流仅包含满足 predicate 条件的元素。FilterOpStreamSpliterators 的一个内部类,它会在迭代流时应用过滤条件。

2. map()

map() 方法用于转换流中的元素,同样是在 AbstractStream 中实现。

java 复制代码
@Override
public <R> Stream<R> map(Function<? super T, ? extends R> mapper) {
    Objects.requireNonNull(mapper);
    return new StreamSpliterators.MapOp<>(this, mapper);
}
  • map() 方法通过传入的 Function,将流中的每个元素映射为一个新的值。内部通过 MapOp 类完成具体操作,生成一个新的流。

3. distinct()

distinct() 用于去重,它通过 StreamSpliterators.DistinctOp 来完成去重操作。

java 复制代码
@Override
public Stream<T> distinct() {
    return new StreamSpliterators.DistinctOp<>(this);
}
  • 该方法返回一个新的流,去除了流中的重复元素,内部使用 Set 来记录已遇到的元素。DistinctOp 负责实际的去重操作。

4. sorted()

sorted() 方法用来对流中的元素进行排序。

java 复制代码
@Override
public Stream<T> sorted() {
    return new StreamSpliterators.SortOp<>(this, null);
}

@Override
public Stream<T> sorted(Comparator<? super T> comparator) {
    return new StreamSpliterators.SortOp<>(this, comparator);
}
  • sorted() 方法有两个重载,一个使用自然顺序排序,另一个使用自定义 Comparator 排序。具体排序操作由 SortOp 类实现。

5. collect()

collect() 是流操作中的一个终结操作,它通过 Collector 来收集元素。

java 复制代码
@Override
public <R, A> R collect(Collector<? super T, A, R> collector) {
    Objects.requireNonNull(collector);
    return collector.finisher().apply(collector.accumulator().apply(collector.supplier(), stream));
}
  • collect() 方法调用 Collector 的方法来执行元素收集操作。它分为 supplier(提供一个空的容器)、accumulator(收集数据)、combiner(并行时合并数据)以及 finisher(最终转换成结果)。

6. reduce()

reduce() 方法用于将流中的元素合并成一个单一的结果。

java 复制代码
@Override
public Optional<T> reduce(BinaryOperator<T> accumulator) {
    Objects.requireNonNull(accumulator);
    return reduce((a, b) -> accumulator.apply(a, b));
}

@Override
public T reduce(T identity, BinaryOperator<T> accumulator) {
    Objects.requireNonNull(accumulator);
    T result = identity;
    for (T element : this) {
        result = accumulator.apply(result, element);
    }
    return result;
}
  • reduce() 方法依赖于二元操作 BinaryOperator 来将流中的元素逐步合并。第二个重载版本支持一个初始值。

7. anyMatch()

anyMatch() 判断流中是否有元素满足给定条件。

java 复制代码
@Override
public boolean anyMatch(Predicate<? super T> predicate) {
    Objects.requireNonNull(predicate);
    for (T t : this) {
        if (predicate.test(t)) {
            return true;
        }
    }
    return false;
}
  • anyMatch() 遍历流中的元素,只要有一个元素满足条件,就返回 true,否则返回 false

8. allMatch()

allMatch() 判断流中所有元素是否都满足给定条件。

java 复制代码
@Override
public boolean allMatch(Predicate<? super T> predicate) {
    Objects.requireNonNull(predicate);
    for (T t : this) {
        if (!predicate.test(t)) {
            return false;
        }
    }
    return true;
}
  • allMatch() 方法会检查每一个元素,如果任何一个元素不符合条件,立即返回 false

9. noneMatch()

noneMatch() 判断流中是否没有元素符合给定条件。

java 复制代码
@Override
public boolean noneMatch(Predicate<? super T> predicate) {
    Objects.requireNonNull(predicate);
    for (T t : this) {
        if (predicate.test(t)) {
            return false;
        }
    }
    return true;
}
  • noneMatch() 遍历流中的元素,如果有任何元素满足条件,则返回 false,否则返回 true

10. forEach()

forEach() 遍历流中的元素并对每个元素执行给定的操作。

java 复制代码
@Override
public void forEach(Consumer<? super T> action) {
    Objects.requireNonNull(action);
    for (T t : this) {
        action.accept(t);
    }
}
  • forEach() 方法遍历流中的每个元素,并对每个元素执行 Consumer 给定的操作。

小结

在本文中,我们深入探讨了Java 8的Stream API如何与Set集合结合使用,极大简化了集合操作的代码量,同时提升了开发效率。通过示例代码,我们展示了Stream API中的常用操作方法及其实际应用,包括:filter()map()distinct()sorted()collect()reduce()anyMatch()allMatch()noneMatch()、以及forEach()等。这些方法使得集合的操作更加简洁、声明性和高效,避免了传统的循环和条件判断,提供了一种更加函数式的编程风格。

关键点回顾

  1. filter(): 用于过滤集合中的元素,基于给定的条件进行筛选。
  2. map(): 用于转换集合中的元素,常用于类型转换或内容修改。
  3. distinct() : 去除重复元素,尽管Set保证了唯一性,但流操作中可能需要显式去重。
  4. sorted(): 排序集合元素,可以使用自然顺序或者自定义的比较器。
  5. collect() : 用于将流收集到集合中,如ListSet等。
  6. reduce(): 进行聚合操作,将集合中的元素通过某种规则合并成一个结果,常用于求和、求最大值等。
  7. 匹配操作 : anyMatch()allMatch()noneMatch()用于判断流中的元素是否符合给定条件,提供了不同的匹配策略。

流的底层实现

在底层实现方面,Stream API的每个操作方法都通过中间操作和终止操作的组合来实现。例如,filter()会返回一个新的流,其中的元素经过Predicate筛选;map()会根据给定的Function对每个元素进行转换,形成新的流;sorted()会根据自然顺序或自定义比较器对流中的元素进行排序。

这些方法的实现往往涉及到流式迭代器(如StreamSpliterators.FilterOpStreamSpliterators.MapOp等),它们负责在流的遍历过程中应用具体的操作,如过滤、转换、排序等。

Stream API的优势

  1. 简洁性 : 使用Stream API可以将原本繁琐的集合操作(如遍历、过滤、转换等)通过链式调用简洁地表达出来,代码更加清晰。
  2. 并行化支持 : Stream API支持并行操作,只需要调用parallelStream(),即可通过多核处理器并行处理集合中的元素。
  3. 函数式编程支持 : Stream API的操作方法大多数都是基于函数式编程思想设计的,使得代码更加模块化、灵活。

应用场景

Stream API非常适用于大规模数据处理、集合数据转换和复杂的条件筛选等场景。在现代开发中,尤其是处理API、数据库查询结果、文件流等数据源时,Stream API能够显著提升代码的可读性和执行效率。

总结

通过熟练掌握Stream API及其各种方法,相信大家可以更高效地处理Java集合中的数据,简化常见的数据操作,并且提升代码的可维护性。结合Lambda表达式,Stream API提供了强大的函数式编程能力,可以让你用更少的代码完成更多的任务。如果你还没有完全掌握Stream API,不妨通过实际的编程练习,深入理解每个方法的使用场景和底层原理,进一步提高你的Java编程水平。

... ...

文末

好啦,以上就是我这期的全部内容,如果有任何疑问,欢迎下方留言哦,咱们下期见。

... ...

学习不分先后,知识不分多少;事无巨细,当以虚心求教;三人行,必有我师焉!!!

wished for you successed !!!


⭐️若喜欢我,就请关注我叭。

⭐️若对您有用,就请点赞叭。

⭐️若有疑问,就请评论留言告诉我叭。


版权声明:本文由作者原创,转载请注明出处,谢谢支持!

相关推荐
Hanson Huang1 小时前
【数据结构】堆排序详细图解
java·数据结构·排序算法·堆排序
慕容静漪1 小时前
如何本地安装Python Flask并结合内网穿透实现远程开发
开发语言·后端·golang
ErizJ1 小时前
Golang|锁相关
开发语言·后端·golang
路在脚下@2 小时前
Redis实现分布式定时任务
java·redis
xrkhy2 小时前
idea的快捷键使用以及相关设置
java·ide·intellij-idea
巨龙之路2 小时前
Lua中的元表
java·开发语言·lua
烛阴2 小时前
手把手教你搭建 Express 日志系统,告别线上事故!
javascript·后端·express
良许Linux2 小时前
请问做嵌入式开发C语言应该学到什么水平?
后端
Pitayafruit2 小时前
SpringBoot整合Flowable【08】- 前后端如何交互
spring boot·后端·workflow
花花鱼2 小时前
itext7 html2pdf 将html文本转为pdf
java·pdf