什么是stream
stream是Java8 中的一个新特性,它主要能让开发人员用函数式编程的方式(如Lamba表达式)对集合做聚合操作。所谓的聚合操作就是对集合的查找、遍历、过滤以及常见计算等。
下面是stream的一些常见操作介绍:
foreach:循环操作
Random random = new Random();
random.ints().limit(10).forEach(System.out::println);
map:将每一个元素映射到相应的结果里
List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
//get list of unique squares
List<Integer> squaresList = numbers.stream().map( i -> i*i).distinct().collect(Collectors.toList());
filter:过滤某些元素
List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
//get list of unique squares
List<Integer> squaresList = numbers.stream().map( i -> i*i).distinct().collect(Collectors.toList());
limit:限制输出流的个数
Random random = new Random();
random.ints().limit(10).forEach(System.out::println);
sorted:对输出流元素进行排序
Random random = new Random();
random.ints().limit(10).sorted().forEach(System.out::println);
Collectors:用于聚合输出流的结果,可拼成list或者string
List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());
System.out.println("Filtered List: " + filtered);
String mergedString = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.joining(", "));
System.out.println("Merged String: " + mergedString);
首先,我们创建一个存储了用户信息的列表进行示例,我们先看看如何过滤:
过滤出姓名为xiao ming的用户
User user1 = new User("xiao ming", 12, "小学");
User user2 = new User("mei mei", 18, "大学");
User user3 = new User("li lei", 11, "小学");
User user4 = new User("xiao hong", 15, "初中");
List<User> userList = new ArrayList<>(3);
userList.add(user1);
userList.add(user2);
userList.add(user3);
userList.add(user4);
useList.stream().filter(user -> user.getName().equals("xiao ming")).forEach(user -> System.out.println(user.getGrade()));
你可以看到只要在列表后加上.stream(),默认就会生成一个流。
有了这个流后,你可以调用filter(),并在里边设置过滤条件即可过滤出相应的元素
下面我们再看看基于stream转成其他数据结构,现在我们将这个User类转成另外一个类。
原User类
class User{
String name;
int age;
String grade;
}
异构后的类
class UserInfo{
String name;
int age;
String extend;
}
如果按传统写法,我们肯定就要用for循环遍历原userlist,再一个个赋值过去了,现在有了stream就只需这样:
List<UserInfo> userInfoList = userList.stream.map(tmp->{
UserInfo = usrInfo = new UserInfo();
usrInfo.setName(tmp.getName());
usrInfo.setAge(tmp.getAge());
if (tmp.getGrade().equals("大学")){
usrInfo.setExtend("university");
}
return usrInfo;
}).collect(Collectors.toList());
再换个玩法,如果希望list转成map,key为用户名,value为整个用户对象,最后遍历打印map里的对象,那用stream要怎么玩呢?
Map<String, User> userMap = userList.stream().collect(Collectors.toMap(User::getName, user -> user));
userMap.forEach((K, V) -> System.out.println("key:" + K + "val:" + V));
好,我们继续加需求,在原User类上,要记录他所借阅过的书籍,那么数据结构将会变成这样:
原User类
class User{
String name;
int age;
String grade;
Set<String> books;
public void addBook(String book) {
if (this.book == null) {
this.book = new HashSet<>();
}
this.book.add(book);
}
}
我们要将小明,梅梅借的书读取出来
//初始化
User user1 = new User("xiao ming", 12, "小学");
User user2 = new User("mei mei", 18, "大学");
//添加图书
user1.addBook("Java 8 in Action");
user1.addBook("Spring Boot in Action");
user1.addBook("Effective Java (2nd Edition)");
user2.addBook("Learning Python, 5th Edition");
user2.addBook("Effective Java (2nd Edition)");
List<User> userList = new ArrayList<>(3);
userList.add(user1);
userList.add(user2);
List<String> collect = list.stream()
.map(x -> x.getBook()) //Stream<Set<String>>
.flatMap(x -> x.stream()) //Stream<String>
.distinct()
.collect(Collectors.toList());
collect.forEach(x -> System.out.println(x));
按照年级对用户进行分组
Map<String, List<User>> userGroup = userList.stream().collect(Collectors.groupingBy(User::getGrade));
判断用户列表中是否有符合指定年龄段的用户
boolean isAllAdult = useList.stream().allMatch(p -> p.getAge() > 10);
boolean isAnyChild = useList.stream().anyMatch(p -> p.getAge() < 12);