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

2023-02-22 09:16:54
目录
事前准备FilterSortedMapMatchCountReduce总结

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

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

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

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

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

事前准备

演示>

    新建一个工具类,方便创建集合。新建两个类,例如开发中常见的数据库实体类和 DTO 类。
     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>

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

    具体使用方法如下:

     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>

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

    具体使用方法如下:

     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 数据转换
     */
     <R> Stream<R> map(Function<? super T, ? extends R> mapper);
    

    具体使用方法如下:

     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

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

    具体使用方法如下:

     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

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

    具体使用方法如下:

     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

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

    具体使用方法如下:

     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>

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

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