服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Java教程 - Java集合Stream流操作的基本使用教程分享

Java集合Stream流操作的基本使用教程分享

2023-03-01 14:53码指星斗 Java教程

流操作并不会影响原来的集合,可以简单认为,流操作是把集合中的一个元素逐个复制放到一个首尾相接的流动的水槽中。这篇文章整理了Stream流操作的基本使用,需要的可以参考一下

Java 中可以使用 java.util.Stream 对一个集合(实现了java.util.Collection接口的类)做各种操作,例如:求和、过滤、排序等等。

这些操作可能是中间操作——返回一个 Stream 流,或者是终端操作——返回一个结果。

流操作并不会影响原来的集合,可以简单认为,流操作是把集合中的一个元素逐个复制放到一个首尾相接的流动的水槽中。

Stream 流支持同步执行,也支持并发执行。如果我们直接获取 stream 流,得到的是同步执行的 stream 流;如果调用方法 parallelStream,则得到一个可以并发执行的 Stream 流。

注意:Map不支持 Stream 流,但是它的 KeyValue 支持,因为它们实现了 Set 接口。

事前准备

演示 Stream 流的提前准备,创建几个类以供测试

  • 新建一个工具类,方便创建集合。
  • 新建两个类,例如开发中常见的数据库实体类和 DTO 类。
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
public class MyUtil {
    private static List<String> list = new ArrayList<>();
    private static List<Student> students = new ArrayList<>();
    static {
        list.add("abc");
        list.add("xyz");
        list.add("fgh");
        list.add("abc");
        list.add("def");
        list.add("xyz");
        list.add("efg");
        Student s1 = new Student();
        s1.setAge("16");
        s1.setId(UUID.randomUUID().toString());
        s1.setName("张三");
        s1.setMajor("计算机科学与技术");
        Student s2 = new Student();
        s2.setAge("18");
        s2.setId(UUID.randomUUID().toString());
        s2.setName("李四");
        s2.setMajor("物联网工程");
        Student s3 = new Student();
        s3.setAge("20");
        s3.setId(UUID.randomUUID().toString());
        s3.setName("王五");
        s3.setMajor("网络工程");
        students.add(s1);
        students.add(s2);
        students.add(s3);
    }
    public static List<String> getList() {
        return list;
    }
    public static List<Student> getStudents() {
        return students;
    }
}
public class Student {
    private String id;
    private String name;
    private String age;
    private String major;
    
}
public class StudentDTO {
    private String name;
    private String major;
}

Filter

filter 可以帮助我们过滤流中的某些元素,其方法签名如下

?
1
2
3
4
5
/*
过滤操作,
Predicate 相当于一个谓词,即断言流中的元素满足某个条件,返回一个 布尔值
*/
Stream<T> filter(Predicate<? super T> predicate);

具体使用方法如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class Main {
    public static void main(String[] args) {
        List<String> list = MyUtil.getList();
        System.out.println("过滤操作之前:");
        System.out.println(list);
        // 过滤不以 a 开头的字符串,collect() 将流中的元素放到一个新的集合中
        List<String> newList = list.stream().filter(s -> !s.startsWith("a")).collect(Collectors.toList());
        System.out.println("-------------------------");
        System.out.println("过滤操作之后:");
        System.out.println(newList);
    }
}
======== 输出 =========
过滤操作之前:
[abc, xyz, fgh, abc, def, xyz, efg]
-------------------------
过滤操作之后:
[xyz, fgh, def, xyz, efg]

Sorted

sorted 可以帮助我们排序流中的元素,方法签名如下:

?
1
2
3
4
5
/*
中间操作,传入一个 Comparator,对流中的元素进行排序,如果不传入,则使用默认的 Comparable 排序
对原集合不影响
*/
Stream<T> sorted(Comparator<? super T> comparator);

