JDK8新特性:Stream语法详解
大家可以把Stream当成一个高级版本的Iterator。原始版本的Iterator,用户只能一个一个的遍历元素并对其执行某些操作;高级版本的Stream,用户只要给出需要对其包含的元素执行什么操作,比如“过滤掉长度大于10的字符串”、“获取每个字符串的首字母”等,具体这些操作如何应用到每个元素上,就给Stream就好了!(这个秘籍,一般人我不告诉他:)。
先看如下几个例子:
List<Integer> nums = Lists.newArrayList(1,null,3,4,null,6);
nums.stream().filter(num -> num != null).count();
list.stream()
.filter(student -> student.getSex().equals("G"))
.forEach(student -> System.out.println(student.toString()));
List<String> lastStoneList =
stoneLine.stream()
.filter(s -> s.getWeight() < 500)//挑选出质量小于500g的鹅卵石
.sorted(comparing(Stone::getWeight))//按照质量进行排序
.map(Stone::getName)//提取满足要求的鹅卵石的名字
.collect(toList());//将名字保存到List中
---------------------
- 创建Stream;
- 转换Stream,每次转换原有Stream对象不改变,返回一个新的Stream对象(**可以有多次转换**);
- 对Stream进行聚合(Reduce)操作,获取想要的结果;
2.1 使用Stream静态方法来创建Stream的三种方法:
1. of方法:有两个overload方法,一个接受变长参数,一个接口单一值
Stream<Integer> integerStream = Stream.of(1, 2, 3, 5);
Stream<String> stringStream = Stream.of("taobao");
2. generator方法:生成一个无限长度的Stream,其元素的生成是通过给定的Supplier(这个接口可以看成一个对象的工厂,每次调用返回一个给定类型的对象)
Stream.generate(() -> Math.random());
Stream.generate(Math::random);
3. iterate方法:也是生成无限长度的Stream,和generator不同的是,其元素的生成是重复对给定的种子值(seed)调用用户指定函数来生成的。其中包含的元素可以认为是:seed,f(seed),f(f(seed))无限循环。
Stream.iterate(
1
, item -> item +
1
).limit(
10
).forEach(System.out::println);
3. 转换Stream:
转换Stream其实就是把一个Stream通过某些行为转换成一个新的Stream。Stream接口中定义了几个常用的转换方法,下面我们挑选几个常用的转换方法来解释。
1. distinct: 对于Stream中包含的元素进行去重操作(去重逻辑依赖元素的equals方法),新生成的Stream中没有重复的元素;
2. filter: 对于Stream中包含的元素使用给定的过滤函数进行过滤操作,新生成的Stream只包含符合条件的元素;
3. map: 对于Stream中包含的元素使用给定的转换函数进行转换操作,新生成的Stream只包含转换生成的元素。这个方法有三个对于原始类型的变种方法,分别是:mapToInt,mapToLong和mapToDouble。
4. flatMap:和map类似,不同的是其每个元素转换得到的是Stream对象,会把子Stream中的元素压缩到父集合中;
5. peek: 生成一个包含原Stream的所有元素的新Stream,同时会提供一个消费函数(Consumer实例),新Stream每个元素被消费的时候都会执行给定的消费函数;
6. limit: 对一个Stream进行截断操作,获取其前N个元素,如果原Stream中包含的元素个数小于N,那就获取其所有的元素;
7. skip: 返回一个丢弃原Stream的前N个元素后剩下元素组成的新Stream,如果原Stream中包含的元素个数小于N,那么返回空Stream;
Stream的类型和创建方式2:
// 从数组创建
int [] source = {1,2,3,4,5,6};
IntStream s = Arrays.stream(source);
// 从集合创建
List list = Arrays.asList(1,2,3,4,5);
Stream s2 = list.stream();
// 创建1到10的流
IntStream s3 = IntStream.range(1,10);
// 直接创建
Stream s4 = Stream.of("wo", "ai", "?")
// 支持串行并行操作的序列,元素只有double,int,Long类型的流 DoubleStream,IntStream,LongStream。
案例:
// 将元素中的所有偶数累加求和
int[] nums = {2, 3, 4, 5, 6};
System.out.println(
Arrays.stream(nums)
.map(i -> i % 2 == 0 ? i : 0)
.reduce(0, Integer::sum)
);
// flatMap处理嵌套的list List<List<Integer>> ll = Arrays.asList( Arrays.asList(1, 2, 3), Arrays.asList(11, 22, 33), Arrays.asList(0xF1, 0xF2, 0xF3) ); ll.stream() .flatMap(list -> list.stream()) .map(i -> 2 * i) .forEach(i -> System.out.println(i));
案例三:假设有N条营业数据,前5条是无关的测试数据,中间10条是要参加考核的,参与考核的需要知道其中超过50w(包括50)的数据的交易额平均值,其他不参与考核的忽略
Stream<Integer> trans = Stream.of(11, 9, 2, 13, 1, 2, 99, 54, 23, 66, 70, 23, 46, 50, 100, 10, 24, 18, 19, 2);
IntSummaryStatistics all = trans
// 前5条跳过,2, 99, 54, 23, 66, 70, 23, 46, 50, 100, 10, 24, 18, 19, 2
.skip(5)
// 取10条考核交易 2, 99, 54, 23, 66, 70, 23, 46, 50, 100
.limit(10)
// 将50以下的交易剔除 99, 54, 66, 70, 50, 100
.filter(i -> i >= 50)
// 转换成数字。如果是IntStream 则不需要转换
.mapToInt(i->i)
// 将流的统计结果放入包装对象中
.summaryStatistics();
// 交易总量 439w,平均值为439/6
System.out.println(all.getAverage());
Stream流的特性:
1.不能重复使用。
Stream<Integer> trans = Stream.of(11, 9, 2);
trans.forEach(i -> System.out.println(i));
trans.reduce(0, Integer::sum);
当我第二次使用trans时,报错了。

2.验证流延迟操作:流只要在终止操作(及早求值)时,才会对数据统一做操作,在没有遇到求值操作的时候,惰性操作代码不会被执行。
Stream<Integer> trans = Stream.of(11, 70, 23, 46, 50, 100, 10, 24, 18, 19, 2);
trans.map(i->{
System.out.println(i);
return i;
});

3.不影响源数据。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器