关注我的公众号:【编程朝花夕拾】,可获取首发内容。

01 引言
在日常开发中,集合的操作是无法避开的。对于集合的操作,你是在JDK
的流式处理还是Guava
处理呢?
JDK8
以前对于集合的处理,基本上只能遍历处理。而Guava
对于集合操作的封装,简直不要太爽,备受广发开发者好评。而JDK8
以后,流式处理简化了集合的操作,慢慢的吸引了一批开发者成为忠粉。
但是单独对于集合的处理,JDK
和Guava
孰强孰弱?
02 集合处理需求
数据准备:
java
@Data
@AllArgsConstructor
public class User {
Integer id;
String name;
int age;
}
// 集合
List<User> list = new ArrayList<>();
list.add(new User(1, "name1", 4));
list.add(new User(2, "name2", 8));
list.add(new User(3, "name3", 4));
list.add(new User(4, "name4", 6));
list.add(new User(5, "name5", 8));
处理任务:
- list转Map
- 通过年龄属性分组
- List分片
- Map集合的处理
03 流式处理对比Guava
先回顾一下传统的集合处理方法,无疑就是遍历。
java
for (User user : list) {
// 业务处理
}
传统的处理方式不是不好,反而更加通用。但是相比一些特定的处理,传统的方式相对而言麻烦一下。
Guava的Maven依赖:
xml
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>33.4.8-jre</version>
</dependency>
3.1 List转Map
业务开发中,我们查询一个列表数据,需要填充数据的某个属性时,就是需要先查出集合中数据对应在另外一个表的属性,然后转成以id
为key
, 当前对象为value
转成Map。遍历填充的时候,就可以直接通过Map获取即可。
有没有人知己在遍历的时候,直接通过查询的数据库的方式,填充数据的?这种方式是不可取的,当数量大时,这种处理方式就会暴漏出弊端。有多少数据量,就有多少次IO的处理。
对于案例数据,我们就将list转化成以id
为key
,user
为value
的Map。
java
// 传统的写法
Map<Integer, User> map1 = new HashMap<>();
for (User user : list) {
map1.put(user.getId(), user);
}
// JDK8流式处理
Map<Integer, User> collect = list.stream()
.collect(Collectors.toMap(User::getId, Function.identity()));
// Guava处理
ImmutableMap<Integer, User> immutableMap = Maps.uniqueIndex(list, User::getId);
从案例代码上来看,JDK8
和Guava
都是一行代码完成了List到Map的转化,代码确实精简不少。JDK8
和Guava
处理的结果集是不可变集合,无法再次像集合中添加元素,而传统的写法,却不受限制。
我们技术上难度
我们假设id有重复的,增加重复的数据:
java
list.add(new User(5, "name6", 9));
此时,流式处理和Guava
的写法,全部崩溃,大致的报错都是因为key重复导致的。
JDK
报错:

Guava报错:

然而JDK
的流式处理,提供另外一个重载方法课解决此问题:
java
Map<Integer,User> userMap4 = list.stream()
.collect(Collectors.toMap(User::getId, Function.identity(),(value1,value2)->value2));
后面的参数指定了取值,如果Key
重复,则选用第二个参数。但从这一点上JDK8
的流式处理略胜一筹。
3.2 通过年龄属性分组
通过属性分组,是另外的一种List转Map,就是当key
重复的时候,将value
只通过List集合收集起来。
java
// JKD8 流式处理
Map<Integer, List<User>> collect1 = list.stream().collect(Collectors.groupingBy(User::getAge));
// Guava 处理
ImmutableListMultimap<Integer, User> indexed = Multimaps.index(list, User::getAge);

但看这种处理方式,几乎没有什么区别,都非常简洁。
3.3 List分片
List
分片在处理海量数据的时候需要用到,通过分片,将分片数据交给不同的算子,以提高处理速度。分而治之的思想就体现在这里。
List
的分片JDK
并没有提供现成的方法,可以说Guava
完胜。但是我们依然可以自行实现分片的功能。
java
// 为了方便,我们使用整型数据
List<Integer> list = List.of(1, 2, 3, 4, 5, 6, 7, 8);
// Guava 的处理
List<List<Integer>> partition = Lists.partition(list, 3);

我们可以看到:
将原集合分成了三组。
JDK 自行实现
java
List<List<Integer>> partition2 = myListPartition(list, 3);
System.out.println(partition2);
private List<List<Integer>> myListPartition(List<Integer> list, int size) {
List<List<Integer>> partition2 = new ArrayList<>();
// 总长度
int len = list.size();
// 每一组的长度
int groupSize = (int) Math.ceil((double) len / size);
for (int i = 0; i < groupSize; i++) {
int index = i * size;
int end = Math.min(index + size, len);
partition2.add(list.subList(index, end));
}
return partition2;
}
3.4 Map集合的处理
Map集合的处理JDK
的流式处理,可能就会略显冗长,但是更灵活。
java
// 数据准备
Map<Integer, User> maps = new HashMap<>();
maps.put(1, new User(1, "name1", 4));
maps.put(2, new User(2, "name2", 6));
maps.put(3, new User(3, "name3", 8));
maps.put(4, new User(4, "name4", 6));
修改Map集合的Value为name属性
java
// JDK 处理
Map<Integer, String> collect = maps.entrySet().stream()
.collect(Collectors.toMap(Entry::getKey, entry -> entry.getValue().getName()));
// Guava 处理
Map<Integer, String> strMap = Maps.transformValues(maps, User::getName);
// 或者
Map<Integer, Integer> strMap = Maps.transformEntries(maps, (k, v) ->v.getName()));
处理的时候发现一个问题,就是Guava
的处理只能针对value
,而JDK
的处理既可以处理Key
,也可以处理Value
。
04 小结
对于工具的使用熟能生巧,并不是一定要分出哪个一定好,哪个一定坏,只不过是使用的场景不同而已。重要的事,你用了什么不重要,重要的事你能把问题解决了。
你们更习惯使用哪种方式呢?评论区留言。