当前位置: 首页 > news >正文

JAVA中关于Stream流的使用

1 集合处理的弊端

当我们需要对集合中的元素进行操作的时候,除了必需的添加、删除、获取外,最典型的就是集合遍历。我们来体验 集合操作数据的弊端,需求如下:

public class Demo01 {public static void main(String[] args) {// 一个ArrayList集合中存储有以下数据:张无忌,周芷若,赵敏,张强,张三丰// 需求:1.拿到所有姓张的 2.拿到名字长度为3个字的 3.打印这些数据ArrayList<String> list = new ArrayList<>();Collections.addAll(list, "张无忌", "周芷若", "赵敏", "张强", "张三丰");// 1.拿到所有姓张的ArrayList<String> zhanglist = new ArrayList<String>();for (String string : list) {if (string.startsWith("张")) {zhanglist.add(string);}}System.out.println(zhanglist);ArrayList<String> threeList = new ArrayList<String>();// 2.拿到名字长度为3的字for (String string : zhanglist) {if (string.length() == 3) {threeList.add(string);}}System.out.println(threeList);// 这段代码中含有三个循环,每一个作用不同:
// 1. 首先筛选所有姓张的人;
// 2. 然后筛选名字有三个字的人;
// 3. 最后进行对结果进行打印输出。
// 每当我们需要对集合中的元素进行操作的时候,总是需要进行循环、循环、再循环。// 这是理所当然的么? 不是。循环 是做事情的方式,而不是目的。// 每个需求都要循环一次,还要搞一个新集合来装数据,如果希望再次遍历,// 只能再使 用另一个循环从头开始。
// 那Stream能给我们带来怎样更加优雅的写法呢?System.out.println("==========================");// 使用Stream流的方式来完成此处的任务list.stream().filter(string -> string.startsWith("张")).filter(string -> string.length() == 3).forEach(System.out::println);}}
// 直接阅读代码的字面意思即可完美展示无关逻辑方式的语义:
// 获取流、过滤姓张、过滤长度为3、逐一打印。
// 我们真 正要做的事情内容被更好地体现在代码中。

Stream流思想概述

注意: StreamIO(InputStream/OutputStream)没有任何关系,请暂时忘记对传统IO流的固有印象!

Stream流式思想类似于工厂车间的“生产流水线” ,Stream流不是一种数据结构,不保存数据,而是对数据进行加工 处理。 Stream可以看作是流水线上的一个工序。在流水线上,通过多个工序让一个原材料加工成一个商品。

2  获取Stream流的方式

java.util.stream.Stream<T>是JDK 8新加入的流接口。 获取一个流非常简单,有以下几种常用的方式:

  1. Collection集合提供了 default Stream<E> stream()获取流;

