集合的处理:JDK和Guava孰强孰弱?

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

01 引言

在日常开发中,集合的操作是无法避开的。对于集合的操作,你是在JDK的流式处理还是Guava处理呢?

JDK8以前对于集合的处理,基本上只能遍历处理。而Guava对于集合操作的封装,简直不要太爽,备受广发开发者好评。而JDK8以后,流式处理简化了集合的操作,慢慢的吸引了一批开发者成为忠粉。

但是单独对于集合的处理,JDKGuava孰强孰弱?

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

业务开发中,我们查询一个列表数据,需要填充数据的某个属性时,就是需要先查出集合中数据对应在另外一个表的属性,然后转成以idkey, 当前对象为value转成Map。遍历填充的时候,就可以直接通过Map获取即可。

有没有人知己在遍历的时候,直接通过查询的数据库的方式,填充数据的?这种方式是不可取的,当数量大时,这种处理方式就会暴漏出弊端。有多少数据量,就有多少次IO的处理。

对于案例数据,我们就将list转化成以idkeyuservalue的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);

从案例代码上来看,JDK8Guava都是一行代码完成了List到Map的转化,代码确实精简不少。JDK8Guava处理的结果集是不可变集合,无法再次像集合中添加元素,而传统的写法,却不受限制。

我们技术上难度

我们假设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 小结

对于工具的使用熟能生巧,并不是一定要分出哪个一定好,哪个一定坏,只不过是使用的场景不同而已。重要的事,你用了什么不重要,重要的事你能把问题解决了。

你们更习惯使用哪种方式呢?评论区留言。

相关推荐
重整旗鼓~12 分钟前
7.索引库操作
java·开发语言
云心雨禅28 分钟前
Spring Boot热更新技巧:节省90%重启时间
java·数据库·spring boot
wmze29 分钟前
InnoDB存储引擎
后端
W说编程31 分钟前
算法导论第十四章 B树与B+树:海量数据的守护者
c语言·数据结构·b树·算法·性能优化
Jay Kay31 分钟前
深入解析协程:高并发编程的轻量级解决方案
开发语言·c++·算法
岁忧34 分钟前
(LeetCode 每日一题) 2966. 划分数组并满足最大差限制 (贪心、排序)
java·c++·算法·leetcode·职场和发展·go
Maỿbe1 小时前
实现回显服务器(基于UDP)
java·javaweb·echo·回显服务器
葡萄城技术团队1 小时前
450 + 公式计算支持,GcExcel Java 强大计算引擎揭秘
java
lifallen1 小时前
Java BitSet类解析:高效位向量实现
java·开发语言·后端·算法
学不好python的小猫1 小时前
7-4 身份证号处理
开发语言·python·算法