stream是jdk1.8引入的一个新概念,把列表流stream化,然后再加工成我们想要的列表或者别的数据
我们经常会对列表list数据用for循环,用stream来替换for循环会更简洁。
参考网友的图,我觉得这张图描述的很清楚,steam可以不断进行加工
1.集合中的方法都有stream(),使用stream()把集合进行流化,例如 list.stream(),流化后可以使用stream的中间操作符和终止操作符,即使用stream提供的api处理集合。
2.中间操作符就是Lambda表达式的链式操作,可以链式对流进行操作,操作完后还是返回流
3.终止操作符就是用来结束流的,数据经过中间加工操作,最后通过终止操作符对数据进行收集或者消费的,数据到了终止操作这里就不会向下流动了,终止操作符只能使用一次
filter
可以通过 filter 方法将一个流转换成另一个子集流
map
可以通过map 方法将一个流映射成另一个流
sort
在流里面进行排序
limit
限制流,例如只取前流的前几个元素
skip
跳过操作,例如跳过流的前几个元素
count
统计个数,正如旧集合 Collection 当中的 size 方法一样,流提供 count 方法来数一数其中的元素个数
例如下面有一个列表数据,我们要把列表按创建时间来 分组(按年月格式分组)、倒叙,来获取一个分组后的集合
按年月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;
}
}
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);
}
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)