You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java 1.7下如何高效生成多学生订阅的学科-学生ID映射表

嘿,这个问题我之前处理过类似的大数据量场景,Java 1.7下确实要尽量避免先全量构建再过滤的方式——太浪费内存和CPU了。给你两个高效的一次遍历方案,都是边处理边筛选,能大幅降低资源消耗:

方案一:实时维护Map,事后轻量过滤

这个方案在遍历过程中就先把所有学科的学生列表存起来,但只在最后做一次极小的过滤(移除单元素的条目),相比先存再删的原始思路,内存占用已经优化很多:

Map<String, List<String>> subjectToStudents = new HashMap<String, List<String>>();

for (Candidate candidate : candidates) {
    String subjId = candidate.getSubjectId();
    String stuId = candidate.getStudentId();
    
    List<String> stuList = subjectToStudents.get(subjId);
    if (stuList == null) {
        // 首次遇到该学科,初始化容量为2的列表(避免后续扩容)
        stuList = new ArrayList<String>(2);
        stuList.add(stuId);
        subjectToStudents.put(subjId, stuList);
    } else {
        stuList.add(stuId);
    }
}

// 最后移除仅单个学生的学科,用Iterator避免ConcurrentModificationException
Iterator<Map.Entry<String, List<String>>> iter = subjectToStudents.entrySet().iterator();
while (iter.hasNext()) {
    Map.Entry<String, List<String>> entry = iter.next();
    if (entry.getValue().size() < 2) {
        iter.remove();
    }
}

为什么高效?

  • 遍历过程中没有额外的判断逻辑,只做最基础的添加操作,速度快
  • 初始化列表时设容量为2,减少小列表的扩容开销
  • 最后过滤的是少数不符合条件的条目,相比全量遍历过滤,耗时可以忽略
方案二:仅保留符合条件的学科,完全避免事后过滤

如果数据量特别大,连存储单元素列表都觉得浪费内存,可以用两个辅助Map来跟踪首次出现的学生和计数,只把满足“多个学生”条件的学科加入结果Map:

Map<String, String> firstStudentOfSubject = new HashMap<String, String>();
Map<String, Integer> subjectCount = new HashMap<String, Integer>();
Map<String, List<String>> result = new HashMap<String, List<String>>();

for (Candidate candidate : candidates) {
    String subjId = candidate.getSubjectId();
    String stuId = candidate.getStudentId();
    
    Integer count = subjectCount.get(subjId);
    if (count == null) {
        // 第一次遇到该学科,记录计数和首个学生
        subjectCount.put(subjId, 1);
        firstStudentOfSubject.put(subjId, stuId);
    } else if (count == 1) {
        // 第二次遇到,说明符合条件,创建列表并加入首个和当前学生
        List<String> stuList = new ArrayList<String>();
        stuList.add(firstStudentOfSubject.get(subjId));
        stuList.add(stuId);
        result.put(subjId, stuList);
        subjectCount.put(subjId, 2); // 标记为已加入结果
    } else {
        // 已经在结果里的学科,直接追加学生ID
        result.get(subjId).add(stuId);
    }
}

为什么高效?

  • 结果Map从始至终只存储符合条件的学科,完全不用后续过滤
  • 辅助Map存储的是轻量的String键值对,比ArrayList占用内存少得多
  • 遍历过程中的判断逻辑非常简单,对性能影响极小
额外优化建议
  • 如果能预估符合条件的学科数量,给resultMap设置初始容量(比如new HashMap<>(estimatedSize)),可以避免扩容带来的性能损耗
  • 如果需要对学生ID去重(同一个学生多次订阅同一学科只保留一次),可以把List换成HashSet,最后再转成List(如果业务需要List格式的话)
  • 若在多线程环境下处理,把HashMap换成ConcurrentHashMap即可,Java 1.7的ConcurrentHashMap性能表现很不错

内容的提问来源于stack exchange,提问作者IUnknown

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 07:30:05