stream是jdk1.8引入的一个新概念,把列表流stream化,然后再加工成我们想要的列表或者别的数据
我们经常会对列表list数据用for循环,用stream来替换for循环会更简洁。
参考网友的图,我觉得这张图描述的很清楚,steam可以不断进行加工
Stream的api大体上分为两种:中间操作符和终止操作符
1.集合中的方法都有stream(),使用stream()把集合进行流化,例如 list.stream(),流化后可以使用stream的中间操作符和终止操作符,即使用stream提供的api处理集合。
2.中间操作符就是Lambda表达式的链式操作,可以链式对流进行操作,操作完后还是返回流
3.终止操作符就是用来结束流的,数据经过中间加工操作,最后通过终止操作符对数据进行收集或者消费的,数据到了终止操作这里就不会向下流动了,终止操作符只能使用一次
中间操作符:
- filter
可以通过 filter 方法将一个流转换成另一个子集流 - map
可以通过map 方法将一个流映射成另一个流 - sort
在流里面进行排序 - limit
限制流,例如只取前流的前几个元素 - skip
跳过操作,例如跳过流的前几个元素 - count
统计个数,正如旧集合 Collection 当中的 size 方法一样,流提供 count 方法来数一数其中的元素个数
终止操作符:
- collect
收集操作,将所有数据收集起来,Stream 的核心在于Collectors,常用的Collectors.toSet()、Collectors.toList()、Collectors.groupingBy()。 - count
统计操作,统计最终的数据个数。 - findFirst、findAny
查找操作,查找第一个、查找任何一个 返回的类型为Optional。 - noneMatch、allMatch、anyMatch
匹配操作,数据流中是否存在符合条件的元素 返回值为bool 值。 - min、max
最值操作,需要自定义比较器,返回数据流中最大最小的值。 - reduce
规约操作,将整个数据流的值规约为一个值,count、min、max底层就是使用reduce。 - forEach、forEachOrdered
遍历操作,这里就是对最终的数据进行消费了。 - toArray
数组操作,将数据流的元素转换成数组。
实战demo
例如下面有一个列表数据,我们要把列表按创建时间来 分组(按年月格式分组)、倒叙,来获取一个分组后的集合
按年月yyyy-MM格式分组
public List<User> initData(){
List<User> userList = new ArrayList<>();
User user1 = new User(1,"测试1","2019-12-27 11:33:48");
User user2 = new User(2,"测试2","2020-01-21 11:33:48");
User user3 = new User(3,"测试3","2020-02-21 11:32:48");
User user4 = new User(4,"测试4","2020-02-21 11:31:48");
User user5 = new User(5,"测试5","2020-01-23 10:33:48");
userList.add(user1);
userList.add(user2);
userList.add(user3);
userList.add(user4);
userList.add(user5);
return userList;
}
@Data
public static class User{
int id;
String name;
String creteTime;
public User(int id,String name,String creteTime){
this.id = id;
this.name = name;
this.creteTime = creteTime;
}
}
方式一:使用for循环
List<Map<String,Object>> newListGroupByMonth = new ArrayList<>();
//按月分组
Set<String> yearMonthList = new TreeSet<>(new Comparator(){
@Override
public int compare(Object element1, Object element2) {//按时间倒叙
int result = element2.toString().compareTo(element1.toString());
return result;
}
});
//获取月份数组
for(User user : userList){
String createTime = dataformat(user.getCreteTime(), "yyyy-MM");
yearMonthList.add(createTime);
}
//根据月份分组,获取每个月份的列表数据
for(String yearMonth : yearMonthList){
//每个月份的数据列表
List<User> users = new ArrayList<>();
for(User user : userList){
String createTime = dataformat(user.getCreteTime(), "yyyy-MM");
if(yearMonth.equals(createTime)){
users.add(user);
}
}
Map<String,Object> data = new HashMap<>();
data.put("yearMonth",yearMonth);
data.put("list",users);
newListGroupByMonth.add(data);
}
方式二:使用stream
List<Map<String,Object>> newListGroupByMonth = userList.stream()
.map(m->dataformat(m.getCreteTime(),"yyyy-MM"))
.sorted( (element1, element2)->element2.toString().compareTo(element1.toString()))
.collect(Collectors.toSet())
.stream()
.map(yearMonth->{
//按月分组
List curUserList = userList.stream().filter(user->yearMonth.equals(dataformat(user.getCreteTime(),"yyyy-MM"))).collect(Collectors.toList());
Map<String,Object> data = new HashMap<>();
data.put("yearMonth",yearMonth);
data.put("list",curUserList);
return data;
}).collect(Collectors.toList());
可以看到使用stream方式没有用到for循环,代码也简洁了不少
上面的代码运行起来看到实现的功能都是一样的,都是把列表进行按月分组
注:
要是时间都是年月yyyy-MM这种格式的话,可以直接使用Collectors.groupingBy(User::getCreateTime)分组
上述demo的所有代码
public class StreamTest {
/**
* 使用for循环
*/
@Test
public void TestByFor() {
List<User> userList = initData();
/****************方式一start:for循环**********************/
List<Map<String,Object>> newListGroupByMonth = new ArrayList<>();
//按月分组
Set<String> yearMonthList = new TreeSet<>(new Comparator(){
@Override
public int compare(Object element1, Object element2) {//按时间倒叙
int result = element2.toString().compareTo(element1.toString());
return result;
}
});
//获取月份数组
for(User user : userList){
String createTime = dataformat(user.getCreteTime(), "yyyy-MM");
yearMonthList.add(createTime);
}
//根据月份分组,获取每个月份的列表数据
for(String yearMonth : yearMonthList){
//每个月份的数据列表
List<User> users = new ArrayList<>();
for(User user : userList){
String createTime = dataformat(user.getCreteTime(), "yyyy-MM");
if(yearMonth.equals(createTime)){
users.add(user);
}
}
Map<String,Object> data = new HashMap<>();
data.put("yearMonth",yearMonth);
data.put("list",users);
newListGroupByMonth.add(data);
}
/****************方式一end:for循环**********************/
printData(newListGroupByMonth);
}
/**
* 使用stream
*/
@Test
public void TestByStream() {
List<User> userList = initData();
/****************方式二start:stream**********************/
List<Map<String,Object>> newListGroupByMonth = userList.stream()
.map(m->dataformat(m.getCreteTime(),"yyyy-MM"))
.sorted( (element1, element2)->element2.toString().compareTo(element1.toString()))
.collect(Collectors.toSet())
.stream()
.map(yearMonth->{
List curUserList = userList.stream().filter(user->yearMonth.equals(dataformat(user.getCreteTime(),"yyyy-MM"))).collect(Collectors.toList());
Map<String,Object> data = new HashMap<>();
data.put("yearMonth",yearMonth);
data.put("list",curUserList);
return data;
}).collect(Collectors.toList());
/****************方式二end:stream**********************/
printData(newListGroupByMonth);
}
/**
* 初始化数据
* @return
*/
public List<User> initData(){
List<User> userList = new ArrayList<>();
User user1 = new User(1,"测试1","2019-12-27 11:33:48");
User user2 = new User(2,"测试2","2020-01-21 11:33:48");
User user3 = new User(3,"测试3","2020-02-21 11:32:48");
User user4 = new User(4,"测试4","2020-02-21 11:31:48");
User user5 = new User(5,"测试5","2020-01-23 10:33:48");
userList.add(user1);
userList.add(user2);
userList.add(user3);
userList.add(user4);
userList.add(user5);
return userList;
}
/**
* 打印列表数据
* @param newListGroupByMonth
*/
public void printData(List<Map<String,Object>> newListGroupByMonth){
newListGroupByMonth.stream().forEach(m->{
System.out.println("当前月份:"+m.get("yearMonth"));
List<User> curUsers = (List<User>)m.get("list");
curUsers.stream().forEach(user-> System.out.println("id:"+user.getId()+",name:"+user.name+",createTime:"+user.getCreteTime()));
System.out.println("-------------------------------");
});
}
@Data
public static class User{
int id;
String name;
String creteTime;
public User(int id,String name,String creteTime){
this.id = id;
this.name = name;
this.creteTime = creteTime;
}
}
/**
* 格式化时间
*
* @param data
* @param format
* @return
*/
public static String dataformat(String data, String format) {
SimpleDateFormat sformat = new SimpleDateFormat(format);
Date date = null;
try {
date = sformat.parse(data);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return sformat.format(date);
}
}
参考Java 之 Stream 流玩转Java8Stream(一、从零认识Stream)