在社交类应用的开发中,好友关注关系的存储和查询是高频需求,使用Map嵌套Set的数据结构可以非常轻量地实现这类逻辑,既不需要依赖数据库,也能满足基础的功能演示和小型场景使用。这种结构的核心思路是用Map的键存储用户标识,值用Set存储该用户关注的其他用户标识,利用Set的去重特性避免重复关注的问题。

整体设计思路
我们首先定义两个核心的Map结构,分别用来存储关注关系和粉丝关系,提升查询效率:
- followMap:键为当前用户ID,值为该用户关注的用户ID集合,用来快速查询某个用户的关注列表
- fansMap:键为当前用户ID,值为关注该用户的用户ID集合,用来快速查询某个用户的粉丝列表
当用户A关注用户B时,需要同时更新两个Map:在followMap中A的集合里加入B,在fansMap中B的集合里加入A。取消关注时则执行相反的操作,移除对应的元素。
核心功能实现代码
1. 初始化数据结构
首先定义存储关注关系和粉丝关系的Map,这里使用HashMap和HashSet来实现:
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public class SocialRelationSystem {
// 存储用户的关注关系:key是用户ID,value是该用户关注的用户ID集合
private Map<String, Set<String>> followMap;
// 存储用户的粉丝关系:key是用户ID,value是关注该用户的用户ID集合
private Map<String, Set<String>> fansMap;
public SocialRelationSystem() {
followMap = new HashMap<>();
fansMap = new HashMap<>();
}
}
2. 实现关注功能
关注功能需要处理重复关注的情况,利用Set的add方法返回值判断是否已经关注过:
/**
* 用户userId关注目标用户targetId
* @param userId 发起关注的用户ID
* @param targetId 被关注的用户ID
* @return 是否关注成功,已经关注过则返回false
*/
public boolean follow(String userId, String targetId) {
// 不能关注自己
if (userId.equals(targetId)) {
System.out.println("不能关注自己");
return false;
}
// 初始化当前用户的关注集合(如果不存在的话)
followMap.putIfAbsent(userId, new HashSet<>());
Set<String> followSet = followMap.get(userId);
// 如果已经关注过,直接返回false
if (followSet.contains(targetId)) {
System.out.println(userId + " 已经关注过 " + targetId);
return false;
}
// 更新关注关系
followSet.add(targetId);
// 更新粉丝关系
fansMap.putIfAbsent(targetId, new HashSet<>());
fansMap.get(targetId).add(userId);
System.out.println(userId + " 成功关注 " + targetId);
return true;
}
3. 实现取消关注功能
取消关注需要同时移除两个Map中对应的元素,还要处理集合为空的情况:
/**
* 用户userId取消关注目标用户targetId
* @param userId 发起取消关注的用户ID
* @param targetId 被取消关注的用户ID
* @return 是否取消成功,未关注过则返回false
*/
public boolean unfollow(String userId, String targetId) {
// 检查是否存在关注关系
Set<String> followSet = followMap.get(userId);
if (followSet == null || !followSet.contains(targetId)) {
System.out.println(userId + " 未关注过 " + targetId);
return false;
}
// 移除关注关系
followSet.remove(targetId);
// 如果关注集合为空,移除该用户的键
if (followSet.isEmpty()) {
followMap.remove(userId);
}
// 移除粉丝关系
Set<String> fansSet = fansMap.get(targetId);
if (fansSet != null) {
fansSet.remove(userId);
if (fansSet.isEmpty()) {
fansMap.remove(targetId);
}
}
System.out.println(userId + " 成功取消关注 " + targetId);
return true;
}
4. 查询关注列表和粉丝列表
查询功能直接返回对应Map中的集合即可,注意返回不可修改的集合避免外部修改内部结构:
import java.util.Collections;
/**
* 获取用户的关注列表
* @param userId 用户ID
* @return 该用户的关注用户ID集合,无关注则返回空集合
*/
public Set<String> getFollowList(String userId) {
Set<String> followSet = followMap.get(userId);
if (followSet == null) {
return Collections.emptySet();
}
// 返回不可修改的集合,避免外部修改内部数据
return Collections.unmodifiableSet(followSet);
}
/**
* 获取用户的粉丝列表
* @param userId 用户ID
* @return 该用户的粉丝用户ID集合,无粉丝则返回空集合
*/
public Set<String> getFansList(String userId) {
Set<String> fansSet = fansMap.get(userId);
if (fansSet == null) {
return Collections.emptySet();
}
return Collections.unmodifiableSet(fansSet);
}
5. 功能测试示例
编写测试代码验证上述功能是否正常:
public static void main(String[] args) {
SocialRelationSystem system = new SocialRelationSystem();
// 测试关注功能
system.follow("user1", "user2");
system.follow("user1", "user3");
system.follow("user2", "user1");
// 测试重复关注
system.follow("user1", "user2");
// 测试关注自己
system.follow("user1", "user1");
// 查询关注列表
System.out.println("user1的关注列表:" + system.getFollowList("user1"));
System.out.println("user2的关注列表:" + system.getFollowList("user2"));
// 查询粉丝列表
System.out.println("user1的粉丝列表:" + system.getFansList("user1"));
System.out.println("user2的粉丝列表:" + system.getFansList("user2"));
// 测试取消关注
system.unfollow("user1", "user2");
System.out.println("取消关注后user1的关注列表:" + system.getFollowList("user1"));
System.out.println("取消关注后user2的粉丝列表:" + system.getFansList("user2"));
}
注意事项
这种实现方式适合轻量级的场景,实际生产环境中如果需要持久化存储,还需要结合数据库使用,同时要注意以下几点:
- 用户ID建议使用唯一标识,比如UUID或者自增ID,避免重复
- 如果需要支持大量用户,Map和Set的初始容量可以提前设置,减少扩容带来的性能损耗
- 如果涉及并发场景,需要使用ConcurrentHashMap和ConcurrentHashSet来保证线程安全
- 实际社交系统中还需要考虑关注上限、黑名单、关注审核等额外逻辑,可以在上述基础上扩展
通过上述实现,我们可以快速搭建一个简单的好友关注逻辑模块,理解Map嵌套Set这种数据结构在关系类场景中的应用方式,后续也可以根据需求扩展更多功能,比如互关判断、共同关注查询等。