  2. Stream接口的静态方法 of 可以获取对应的流。

public class Demo02 {public static void main(String[] args) {// 方式1:List<String> list = new ArrayList<String>(Arrays.asList("aa","bb","cc"));Stream<String> stream1 = list.stream();System.out.println("============================");stream1.forEach(System.out::println);Set<String> set = new HashSet<String>(Arrays.asList("aa","bb","cc"));Stream<String> stream2 = set.stream();System.out.println("============================");stream2.forEach(System.out::println);Map<Integer, String> map = new HashMap<Integer, String>(){{put(1, "aa");put(2, "bb");put(3, "cc");}};Stream<Integer> stream3 = map.keySet().stream();Stream<String> stream4 = map.values().stream();Stream<Map.Entry<Integer, String>> stream5 = map.entrySet().stream();System.out.println("============================");stream3.forEach(System.out::println);System.out.println("============================");stream4.forEach(System.out::println);System.out.println("============================");stream5.forEach(System.out::println);// 方式2:Stream<String> stream6 = Stream.of("aa", "bb", "cc");System.out.println("============================");stream6.forEach(System.out::println);String[] strs = {"aa", "bb", "cc"};Stream<String> stream7 = Stream.of(strs);System.out.println("============================");stream7.forEach(System.out::println);int[] ints1= {1,2,3,4,5};int[] ints2= {0,6,7,8,9};Stream<int[]> stream8 = Stream.of(ints1,ints2);System.out.println("============================");stream8.forEach(System.out::println);}
}

3  Stream流的常用方法和注意事项

Stream流常用方法

Stream流模型的操作很丰富,这里介绍一些常用的API。

这些方法可以被分成两种:

终结方法:返回值类型不再是 Stream类型的方法,不再支持链式调用。本小节中,终结方法包括 count和 forEach 方法。

非终结方法:返回值类型仍然是 Stream类型的方法,支持链式调用。(除了终结方法外,其余方法均为非终结 方法。)

public class Demo03 {public static void main(String[] args) {Stream<String> stream = Stream.of("aa", "bb", "cc","dd");
//        long count = stream.count();
//        System.out.println(count);//        long count1 = stream.count();  //报错//2.只要对流做操作,返回的就不是原来的流,而是一个新流Stream<String> stream2 = stream.limit(3);
//        stream2.forEach(System.out::println);//3.不使用终结方法,中间的操作不会执行stream2.filter(str->{System.out.println(str);return true;}).count();}
}

1  forEach方法

forEach 用来遍历流中的数据 void forEach(Consumer<? super T> action); 该方法接收一个 Consumer接口函数,会将每一个流元素交给该函数进行处理。例如:

List<String> list = new ArrayList<String>();
Collections.addAll(list,"迪丽热巴","古力娜扎","刘亦菲","赵雅芝");
//1.获取流  遍历集合中的元素
Stream<String> stream=list.stream();
stream.forEach(str-> System.out.println(str));

2  count方法

Stream流提供 count方法来统计其中的元素个数:long count(); 该方法返回一个long值代表元素个数。基本使用:

List<String> list = new ArrayList<String>();
Collections.addAll(list,"迪丽热巴","古力娜扎","刘亦菲","赵雅芝");//2.Stream流提供count方法来统计其中的元素个数
long count=stream.count();
System.out.println(count);

3  filter方法

filter用于过滤数据,返回符合过滤条件的数据,可以通过 filter方法将一个流转换成另一个子集流。
该方法接收一个 Predicate 函数式接口参数(可以是一个Lambda或方法引用)作为筛选条件。

List<String> list = new ArrayList<String>();
Collections.addAll(list,"迪丽热巴","古力娜扎","刘亦菲","赵雅芝");//3.filter用于过滤器,返回符合过滤条件的数据
Stream<String> stream1=stream.filter(str->str.length()==3);
stream1.forEach(System.out::println);

4  limit方法

limit方法可以对流进行截取,只取用前n个。参数是一个long型,如果集合当前长度大于参数则进行截取。否则不进行操作。

List<String> list = new ArrayList<String>();
Collections.addAll(list,"迪丽热巴","古力娜扎","刘亦菲","赵雅芝");//4.limit方法可以对流进行截取,只取用前n个
stream.limit(3).forEach(System.out::println);

5  skip方法

如果希望跳过前几个元素,可以使用 skip方法获取一个截取之后的新流。如果流的当前长度大于n ,则跳过前n个;否则将会得到一个长度为0的空流。

List<String> list = new ArrayList<String>();
Collections.addAll(list,"迪丽热巴","古力娜扎","刘亦菲","赵雅芝");//5.如果希望跳过前几个元素,可以使用 skip方法获取一个截取之后的新流。
stream.skip(2).forEach(System.out::println);

6  map方法

Map可以将一种类型的流转换成另一种类型的流。该接口需要一个 Function 函数式接口参数,可以将当前流中的T类型数据转换为另一种R类型的流。

