Java 8 Stream常用方法学习
Stream基础概念
Stream流是 Java8 API 新增的一个处理集合的关键抽象概念,是一个来自数据源的元素队列并支持聚合操作。以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询。也可以使用 Stream API 来并行执行操作。简而言之,Stream API 提供了一种高效且易于使用的处理数据的方式。
相关名词 | 描述 |
---|---|
元素 | 对象形成的一个队列。 Java中的Stream并不会存储元素,而是按需计算。 |
数据源 | 是流Stream的来源。 可以是集合、数组、I/O channel、 产生器generator 等 |
聚合操作 | 类似SQL语句一样的操作,比如filter, map, reduce, find, match, sorted等。 |
内部迭代 | 中间操作都会返回流对象本身。 这样多个操作可以串联成一个管道, 如同流式风格(fluent style)。 这样做可以对操作进行优化, 比如延迟执行(laziness)和短路( short-circuiting)。 |
Pipelining | 以前对集合遍历都是通过Iterator或者For-Each的方式, 显式的在集合外部进行迭代, 这叫做外部迭代。 Stream提供了内部迭代的方式, 通过访问者模式(Visitor)实现。 |
Stream的特点:
- Stream不是什么数据结构,它不会保存数据,只是将操作的数据结果保存到另一个对象中。
- Stream是惰性求值的(延迟执行),在中间处理的过程中,只对操作进行记录,并不会立即执行,只有等到执行终止操作的时候才会进行实际的计算,这时候中间操作才会执行。
- 可以把Stream当成一个高级版本的Iterator来使用。(原始版本的Iterator,只能一个个的遍历操作)
1. 分类
Stream操作分类 | 作用描述 | 常用方法 |
---|---|---|
无状态 | 中间操作, 该操作不受之前元素的影响 | unordered、filter、map、mapToInt、mapToLong、mapToDouble、flatMap、flatMapToInt、flatMapToLongg、flatMapToDouble、peek |
有状态 | 中间操作,该操作只有拿到所有元素之后才能继续执行 | distinct、sorted、limit、skip |
非短路操作 | 结束操作 , 必须处理所有元素才能得到最终结果 | forEach、forEachOrdered、toArray、collect、max、min、count、reduce |
短路操作 | 结束操作 , 遇到某些符合条件的元素就可以得到最终结果 | anyMatch、allMatch、noneMatch、findFirsh、findAny |
2. 常用方法
初始化一个String类型的List集合
List<String> stringList = Arrays.asList("a","b", "", "", "c", "", "a", "d","e","a");
System.out.println("字符串集合:" + stringList);
- 1
- 2
运行结果:
字符串集合:[a, b, , , c, , a, d, e, a]
创建JavaBean对象User,初始化一个User列表
@Data
class User{
String name;
String description;
}
List<User> userList = new ArrayList<>(
Arrays.asList(
new User("strive", "努力"),
new User("fighter", "奋斗"),
new User("lucky", "幸运"),
new User("lucky", "幸运222")
)
);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
运行结果:
[User{name=‘strive’, description=‘努力’}, User{name=‘fighter’, description=‘奋斗’}, User{name=‘lucky’, description=‘幸运’}, User{name=‘lucky’, description=‘幸运222’}]
2.1 forEach
forEach方法用于迭代遍历每个数据
//迭代遍历输出
stringList.forEach(str ->{
System.out.print(str + " ");
});
- 1
- 2
- 3
- 4
运行结果:
a b c a d e a
2.2 filter
使用 filter
按照设置的条件过滤元素,得到满足条件的元素。
//获取stringList中非空字符串的集合
List<String> collect = stringList.stream().filter(str -> !str.isEmpty())
.collect(Collectors.toList());
System.out.println("非空字符串集合:" + collect);
- 1
- 2
- 3
- 4
运行结果:
非空字符串集合:[a, b, c, a, d, e, a]
count()
方法,用来统计数量
long emptyStrNum = stringList.stream().filter(str -> str.isEmpty()).count();
System.out.println("空字符串数量 = " + emptyStrNum);
- 1
- 2
运行结果:
空字符串数量 = 3
2.3 distinct
distinct() 方法用于去重
//获取stringList中非空字符串的集合 去重后 转化为list集合
List<String> collect3 = stringList.stream().filter(str -> !str.isEmpty()).distinct()
.collect(Collectors.toList());
System.out.println("去重后字符串集合:" + collect3);
//提取出userList对象中的属性name并去重
List<String> nameList = userList.stream().map(User::getName).distinct().collect(Collectors.toList());
System.out.println("nameList = " + nameList);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
运行结果:
去重后字符串集合:[a, b, c, d, e]
nameList = [strive, fighter, lucky]
2.4 Collectors - (Collector工具库)
Collectors
类中实现了很多的规约操作(可用于返回列表或字符串)
最常用的是将流转换为 集合或聚合元素对象
2.4.1 Collectors.toList()方法将Stream转化为List对象
//查找非空、去重后通过 Collectors.toList() 转化为List列表
List<String> strList = stringList.stream().filter(str -> !str.isEmpty())
.distinct().collect(Collectors.toList());
System.out.println("strList = " + strList);
- 1
- 2
- 3
- 4
运行结果:
strList = [a, b, c, d, e]
2.4.2 Collectors.toSet()方法将Stream转化为Set对象
//通过 Collectors.toSet() 方法转化为set列表
//set集合,不去重也输出相同的结果(set中不会有重复的元素)
Set<String> strSet = stringList.stream().filter(str -> !str.isEmpty())
.collect(Collectors.toSet());
System.out.println("strSet = " + strList);
- 1
- 2
- 3
- 4
- 5
运行结果:
strSet = [a, b, c, d, e]
2.4.3 Collectors.toMap()方法将Stream转化为Map对象
Collector<T, ?, M> toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper,BinaryOperator mergeFunction,Supplier mapSupplier)
- 1
参数1: keyMapper 用来生成key值的。
参数2: valueMapper 用来生成value值的。
参数3: mergeFunction 用在key值冲突的情况下使用(可省略),如果新元素产生的key在Map中已经出现过了,第三个参数就会定义解决的办法。
参数4:mapSupplier 默认返回的map类型为hashMap,可以按自己的需要自己返回不同的map实现。( 可省略 )
主要举个3个参数的案例来说明:
Collectors.toMap(keyMapper, valueMapper, mergeFunction)
- 1
该toMap()方法有三个参数.
比如
collect Collectors.toMap(User::getName, i -> i, (v1, v2) -> v1)
第一个参数
User::getName
表示选择User对象的的getName方法获取的值作为map的key值;第二个参数
i -> i
表示选择将原来的对象作为map的value值(这里的i只是对遍历对象取的别名)第三个参数
(v1, v2) -> v1
,当出现key值相同时(也就是如果v1与v2的key值相同),选择前面的 也就是v1 作为那个key所对应的值,**就是出现相同key时,谁覆盖谁的问题 **
- 点赞
- 收藏
- 关注作者
评论(0)