Stream类全路径为:java.util.stream.Stream
Stream简介
Java 8 中的 Stream 是对(Collection)集合对象功能的增强,它专注于对集合对象进行各种非常便利、高效的聚合操作
或大批量数据操作。Stream API 借助于同样新出现的 Lambda 表达式,极大的提高编程效率和程序可读性。
Stream原理
这种编程风格将要处理的元素集合看作一种流,流在管道中传输,并且可以在管道的节点上进行处理,比如筛选,排序,聚合等。
元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的
结果。
Stream优点
(1)速度更快
(2)代码更少(增加了新的语法Lambda表达式)
(3)强大的Stream API
(4)便于并行
(5)最大化减少了空指针异常Optional
Stream的操作三个步骤:
(1)创建Stream,一个数据源(如:集合、数组),获取一个流;
(2)中间操作,一个中间操作链,对数据源的数据进行处理;
(3)终止操作,一个终止操作,执行中间操作链,并产生结果。
集合有两种方式生成流:
stream() − 为集合创建串行流。
parallelStream() − 为集合创建并行流
-Stream的的中间操作(intermediate)和最终操作(terminal)都包含的方法:
1.中间操作(intermediate)主要有以下方法(此类型的方法返回的都是Stream对象):
方法名 | 说明 |
---|---|
map | 将对应的元素使用给定方法进行转换 |
mapToInt(mapToLong,mapToDouble) | 将对应的元素使用给定方法进行转换(返回类型必须是 int,long,double) |
flatMap | 如果流的元素为数组或者Collection,flatMap就是将每个Object[]元素或Collection<Object>元素都转换为Object元素 |
filter | 通过设置条件来过滤元素 |
distinct | 集合中的元素去重 |
sorted | 将集合中的元素排序 |
peek | 生成一个包含原Stream的所有元素的新Stream,同时会提供一个消费函数即引用的方法A,当Stream每个元素被消费的时候都会先执行新Stream给定的方法A。peek是中间操作,如果pee后没有最终操作,则peek不会执行 |
limit | 返回Stream的前n个元素 |
skip | 删除Stream的前n个元素 |
2.终端操作(terminal)主要有以下方法:
方法名 | 说明 |
---|---|
forEach | 遍历Stream中的每个元素 |
forEachOrdered | 遍历Stream中的每个元素 区别: 在串行流(stream)中没有区别,在并行流(parallelStream)中如果数据源是有序集合,forEachOrdered输出顺序与数据源中顺序一致,forEach则是乱序。 |
toArray | 将流转换为Object[]或者指定类型的数组 |
reduce | 将集合中的每个元素聚合成一条数据 |
collect | 将流转换成集合或聚合元素 |
min | 获取集合中最小值 |
max | 获取集合中最大值 |
count | 获取集合中元素个数 |
anyMatch | Stream 中任意一个元素符合传入的 predicate,返回 true |
allMatch | Stream 中全部元素符合传入的 predicate,返回 true |
noneMatch | Stream 中没有一个元素符合传入的 predicate,返回 true |
findFirst | 如果数据源是有序集合,返回Stream 中第一个元素的Optional对象,如果是无序集合,则返回Stream 中任意一个元素的Optional对象。 |
findAny | 返回Stream 中任意一个元素的Optional对象。 |
iterator | 返回一个无限元素的有序的Stream对象。 |
builder | 返回一个Builder对象,Builder对象在调用build()返回Stream对象。 |
empty | 返回一个空的有序的Stream对象。 |
of | 返回包含单个元素的有序的Stream对象。 |
generate | 返回一个无限元素的无序的的Stream对象。 |
concat | 将两个Stream连接成一个Stream。 |
方法演示
中间操作(intermediate)
1.filter : 通过设置条件来过滤元素。
List<String> list = Arrays.asList("aaa","ddd","bbb","ccc","a2a","d2d","b2b","c2c","a3a","d3d","b3b","c3c");
list.stream().filter((s)->s.contains("a")).forEach(s -> System.out.println(s));
以上代码使用filter方法过滤出只包含”a”的元素,然后通过forEach将满足条件的元素遍历出来。输出如下:
aaa
a2a
a3a
2.map : 就是将对应的元素使用给定方法进行转换。
List<String> list = Arrays.asList("aaa","ddd","bbb","ccc","a2a","d2d","b2b","c2c","a3a","d3d","b3b","c3c");
list.stream().filter((s)->s.contains("a")).map((s)-> s + "---map").forEach(s -> System.out.println(s));
在filter的基础上,给每个元素后面添加字符串”—map”,输出如下:
aaa—map
a2a—map
a3a—map
3.flatMap:如果流的元素为数组或者Collection,flatMap就是将每个Object[]元素或Collection<Object>元素都转换为Object元素。
List<String[]> setList = new ArrayList<>();
setList.add(new String[]{"aa","bb"});
setList.add(new String[]{"cc","dd"});
setList.add(new String[]{"ee","ff"});
//使用map方法
setList.stream().map(s->Arrays.stream(s)).forEach(s-> System.out.println("map==" + s));
//使用flatMap方法
setList.stream().flatMap(s->Arrays.stream(s)).forEach(s-> System.out.println("flatMap==" + s));
输出如下:
map==java.util.stream.ReferencePipeline&Head@50040f0c
map==java.util.stream.ReferencePipeline&Head@2dda6444
map==java.util.stream.ReferencePipeline&Head@5e9f23b4
flatMap==aa
flatMap==bb
flatMap==cc
flatMap==dd
flatMap==ee
flatMap==ff
map就是将数组流直接返回,flatMap是将数组流中的每个元素都返回。
4.distinct:将集合中的元素去重。
List<String> disList = Arrays.asList("aaa","ddd","bbb","ddd","aaa");
disList.stream().distinct().forEach(s-> System.out.println(s));
输出如下:
aaa
ddd
bbb
5.sorted:将集合中的元素排序。
List<Integer> integerList = Arrays.asList(2,4,1,3);
integerList.stream().sorted().forEach(s-> System.out.println(s));
输出如下:
1
2
3
4
可以按照自定义排序:
List<Integer> integerList = Arrays.asList(2,4,1,3);
integerList.stream().sorted((s1,s2)->s2.compareTo(s1)).forEach(s-> System.out.println(s));
输出如下:
4
3
2
1
6.peek:生成一个包含原Stream的所有元素的新Stream,同时会提供一个消费函数即引用的方法A,当Stream每个元素被消费的时候都会先
执行新Stream给定的方法A。peek是中间操作,如果peek后没有最终操作,则peek不会执行。
List<Integer> integerList = Arrays.asList(1,2,3,4);
integerList.stream().peek(s-> System.out.println("peek = "+s)).forEach(s-> System.out.println("forEach = "+s));
输出如下:
peek = 1
forEach = 1
peek = 2
forEach = 2
peek = 3
forEach = 3
peek = 4
forEach = 4
7.limit:返回Stream的前n个元素。
List<Integer> integerList = Arrays.asList(1,2,3,4);
integerList.stream().limit(2).forEach(s-> System.out.println(s));
输出为:
1
2
8.skip:删除Stream的前n个元素。
List<Integer> integerList = Arrays.asList(1,2,3,4);
integerList.stream().skip(2).forEach(s-> System.out.println(s));
输出如下:
3
4
终端操作(terminal)
1.forEach:遍历Stream中的每个元素,前面每个例子都有使用,此处不再演示。
List<Integer> integerList = Arrays.asList(1,2,3,4);
integerList.stream().skip(2).forEach(s-> System.out.println(s));
输出为:
1
2
3
4
2.forEachOrdered:遍历Stream中的每个元素。
区别: 在串行流(stream)中没有区别,在并行流(parallelStream)中如果数据源是有序集合,forEachOrdered输出顺序与数据源中顺序
一致,forEach则是乱序。
List<Integer> integerList = Arrays.asList(1,2,3,4);
integerList.parallelStream().forEachOrdered(s-> System.out.println(s));
输出(测试多次,每次都是这个结果,与integerList中的元素顺序一致):
1
2
3
4
3.toArray:将流转换为Object[]或者指定类型的数组。
List<Integer> integerList = Arrays.asList(1,2,3,4);
Object[] array = integerList.stream().toArray();
String[] strArr = integerList.stream().toArray(String[]::new);
Stream中的toArray普通情况下和集合中的toArray没什么区别,但是Stream中的toArray转换为指定类型的数组。
4.reduce:将集合中的每个元素聚合成一条数据。有三种情况:
reduce(BinaryOperator accumulator):此处需要一个参数,返回Optional对象:
Optional<Integer> reduce = integerList.stream().reduce((a, b) -> a + b);
reduce(T identity, BinaryOperator accumulator):此处需要两个参数,第一个参数为起始值,第二个参数为引用的方法。从起始值开始,
每个元素执行一次引用的方法(方法引用的中的两个参数:第一个参数为上个元素执行方法引用的结果,第二个参数为当前元素)。
List<Integer> integerList = Arrays.asList(1,2,3,4);
int integer = integerList.stream().reduce(5,(a, b) -> a + b);
System.out.println(integer);
输出为:
15
此例中使用起始值为5,对集合中每个元素求和,可以理解为:5+1+2+3+4=15。
reduce:此处需要三个参数。此方法用在
并发流(parallelStream)中,启动多个子线程使用accumulator进行并行计算,最终使用combiner对子线程结果进行合并,返回identity类
型的数据。
5.collect:将流转换成集合或聚合元素。有两种情况。接受一个参数和接受三个参数(三个参数在并发流parallelStream中使用),此处介绍一个参数的情况,单个参数接受的参数类型为Collector,Collectors 类实现了很多归约操作
List<Integer> integerList = Arrays.asList(2,4,1,3);
List<Integer> integers = integerList.stream().filter(s -> s > 1).collect(Collectors.toList());
System.out.println(integers.toString());
此处统计集合中大于1的元素并最终返回list。输出如下:
[2, 4, 3]
6.min:获取集合中最小值。
List<Integer> integerList = Arrays.asList(2,4,1,3);
Integer min = integerList.stream().min(Integer::compareTo).get();
System.out.println(min);
输出为:
1
7.max:获取集合中最大值。
List<Integer> integerList = Arrays.asList(2,4,1,3);
Integer max = integerList.stream().max(Integer::compareTo).get();
System.out.println(max);
8.count:获取集合中元素个数
List<Integer> integerList = Arrays.asList(2,4,1,3);
long count = integerList.stream().count();
System.out.println(count);
输出为:
4
---------------------------------------- ----- CJZ ------ ------------------------------------------
举例
设有一组用户信息(userInfo:包含 姓名(name) 性别(sex) 年龄(age)),将这些用户信息分成 男和女 存入Map(key:sex values:List<userInfo>)中.
准备数据
UserInfo实体类
class UserInfo {
private String name;
private String sex;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "UserInfo{" +
"name='" + name + '\'' +
", sex='" + sex + '\'' +
", age=" + age +
'}';
}
}
获取用户信息
public List<UserInfo> buildUserInfoList(){
Random ra =new Random();
List<UserInfo> userInfoList = new ArrayList<>();
String first="赵钱孙李周吴郑王冯陈褚卫蒋沈韩杨朱秦尤许何吕施张孔";
String boy="伟刚勇毅俊峰强军平保东文辉力明永健世广志义兴良海山仁";
for (int i=0; i<10;i++){
UserInfo userInfo = new UserInfo();
int sum1 = ra.nextInt(first.length());
int sum2 = ra.nextInt(boy.length());
userInfo.setName(first.substring(sum1,sum1+1)+boy.substring(sum2,sum2+1));
userInfo.setSex(sum1%2==0 ? "男":"女");
userInfo.setAge(ra.nextInt(100));
userInfoList.add(userInfo);
}
return userInfoList;
}
代码实现
普通实现方式
public void userInfoClassify(){
List<UserInfo> userInfoList = buildUserInfoList();
Map<String, List<UserInfo>> map = new HashMap();
List<UserInfo> male =new ArrayList<>();
List<UserInfo> female =new ArrayList<>();
for (UserInfo userInfo:userInfoList){
if("女".equals(userInfo.getSex())){
female.add(userInfo);
}else ("男".equals(userInfo.getSex())){
male.add(userInfo);
}
}
map.put("男",male);
map.put("女",female);
}
stream实现方式
public void userInfoClassifyStream() {
List<UserInfo> userInfoList = buildUserInfoList();
Map<String, List<UserInfo>> collect = userInfoList.stream().collect(Collectors.groupingBy(UserInfo::getSex));
}
map 推荐遍历方式
for (Map.Entry<String, List<UserInfo>> entry : map.entrySet()) {
System.out.println("key:"+entry.getKey()+",value:"+entry.getValue());
}