具体使用方法如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class Main {
    public static void main(String[] args) {
        List<String> list = MyUtil.getList();
        System.out.println("排序操作之前:");
        System.out.println(list);
        List<String> newList = list.stream().sorted().collect(Collectors.toList());
        System.out.println("-------------------------");
        System.out.println("排序操作之后:");
        System.out.println(newList);
        System.out.println("自定义排序:");
        // 倒序排序。 forEach 方法可以用传入的方法 逐个 处理流中的元素
        list.stream().sorted((s1, s2)-> -s1.compareTo(s2)).forEach(System.out::println);
    }
}
======== 输出 =========
排序操作之前:
[abc, xyz, fgh, abc, def, xyz, efg]
-------------------------
排序操作之后:
[abc, abc, def, efg, fgh, xyz, xyz]
自定义排序:
xyz
xyz
fgh
efg
def
abc
abc

Map

Map 操作可以帮助我们将流中的一类元素映射为另一类元素,最典型的应用就是可以用来将数据库实体类转换为供前端使用的 DTO 类。方法签名如下:

?
1
2
3
4
5
/*
中间操作,可以将一个对象转化为另一个对象
例如做 DTO 数据转换
*/
<R> Stream<R> map(Function<? super T, ? extends R> mapper);

具体使用方法如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class Main {
    public static void main(String[] args) {
        List<Student> students = MyUtil.getStudents();
        System.out.println("map 操作之前");
        System.out.println(students);
        // collect 方法可以将流中的元素收集到一个 Collection 中,如果有去除重复元素的需求,可以考虑收集到 Set 中
        List<StudentDTO> dtos = students.stream().map(student -> {
            StudentDTO dto = new StudentDTO();
            dto.setName(student.getName());
            dto.setMajor(student.getMajor());
            return dto;
        }).collect(Collectors.toList());
        System.out.println("-------------------------");
        System.out.println("map 操作之后");
        System.out.println(dtos);
    }
}
======== 输出 =========
map 操作之前
[Student{id='cb5726cd-e73a-443e-95e5-155aa6e876ae', name='张三', age='16', major='计算机科学与技术'}, Student{id='94478bae-b2ee-4c43-bac0-12f45f4099cd', name='李四', age='18', major='物联网工程'}, Student{id='5fdd9e19-f7cf-4c61-b506-0ef58a36dcbe', name='王五', age='20', major='网络工程'}]
-------------------------
map 操作之后
[StudentDTO{name='张三', major='计算机科学与技术'}, StudentDTO{name='李四', major='物联网工程'}, StudentDTO{name='王五', major='网络工程'}]

Match

?
1
2
3
4
5
6
7
8
9
10
/*
终端操作,可以用来匹配操作,返回一个 boolean 值
可以方便地匹配集合中是否存在某种元素
*/
// 只要集合中有一个匹配,就返回 true
boolean anyMatch(Predicate<? super T> predicate);
// 集合中所有元素都匹配,才返回 true
boolean allMatch(Predicate<? super T> predicate);
// 集合中所有元素都不匹配,返回 true
boolean noneMatch(Predicate<? super T> predicate);

具体使用方法如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class Main {
    public static void main(String[] args) {
        List<String> list = MyUtil.getList();
        System.out.println("集合中的所有元素是否都以 a 开头");
        System.out.println(list.stream().allMatch(s -> s.startsWith("a")));
        System.out.println("集合中是否存在元素以 a 开头");
        System.out.println(list.stream().anyMatch(s -> s.startsWith("a")));
        System.out.println("集合中的元素是否都不以 a 开头(相当于 allMatch 的取反):");
        System.out.println(list.stream().noneMatch(s -> s.startsWith("a")));
    }
}
======== 输出 =========
集合中的所有元素是否都以 a 开头
false
集合中是否存在元素以 a 开头
true
集合中的元素是否都不以 a 开头(相当于 allMatch 的取反):
false

Count

?
1
2
3
4
/*
终端操作,返回 stream 流中及集合中的元素个数,返回一个 long 类型
*/
long count();

