通向面包的小路蜿蜒于劳动的沼泽之中,通向衣裳的小路从一块无花的土地中穿过,无论是通向面包的路还是通向衣裳的路,都是一段艰辛的历程。 ——福斯
今天有朋友问我,stream
中如果要将一个User
类中的username
和id
收集起来变成两个list
怎么写,我说可以使用peek
函数
1 2 3 4 5 6 7
| @Data @AllArgsConstructor static class User { private Long id; private Long groupId; private String username; }
|
就像这样:
1 2 3 4 5 6 7 8 9 10 11
| List<User> userList = Stream.iterate(1L, i -> ++i).map(id -> new User(id, 999L, Faker.instance().name().username())).limit(10).collect(Collectors.toList()); List<Long> groupIds = new ArrayList<>(userList.size() * 2); List<String> usernames = new ArrayList<>(userList.size() * 2); List<Long> userIds = userList.parallelStream().peek(user -> groupIds.add(user.getGroupId())).peek(user -> usernames.add(user.getUsername())).map(User::getId).collect(Collectors.toList()); System.out.println(userIds); System.out.println(groupIds); System.out.println(usernames);
|
然后运行结果:
然后它有问,如果他不知道有多少个,有可能有一个,也有可能两个怎么办
我就给他写了另外两种实现方式:
使用动态参数+reduce
实现,以及List
+reduce
实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
@SafeVarargs public static <T> Stream<T> peek(Stream<T> stream, Consumer<T>... peeks) { return Stream.of(peeks).reduce(stream, Stream::peek, Stream::concat); }
public static <T> Stream<T> peek(Stream<T> stream, List<Consumer<T>> peeks) { return peeks.stream().reduce(stream, Stream::peek, Stream::concat); }
|
这两种,使用方式如下:
1 2 3 4 5 6 7 8
| userIds = peek(userList.parallelStream(), user -> groupIds.add(user.getGroupId()), user -> usernames.add(user.getUsername())).map(User::getId).collect(Collectors.toList());
List<Consumer<User>> peeks = Arrays.asList(user -> groupIds.add(user.getGroupId()), user -> usernames.add(user.getUsername())); Stream<User> peek = peek(userList.stream(), peeks);
peek(userList.stream(), peeks.stream().<Consumer<User>>toArray(Consumer[]::new)); peek(userList.stream(), peeks.<Consumer<User>>toArray(new Consumer[0]));
|
这里原理就是用了reduce
函数的累加特性,这个聚合操作:
1
| Stream.of(peeks).reduce(stream, Stream::peek, Stream::concat);
|
相当于:
1 2 3 4
| Stream<User> stream = userList.stream(); for (Consumer<User> consumer : peeks) { stream = stream.peek(consumer); }
|
关于reduce
我之前的博客也写过了,就不再赘述啦~
主要就是分享这种思路,多了一种写法而已