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

Stream 流常见基本操作

文章目录

  • 概述
    • 一、Stream 流的常见生成方式
    • 二、Stream 流中间操作方法
      • 1、常用中间操作方法
      • 2、使用示例1
      • 3、使用示例2
      • 4、使用示例3
      • 5、使用示例4
      • 6、使用示例5
      • 7、Stream 流使用注意事项
    • 三、Stream 流终结操作方法
      • 1、常用终结方法
      • 2、使用示例1
      • 3、使用示例2
      • 4、使用示例3
      • 5、Stream 基本分组功能
    • 四、Stream 综合小练习
  • 小结

概述

Stream 流是 Java8 新特性之一,我们在实际开发中借助 Stream 流搭配 Lambda 表达式,可以很方便的完成一些对集合的操作,可以显著的提升开发的效率和性能。

一、Stream 流的常见生成方式

通常我们会选择对以下类型生成 Stream 流:单列集合、双列集合、数组、零散的数据。

public class StreamDemo {public static void main(String[] args) {//Collection体系的集合可以使用默认方法stream()生成流List<String> list = new ArrayList<String>();Stream<String> listStream = list.stream();Set<String> set = new HashSet<String>();Stream<String> setStream = set.stream();//Map体系的集合间接的生成流Map<String,Integer> map = new HashMap<String, Integer>();Stream<String> keyStream = map.keySet().stream();Stream<Integer> valueStream = map.values().stream();Stream<Map.Entry<String, Integer>> entryStream = map.entrySet().stream();//数组可以通过Arrays中的静态方法stream生成流String[] strArray = {"hello","world","java"};Stream<String> strArrayStream = Arrays.stream(strArray);//同种数据类型的多个数据可以通过Stream接口的静态方法of(T... values)生成流Stream<String> strArrayStream2 = Stream.of("hello", "world", "java");Stream<Integer> intStream = Stream.of(10, 20, 30);}
}

二、Stream 流中间操作方法

1、常用中间操作方法

这里的中间操作的意思是,执行完此方法之后,Stream流依然可以继续执行其他操作(其他中间操作或终结操作)

方法名说明
Stream filter(Predicate predicate)用于对流中的数据进行过滤
Stream limit(long maxSize)获取前几个元素
Stream skip(long n)跳过前几个元素
Stream distinct()元素去重,依赖(hashCode和equals方法)
Stream sorted(Comparator<? super T> comparator)Stream 流元素排序
static Stream concat(Stream a, Stream b)合并a和b两个流为一个流
Stream map(Function<T,R> mapper)转换流中的数据类型

Stream.contact 合并两个 stream 流的时候,如果一个 stream 是 a 类型,另一个 stream 是 b 类型,那么最终合并为 a,b的父类型(类型提升)。

2、使用示例1

public class FilterDemo {// 获取以张开头的元素public static void main(String[] args) {// 创建一个集合,存储多个字符串元素ArrayList<String> list = new ArrayList<>();list.add("张三丰");list.add("张无忌");list.add("张翠山");list.add("王二麻子");list.add("张良");list.add("谢广坤");list.stream().filter(s ->s.startsWith("张")).forEach(s-> System.out.println(s));}
}

3、使用示例2

public class LimitAndSkipDemo {public static void main(String[] args) {//创建一个集合,存储多个字符串元素ArrayList<String> list = new ArrayList<String>();list.add("林青霞");list.add("张曼玉");list.add("王祖贤");list.add("柳岩");list.add("张敏");list.add("张无忌");//需求1:取前3个数据在控制台输出list.stream().limit(3).forEach(s-> System.out.println(s));System.out.println("--------");//需求2:跳过3个元素,把剩下的元素在控制台输出list.stream().skip(3).forEach(s-> System.out.println(s));System.out.println("--------");//需求3:跳过2个元素,把剩下的元素中前2个在控制台输出list.stream().skip(2).limit(2).forEach(s-> System.out.println(s));}
}

4、使用示例3

public class SortedDemo {// 按照年龄进行排序public static void main(String[] args) {ArrayList<String> manList = new ArrayList<>();Collections.addAll(manList,"蔡坤坤,24","叶厚贤,23,","刘不甜,22","吴倩,24","谷加,30","肖亮亮,27");manList.stream().sorted((o1,o2)->Integer.parseInt(o1.split(",")[1]) - Integer.parseInt(o2.split(",")[1])).forEach(x -> System.out.println(x));}
}

5、使用示例4

public class ConcatAndDistinctDemo {public static void main(String[] args) {//创建一个集合,存储多个字符串元素ArrayList<String> list = new ArrayList<String>();list.add("林青霞");list.add("张曼玉");list.add("王祖贤");list.add("柳岩");list.add("张敏");list.add("张无忌");//需求1:取前4个数据组成一个流Stream<String> s1 = list.stream().limit(4);//需求2:跳过2个数据组成一个流Stream<String> s2 = list.stream().skip(2);//需求3:合并需求1和需求2得到的流,并把结果在控制台输出,要求字符串元素不能重复Stream.concat(s1,s2).distinct().forEach(s-> System.out.println(s));}
}

6、使用示例5

public class MapDemo {public static void main(String[] args) {//创建一个集合,存储多个字符串元素ArrayList<String> list = new ArrayList<>();Collections.addAll(list,"张无忌-15","周芷若-14","赵敏-13","张强-20","张三丰-100","张翠山-40");// 需求:只获取里面1的年龄并进行打印List<Integer> collect = list.stream().map(s -> Integer.parseInt(s.split("-")[1])).collect(Collectors.toList());System.out.println(collect);}
}

7、Stream 流使用注意事项

注意1:修改 Stream 流中的数据,不会影响原来集合或者数组中的数据。

注意2:中间方法,返回新的 Stream 流,原来的 Stream 流只能使用一次,建议使用链式编程()。因为每次调用中间方法都会返回新的 Stream 流,原来的 Stream 流会关闭。如:

public class Test1 {public static void main(String[] args) {//创建一个集合,存储多个字符串元素ArrayList<String> list = new ArrayList<String>();list.add("林青霞");list.add("张曼玉");list.add("王祖贤");list.add("柳岩");list.add("张敏");list.add("张无忌");Stream<String> stream1 = list.stream().filter(s -> s.startsWith("张"));Stream<String> stream2 = stream1.filter(s -> s.length() == 3);stream2.forEach(s -> System.out.println(s));stream1.filter(s -> s.length() == 2);}
}

三、Stream 流终结操作方法

1、常用终结方法

终结操作的意思是,执行完终结方法之后,Stream 流将不能再执行其他操作了。

方法名说明
void forEach(Consumer action)遍历
long count()统计个数
toArray()收集流中的数据,放到数组中
R collect(Collector collector)收集流中的数据,放到集合中

工具类 Collectors 提供了具体的收集方式:

方法名说明
public static Collector toList()把元素收集到List集合中
public static Collector toSet()把元素收集到Set集合中
public static Collector toMap(Function keyMapper,Function valueMapper)把元素收集到Map集合中

注意1toSet() 会进行自动去重。
注意2toMap() 如果我们要收集到 Map 集合当中,键重复会报错。

2、使用示例1

public class CountAndForEachDemo {public static void main(String[] args) {//创建一个集合,存储多个字符串元素ArrayList<String> list = new ArrayList<>();list.add("张三丰");list.add("张无忌");list.add("张翠山");list.add("王二麻子");list.add("张良");list.add("谢广坤");// 统计返回此流中的元素数long count = list.stream().count();System.out.println(count);// 遍历打印流中元素list.stream().forEach(x -> System.out.println(x));}
}

3、使用示例2

public class ToArrayDemo {public static void main(String[] args) {//创建一个集合,存储多个字符串元素ArrayList<String> list = new ArrayList<>();list.add("张三丰");list.add("张无忌");list.add("张翠山");list.add("王二麻子");list.add("张良");list.add("谢广坤");// 收集流中的数据,放到数组中 (Object 数组)Object[] objects = list.stream().toArray();System.out.println(Arrays.toString(objects));// 收集流中的数据,放到数组中 (指定类型 数组)// toArray 方法参数就是创建一个指定类型的数组// 底层会依次得到流里面的每一个数据,并把数据放到数组当中// 返回值就是一个装着流里面所有数据的数组String[] strings = list.stream().toArray(valuecount -> new String[valuecount]);System.out.println(Arrays.toString(strings));}
}

4、使用示例3

public class CollectDemo {public static void main(String[] args) {//创建一个集合,存储多个字符串元素ArrayList<String> list = new ArrayList<>();Collections.addAll(list,"张无忌-男-15","周芷若-女-14","赵敏-女-13","张三丰-男-100","谢广坤-男-41");// 需求1:把所有男性收集到list集合当中List<String> newList1 = list.stream().filter(s -> "男".equals(s.split("-")[1])).collect(Collectors.toList());System.out.println(newList1);// 需求2:把所有男性收集到set集合当中Set<String> newList2 = list.stream().filter(s -> "男".equals(s.split("-")[1])).collect(Collectors.toSet());System.out.println(newList2);// 需求3:把所有男性收集到map集合当中(键为姓名,值为年龄)Map<String, Integer> map = list.stream().filter(s -> "男".equals(s.split("-")[1])).collect(Collectors.toMap(s -> s.split("-")[0],s -> Integer.parseInt(s.split("-")[2])));System.out.println(map);}
}

5、Stream 基本分组功能

方法名说明
Collector<T, ?, Map<K, List>> groupingBy(Function<? super T, ? extends K> classifier)这是最基本的 groupingBy 方法,classifier:键映射:该方法的返回值是键值对的 键
Collector<T, ?, Map<K, D>> groupingBy(Function<? super T, ? extends K> classifier, Collector<? super T, A, D> downstream)这个重载方法在基本的 groupingBy 方法的基础上添加了一个 downstream 参数,downstream:值映射:通过聚合方法将同键下的结果聚合为指定类型,该方法返回的是键值对的 值
Collector<T, ?, M> groupingBy(Function<? super T, ? extends K> classifier, Supplier mapFactory, Collector<? super T, A, D> downstream)这个重载方法除了包含分类函数和 downstream 收集器外,还接收一个 mapFactory 参数,mapFactory:无参构造函数提供返回类型:提供一个容器初始化方法,用于创建新的 Map容器 (使用该容器存放值对)
public class GroupDemo {// 基本分组操作public static void main(String[] args) {// 初始化数据Actor actor1 = new Actor("张三",18);Actor actor2 = new Actor("李四",20);Actor actor3 = new Actor("王五",22);List<Actor> actors = new ArrayList<>();Collections.addAll(actors,actor1,actor2,actor3);// 按照姓名分组Map<String, List<Actor>> collect = actors.stream().collect(Collectors.groupingBy(actor -> actor.getName()));// 打印结果System.out.println(collect);// 将不同课程的学生进行分类Map<String, List<Actor>> groupByCourse = actors.stream().collect(Collectors.groupingBy(actor -> actor.getName()));System.out.println(groupByCourse);Map<String, List<Actor>> groupByCourse1 = actors.stream().collect(Collectors.groupingBy(actor -> actor.getName(), Collectors.toList()));System.out.println(groupByCourse1);// 上面的方法中容器类型和值类型都是默认指定的,容器类型为:HashMap,值类型为:ArrayList// 可以通过下面的方法自定义返回结果、值的类型Map<String, List<Actor>> groupByCourse2 = actors.stream().collect(Collectors.groupingBy(actor -> actor.getName(),() -> new HashMap<>(),Collectors.toList()));System.out.println(groupByCourse2);}
}

其他分组操作参考:Stream Collectors.groupingBy 的四种用法

四、Stream 综合小练习

public class Test {public static void main(String[] args) {// 现有两个 ArrayList 集合:// 第一个集合:存储 6 名男演员的名字和年龄;第二个集合:存储 6 名女演员的名字和年龄ArrayList<String> manList = new ArrayList<>();ArrayList<String> womanList = new ArrayList<>();Collections.addAll(manList,"蔡坤坤,24","叶厚贤,23,","刘不甜,22","吴倩,24","谷加,30","肖亮亮,27");Collections.addAll(womanList,"赵晓英,35","杨颖,36","高媛媛,43","刘诗,35","杨小敏,33");// 需求1:男演员只要名字为 3 个字的前两人Stream<String> stream1 = manList.stream().filter(s -> s.split(",")[0].length() == 3).limit(2);// 需求2:女演员只要姓杨的,并且不要第一个Stream<String> stream2 = womanList.stream().filter(s -> s.split(",")[0].startsWith("杨")).skip(1);// 需求3:把过滤后的男演员姓名和女演员合并到一起封装成 Actor 对象(Actor 对象属性有 name、age)Stream<Actor> stream3 = Stream.concat(stream1, stream2).map(s -> new Actor(s.split(",")[0], Integer.parseInt(s.split(",")[1])));// 需求5:将所有的演员对象都报存到 List 集合中stream3.collect(Collectors.toList()).forEach(s -> System.out.println(s));}
}

小结

Stream 流的使用步骤?

