目录
1 Stream基本概念
1.1 什么是Stream
Stream与Lambda表达式同为Java8的新特性,是一个来自数据源的元素队列并支持聚合操作,通过对Stream的操作可以以类似写SQL的方式对Java集合进行包括筛选、排序、聚合等运算。
1.2 Stream的特点
(1)Stream不存储数据;
(2)Stream不会改变源数据;
(3)Stream经过运算后会根据运算的结果返回新的集合对象。
2 Stream API初体验
2.1 构造数据
在这里构造一个Integer类的集合,并添加元素,下面会分别以for循环与Stream API的方式找出其中大于10的元素并返回新的集合。
List<Integer> numList = new ArrayList<>();
Collections.addAll(numList, 1, 2, 3, 4, 5, 6, 10, 12, 14, 16, 18, 20, 100);
2.1 使用for循环实现
使用for循环可以采用将符合条件的元素写入新集合或者从原集合中删除不符合条件的元素,这里采用了前者。
private List<Integer> funByForeach(List<Integer> numList) {
List<Integer> returnList = new ArrayList<>();
for(Integer num : numList) {
if(num > 10) {
returnList.add(num);
}
}
return returnList;
}
2.2 使用Lambda表达式结合Stream API实现
使用Lambda表达式结合Stream API可以将代码精简至一行。
private List<Integer> funByStream(List<Integer> numList) {
return numList.stream().filter(num -> num > 10).collect(Collectors.toList());
}
3 创建Stream对象
3.1 根据数组创建Stream对象
String[] strArray = {"曹孟德", "刘备", "关羽", "张飞"};
Stream<String> stream = Arrays.stream(strArray);
3.2 根据多个值创建Stream对象
这个API在源码中实际上是调用了Arrays.stream方法。
Stream<String> stream = Stream.of("曹孟德", "刘备", "关羽", "张飞");
3.3 根据List或Set创建Stream对象
根据List与Set都是Collection的子类,调用了同样的API去创建Stream对象。
List<String> strList = new ArrayList<>();
Collections.addAll(strList, "曹孟德", "刘备", "关羽", "张飞");
Stream<String> stream = strList.stream();
Set<String> strSet = new HashSet<>();
Collections.addAll(strSet, "曹孟德", "刘备", "关羽", "张飞");
Stream<String> stream = strSet.stream();
3.4 根据Map创建Stream对象
Map<String, String> map = new HashMap<>();
map.put("曹孟德", "Cao Meng De");
map.put("刘备", "Liu Bei");
map.put("关羽", "Guan Yu");
map.put("张飞", "Zhang Fei");
Stream<Map.Entry<String, String>> stream = map.entrySet().stream();
4 根据Stream对象得到指定类型数据
Stream API所做的往往是将集合转为Stream,在Stream对象中对数据进行运算,根据运算后的Stream得到结果,所以在数据转为流后,会根据流对象再转为原来的数据类型对象。
4.1 Stream对象转数组
String[] strArray = {"曹孟德", "刘备", "关羽", "张飞"};
// 根据数组创建Stream
Stream<String> stream = Arrays.stream(strArray);
// 根据流得到数组
String[] resultArray = stream.toArray(String[]::new);
4.2 Stream对象中的元素拼接起来成字符串
// 创建流
Stream<String> stream = Stream.of("曹孟德", "刘备", "关羽", "张飞");
// 根据流得到拼接后的字符串
String resultStr = stream.collect(Collectors.joining());
4.3 Stream对象转List
List<String> strList = new ArrayList<>();
Collections.addAll(strList, "曹孟德", "刘备", "关羽", "张飞");
// 根据List创建Stream
Stream<String> stream = strList.stream();
// 根据Stream得到List
List<String> resultList = stream.collect(Collectors.toList());
4.4 Stream对象转Set
Set<String> strSet = new HashSet<>();
Collections.addAll(strSet, "曹孟德", "刘备", "关羽", "张飞");
// 根据Set创建Stream
Stream<String> stream = strSet.stream();
// 根据Stream得到Set
Set<String> resultSet = stream.collect(Collectors.toSet());
5 中间操作
在将集合或数组转换成流,再从流转为其他类型对象的过程中可以有中间操作,大多数时候我们使用流就是为了使用中间操作,这些中间操作可以对集合中的元素进行过滤、聚合等运算。
这里我们用List集合构造数据对中间操作进行测试,代码如下。
List<Integer> numList = new ArrayList<>();
Collections.addAll(numList,100, 50, 70, 150, 90, 1000, 99, 10);
5.1 过滤
上面构造的numList集合是一个Integer集合,下面的代码是过滤掉所有数值小于或等于100的元素,也就是留下数值大于100的元素。
numList = numList.stream().filter(num -> num > 100).collect(Collectors.toList());
5.2 skip
skip方法的参数是一个long类型,输入的参数值表示跳过的元素个数,比如集合长度为8,使用skip(2),会保留后面6个元素,而从流中删除前两个元素,并且这一操作是有状态的。如下代码所示。
// 此时集合中的元素为[70, 150, 90, 1000, 99, 10]
numList = numList.stream().skip(2).collect(Collectors.toList());
5.3 limit
这里的limit可以限制元素的数量,如果配合skip使用就类似sql语句中limit的用法了。如下代码所示。
// 此时集合中的元素为[70, 150, 90]
numList = numList.stream().skip(2).limit(3).collect(Collectors.toList());
5.4 distinct
是一个无参方法,与sql中distinct关键字的作用类似。
5.5 min
取集合中的最小值,用法如下。
// 这里minNum的值是10
Optional<Integer> optional = numList.stream().min((x, y) -> x - y);
Integer minNum = -1;
if(optional.isPresent()) {
minNum = optional.get();
}
5.6 max
取集合中的最大值,与min的用法类似。
// 这里minNum的值是1000
Optional<Integer> optional = numList.stream().max((x, y) -> x - y);
Integer minNum = -1;
if(optional.isPresent()) {
minNum = optional.get();
}