Java Stream流
a sequence of elements from source that supports aggregate operations
1. 概述
流不存储元素,可以根据需要进行计算转换
pipelining:很多流的操作也是返回一个流
internal iteration:流操作进行迭代,用户感知不到循环遍历
流的工作流程
- 创建一个流
- 指定将流转换为其他流的中间操作,可包括多个步骤(惰性操作)
- 应用终止操作,从而产生结果。这个操作会强制执行之前的惰性操作。这个步骤以后,流就再也不用了。
2. 流的创建
-
1、Collection接口的stream方法
Stream<String> as = new ArrayList<String>().stream();
-
2、Arrays.stream可以将数组转为Stream
Stream<String> b = Arrays.stream("a,b,c,d,e".split(","), 3, 5);
-
3、利用Stream类进行转化
-
of方法,直接将数组转化
Stream<Integer> c = Stream.of(new Integer[5]);
-
empty方法,产生一个空流
Stream<String> d = Stream.empty();
-
generate方法,接收一个Lambda表达式
Stream<String> e1 = Stream.generate(() -> "hello");
Stream<Double> e2 = Stream.generate(Math::random);
-
iterate方法,接收一个种子和一个Lambda表达式
Stream<BigInteger> e3 = Stream.iterate(BigInteger.Zero, n -> n.add(BigInteger.ONE));
-
-
4、基本类型流(只有三种)
-
IntStream
IntStream s = IntStream.of(1,2,3,4,5); Stream<Integer> s1 = s.boxed(); IntStream s2 = s1.mapToInt(Integer::intValue);
-
LongStream
-
DoubleStream
-
-
5、并行流
使得所有的中间转换操作都将被并行化,需要保证传给并行流的操作不存在竞争
-
Collections.parallelStream()将任何集合转为并行流
-
Stream.parallel()方法,产生一个并行流
IntStream s1 = IntStream.range(1, 100000); long evenNum = s1.parallel().filter(n->n%2==0).count();
-
-
6、其他类/方法产生Stream流
-
Files.lines方法
Stream<String> contents = Files.lines(Paths.get("abc.txt"));
-
Pattern的splitAsStream方法
Stream<String> words = Pattern.compile(",").splitAsStream("a,b,c");
-
3. 流的转换
3.1 过滤filter
接收一个Lambda表达式,对每个元素进行判断,符合条件留下
Stream<Integer> s = Stream.of(1,2,3,4,5).filter(n -> n>2);
3.2 去重distinct
对流的元素进行过滤,去除重复,只留下不重复的元素
Stream<Integer> s = Stream.of(1,2,3,4,5).distinct();
对象的判断,先调用hashCode方法,再调用equals方法
3.3 排序sorted
-
对流的基本类型包装类元素进行排序
Stream<Integer> s = Stream.of(1,2,3,4,5).sorted();
-
提供Comparator,对流的元素进行排序
Stream.of(planets).sorted(Comparator.comparing(String::length));
-
对流的自定义对象元素进行排序,调用对象的compareTo方法
3.4 转化
-
1、map
-
利用Lambda表达式对流的每个元素进行函数计算
Stream<Integer> s = Stream.of(1,2,3,4,5).map(n->n*n);
-
利用方法引用,对流每个元素进行函数计算并返回Stream
Stream<Stream<String>> allLetters = Stream.of(planets).map(word->letters(word));
-
利用方法引用,对流每个元素进行函数计算返回Stream,并合并
Stream<String> allLetters = Stream.of(planets).flatMap(word->letters(word))
flatMap执行一对多的转换,然后将所有的Map都展开。
-
-
2、抽取limit
Stream<Integer> s = Stream.of(1,2,3,4,5).limit(3);
-
3、跳过skip
Stream<Integer> s = Stream.of(1,2,3,4,5).skip(3);
-
4、连接concat
Stream<String> s = Stream.concat(s1, s2);
-
5、额外调试peek
Stream<Double> s = Stream.iterate(1.0, n->n*2).peek(n->System.out.println(n)).limit(5);
3.5 总结
- 流的转换从要给流得到另外一个流
- 一个流只能使用一次
- 转换过程,需要使用类本身的方法,如compareTo,hashCode,equals等方法
4. Optional类型
optionnal
4.1 创建
- of方法
- empty方法
- ofNullable方法,对于对象有可能为null情况,安全创建
4.2 使用
直接使用get方法,容易引发NoSuchElementException一场
5. 流的计算
5.1 简单约简(聚合函数)
- count(),计数
- max(Comparator),最大值
- min(Comparator),最小值
- findFirsrt,找到第一个元素
- findAny(),找到任意一个元素
- anyMatch(Predicate),任意元素满足条件返回true
- allMatch(Predicate),所有元素满足条件返回true
- noneMatch(Predicate),没有元素满足条件返回true
5.2 自定义约简
-
reduce,传递一个二元函数BinaryOperator,对流元素进行计算,如求和、求积、字符串连接等
Optional<Integer> sum = s.reduce(Integer::sum); Optional<Integer> product = s1.reduce((x,y)->x*y); Optional<Integer> product1 = s2.reduce(1, (x,y)->x*y);
5.3 查看/遍历元素
- iterator(),遍历元素,返回迭代器
- forEach(Consumer),应用一个函数到每个元素上
5.4 存放到数据结构中
- toArray
- collect(Collectors.toList())
- collect(Collectors.toSet())
- collect(Collectors.toMap())
- collect(Collectors.joining()),将结果连起来
5.5 高阶计算
- 分组groupingBy和分区partitionBy
- 分组后的约简
- counting
- summing
- maxBy
- minBy
5.6 总结
- 流的最终运算结果
- 惰性计算,启动先前的转换环节
- 三种结果:约简、遍历/查看、转存为其他的数据结构
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现