  1. 获取 Stream 流对象
  2. 使用中间方法处理数据
  3. 使用终结方法处理数据

如何获取 Stream 流对象?

  1. 单列集合:Collection 中的默认方法
  2. 双列集合:不能直接获取,可借助 keySets、values 转换成单列集合间接获取
  3. 数组:Arrays 工具类型中的静态方法
  4. 零散的数据:Stream 接口中的静态方法 of

Stream 常见方法?

  1. 中间方法:filter、limit、skip、distinct、concat、map
  2. 终结方法:forEach、count、collect

Lambda 怎么简化?

  1. 首先,数据类型可以省略
  2. 如果形参只有一个,小括号可以省略
  3. 如果形参有多个,小括号就不能省略了
  4. 如果方法体只有一行,那么大括号可以省略,return 可以省略分号可以省略

:上述所有方法皆为函数式接口,因此均可以使用 Lambda 表达式进行替换,或使用方法引用替换(下期介绍)。

http://www.lryc.cn/news/2412621.html

相关文章:

  • ApiPost简介
  • Canvas详解
  • eclipse下载|安装|项目创建|常规设置|详细图文教程【windows10】
  • spring太强了!两万多字干货 超详细讲解
  • Kafka最全讲解,通俗易懂
  • PostgreSQL教程(三):SQL语言
  • Fiddler工具介绍及基本使用
  • axios 开源项目教程
  • Vue 3 中实现 Element Plus 表格的多选功能与条件操作(附Demo)
  • 微信开发者工具
  • 创建虚拟机步骤以及开启电脑虚拟设置方法
  • 大数据入门系列 1:全网最全,Windows 安装 VMware Workstation 虚拟机完整步骤及需要注意的问题
  • SpringBoot--入门使用
  • Node入门
  • 介绍Vant入门及使用方法
  • 国产化的接口测试、接口自动化测试工具apifox的介绍及使用
  • C/C++之(一)洛谷刷题及洛谷评测
  • 抓包工具(二)Wireshark 的下载、安装、使用、快捷键
  • Json文件格式化方法
  • Node.js环境配置
  • 【系统功能开发篇】若依管理系统功能介绍
  • nodejs详细安装步骤(保姆级教程)
  • poj 1204 Word Puzzles
  • 测试基础---测试用例01
  • 1350. 院系无效的学生 1355. 活动参与者 1369. 获取最近第二次的活动 1378. 使用唯一标识码替换员工ID1398. 购买了产品 A 和产品 B 却没有购买产品 C 的顾客
  • eCharts基础详解
  • Vscode 配置C/C++开发环境
  • 我用两个月时间,终于把CSDN付费资源项目玩明白了!
  • AVR单片机网址推荐 .
  • 经典智力题