 ArrayList<String> list = new ArrayList<>(Arrays.asList("32","22","15","80","58"));
Stream<String> stream = list.stream();
//6.Map可以将一种类型的流转换成另一种类型的流
Stream<Integer> stream1=stream.map(string -> Integer.parseInt(string));
stream1.forEach(System.out::println);

7  sorted方法

如果需要将数据排序,可以使用 sorted方法。

ArrayList<String> list = new ArrayList<>(Arrays.asList("32","22","15","80","58"));
Stream<String> stream = list.stream();
//6.Map可以将一种类型的流转换成另一种类型的流
Stream<Integer> stream1=stream.map(string -> Integer.parseInt(string));
//  stream1.forEach(System.out::println);
System.out.println("===============sorted===================");//如果需要将数据排序,可以使用sorted()方法
//使用泛型类型的默认排序规则方法
//        stream1.sorted().forEach(System.out::println);//使用自定义的Comparator比较规则排序
stream1.sorted((a,b)->b-a).forEach(System.out::println);

8  distinct方法

如果需要去除重复数据,可以使用 distinct方法。

ArrayList<String> list = new ArrayList<>(Arrays.asList("32","22","15","80","58"));
Stream<String> stream = list.stream();
//6.Map可以将一种类型的流转换成另一种类型的流
Stream<Integer> stream1=stream.map(string -> Integer.parseInt(string));System.out.println("================distinct===============");
//去重
Stream.of(1,3,5,3,7,3,8,7).distinct().forEach(System.out::println);

9  match方法

如果需要判断数据是否匹配指定的条件,可以使用 Match相关方法。

System.out.println("===============match==================");
//如果需要判断数据是否匹配指定的条件,可以使用Match相关方法
//所有的元素匹配条件,则返回true
boolean b = Stream.of(1,4,6,7,5,8,9,6,4).allMatch(number -> number % 2 == 0);
System.out.println("是否都为偶数?"+b);//只要有一个匹配条件,则返回true
boolean b1 = Stream.of(1,4,6,7,5,8,9,6,4).anyMatch(number -> number % 2 == 0);
System.out.println("是否有偶数?"+b1);//所有的元素都不匹配,则返回true
boolean b3 = Stream.of(1,4,6,7,5,8,9,6,4).noneMatch(number -> number % 2 == 0);
System.out.println("是否都不为偶数?"+b1);

10  collect方法

collect() 收集是一个 最终操作,返回Stream中元素集合,返回值类型是集合(List、Set、Map字符串

将Stream中的元素,收集至新集合

  • Collectors.toList()

  • Collectors.toSet()

  • Collectors.toMap()

public class Demo06 {public static void main(String[] args) {List<String> list = Arrays.asList("abc", "defg", "ghi","ghi","ijkl", "ijkl","ijkl","mno");//将过滤结果,收集至List集合List<String> list1 = list.stream().filter(s->s.toUpperCase().contains("I")).collect(Collectors.toList());System.out.println(list1);System.out.println("=============================");//将过滤结果,收集到set集合Set<String> set = list.stream().filter(s->s.toUpperCase().contains("I")).collect(Collectors.toSet());System.out.println(set);System.out.println("=============================");//将过滤结果,收集至Map集合Map<String,Integer> map=list.stream().distinct().collect(Collectors.toMap(s->s,s->s.length()));System.out.println(map);System.out.println("=============================");//按照字符串长度统计Map<Integer,List<String>> map1=list.stream().collect(Collectors.groupingBy(s->s.length()));System.out.println(map1);System.out.println("=============================");//按照字符串长度转成集合List<Integer> mappingList=list.stream().collect(Collectors.mapping(s->s.length(),Collectors.toList()));System.out.println(mappingList);}
}

11  Parallel Streams 并行流

Stream有串行和并行两种,串行Stream上的操作是在一个线程中依次完成,而并行Stream则是在多个线程上同时执行。

public class Demo07 {public static void main(String[] args) {int max = 1000000;List<String> values = new ArrayList<>(max);for (int i = 0; i < max; i++) {UUID uuid = UUID.randomUUID();values.add(uuid.toString());}long t0 = System.nanoTime();//返回豪微秒
//        values.stream().sorted().forEachOrdered(t -> System.out.println(t));values.parallelStream().sorted().forEachOrdered(t -> System.out.println(t));long t1 = System.nanoTime();long millis = TimeUnit.NANOSECONDS.toMillis(t1 - t0);System.out.println(String.format("串行排序,耗时共计: %d 毫秒", millis));}
}

    4 Stream流注意事项

    1. Stream只能操作一次

    2. Stream方法返回的是新的流

    3. Stream不调用终结方法,中间的操作不会执行

    http://www.dtcms.com/a/324982.html

    相关文章:

  • 虚拟主机示例
  • vuhub drippingblues靶场攻略
  • Windows环境下私有化部署Dify,并接入通义千问模型
  • UNet改进(31):基于Adaptive Attention的UNet设计与实践
  • 基于Spring SSE构建实时监控系统
  • Python 的列表 list 和元组 tuple 有啥本质区别?啥时候用谁更合适?
  • TC39x STM(System Timer)学习记录
  • 压力测试等工具源码包编译及使用方法
  • Vulnhub doubletrouble 靶场复现 详细攻略
  • Knuth‘s TwoSum Algorithm 原理详解
  • MyBatis 核心入门:从概念到实战,一篇掌握简单增删改查
  • 【东枫科技】FR3 可扩展测试平台,适用于 6G 研究与卫星通信,高达 1.6 GHz 的带宽
  • 【自动化运维神器Ansible】playbook案例解析:Tags组件实现任务选择性执行
  • 【01】华勤技术股份有限公司——华勤C++笔试,题目记录及解析
  • Java基础-使用反射做一个简易框架
  • Python 实例属性和类属性
  • 【PyTorch】单目标检测项目
  • vulnhub-Drippingblues靶机
  • Typora结合PicGo + 使用Gitee搭建个人免费图床
  • 计算机网络---IP(互联网协议)
  • 2025年6月电子学会全国青少年软件编程等级考试(Python六级)真题及答案
  • 二叉树进阶 之 【二叉搜索树的简介与模拟实现的前提准备】
  • 【杂谈】-智能代理+可观察性:构建下一代复杂系统监控体系
  • UE5多人MOBA+GAS 41、制作一个飞弹,添加准心索敌
  • JS实现数组扁平化
  • 计算二分类误差时的常见错误及解决方案
  • ubuntu22.04+samba
  • VMware 使用 Ubuntu 一段时间后逐渐卡顿、甚至卡死的问题
  • sqli-labs-master/Less-51~Less-61
  • 解读 GPT-5:从“博士级 AI 专家”能力到 OpenAI API Key 获取与实践(提示工程→性能调优全流程)