好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

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

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

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

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

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

注意: Map 不支持 Stream 流,但是它的 Key 和 Value 支持,因为它们实现了 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测试数据pareTo(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集合Stream流操作的基本使用教程分享的详细内容...

  阅读:18次