具体使用方法如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Main {
    public static void main(String[] args) {
        List<String> list = MyUtil.getList();
        System.out.println(list);
        System.out.println("集合中的个数:" + list.size());
        long count = list.stream().filter(s -> s.startsWith("a")).count();
        System.out.println("集合中以 a 开头的元素个数:" + count);
    }
}
======== 输出 =========
[abc, xyz, fgh, abc, def, xyz, efg]
集合中的个数:7
集合中以 a 开头的元素个数:2

Reduce

?
1
2
3
4
5
/*
终端操作,可以理解为减少集合的个数,对集合中的元素不断进行累加,最终只得到一个元素
Optional 包含一个对象,可以防止空指针异常
*/
Optional<T> reduce(BinaryOperator<T> accumulator);

具体使用方法如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
public class Main {
    public static void main(String[] args) {
        List<String> list = MyUtil.getList();
        // 可以理解为减少集合的个数,对集合中的元素不断进行累加,最终只得到一个元素
        // 例如对数字集合进行累加进行求和
        String s = list.stream().reduce((s1, s2) -> s1 + "###" + s2).get();
        System.out.println(s);
    }
}
======== 输出 =========
abc###xyz###fgh###abc###def###xyz###efg

总结

可以看到,stream 流操作并没有什么使用难度,但如果不熟悉 Lambda 表达式开发和函数引用,则使用起来可能会稍微吃力些。

置于并发流的使用,只需要使用集合的方法parallelStream(),就可以获得一个并发流,在编写代码上基本和同步流没什么区别,因此学会上面的基本用法基本足够了,实际使用过程中,根据实际情况决定如何使用即可。

以上就是Java集合Stream流操作的基本使用教程分享的详细内容,更多关于Java Stream流操作的资料请关注服务器之家其它相关文章!

原文链接:https://juejin.cn/post/7202153876438925372

延伸 · 阅读

精彩推荐
  • Java教程Kotlin 基础语法详细介绍

    Kotlin 基础语法详细介绍

    这篇文章主要介绍了Kotlin 基础语法详细介绍的相关资料,需要的朋友可以参考下...

    一片枫叶3282020-10-08
  • Java教程java使用Filter实现自动登录的方法

    java使用Filter实现自动登录的方法

    这篇文章主要为大家详细介绍了java使用Filter实现自动登录的方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    第九种格调的人生2442020-09-08
  • Java教程详解Java 微服务架构

    详解Java 微服务架构

    这篇文章主要介绍了Java 微服务架构的相关资料,帮助大家更好的理解和使用Java,感兴趣的朋友可以了解下...

    程序员曾曾10792021-08-02
  • Java教程Java inputstream和outputstream使用详解

    Java inputstream和outputstream使用详解

    这篇文章主要介绍了Java inputstream和outputstream使用详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下...

    努力努力再努力_qiqijia10632021-11-15
  • Java教程Java 如何使用JDBC连接数据库

    Java 如何使用JDBC连接数据库

    这篇文章主要介绍了Java 如何使用JDBC连接数据库,帮助大家更好的理解和学习使用Java,感兴趣的朋友可以了解下...

    心悦君兮君不知-睿12452021-08-16
  • Java教程深入理解窗口令牌WindowToken

    深入理解窗口令牌WindowToken

    这篇文章主要介绍了窗口令牌WindowToken的概念与作用,它是对应用组件的行为进行规范管理的一个手段。WindowToken由应用组件或其管理者负责向WMS声明并持有...

    151301403623822021-11-26
  • Java教程使用itextpdf操作pdf的实例讲解

    使用itextpdf操作pdf的实例讲解

    下面小编就为大家分享一篇使用itextpdf操作pdf的实例讲解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...

    悠闲咖啡0076862021-03-14
  • Java教程后端将数据转化为json字符串传输的方法详解

    后端将数据转化为json字符串传输的方法详解

    这篇文章主要给大家介绍了关于后端将数据转化为json字符串传输的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学...

    小强Zzz3232020-08-31