在Java中如何使用size方法获取集合大小_Java集合元素数量解析

size()方法返回集合元素个数,为O(1)时间复杂度,但需防null调用和并发不安全;Map.size()与keySet().size()等价;stream().count()为O(n),不可替代size()。

size() 方法在 Java 集合中的通用行为

size()Collection 接口定义的方法,所有标准集合类(ArrayListHashSetLinkedListHashMapkeySet() 等)都实现了它。它的返回值是 int 类型,表示当前集合中元素的个数。

注意:它不递归计算嵌套结构,只统计直接持有的元素数量;对 Map 来说,map.size() 返回的是键值对数量,不是 key 或 value 单独的数量。

  • size() 是 O(1) 时间复杂度 —— 内部通常只是读取一个计数字段,不遍历
  • 空集合(如新创建的 ArrayList)调用 size() 返回 0,不是 null
  • 如果集合被多个线程并发修改且未加同步,size() 返回值可能不准确(如 ArrayList 非线程安全)

常见误用:对 null 集合调用 size() 导致 NullPointerException

这是最常踩的坑:直接对可能为 null 的集合变量调用 size(),运行时报 NullPointerException

List list = getFromSomewhere(); // 可能返回 null
int count = list.size(); // ❌ 如果 list == null,这里崩

正确做法是显式判空:

  • Objects.nonNull(list) + 三元表达式:int count = Objects.nonNull(list) ? list.size() : 0;
  • 或提前 guard:if (list == null) return 0;
  • 更推荐在方法契约层面避免返回 null —— 改用 Collections.emptyList()Optional

Map 的 size() 和 keySet().size() 是否等价?

等价。对任意 Map 实例 mm.size()m.keySet().size() 总是相等,因为 Map 的大

小定义就是键值对数量,而 keySet() 是其视图,底层共享同一计数逻辑。

但要注意性能和语义差异:

  • m.size() 直接返回字段值,开销最小
  • m.keySet().size() 多一次方法调用和对象访问,虽仍是 O(1),但无必要
  • m.values().size() 同样等价,但 values() 视图在某些实现(如 ConcurrentHashMap)中可能触发轻量初始化,不如直接用 size()

Stream.count() 与 Collection.size() 的关键区别

别把 stream().count() 当作 size() 的替代 —— 它们语义和性能完全不同:

  • collection.size():O(1),不触发遍历,不消耗流资源
  • collection.stream().count():O(n),必须完整遍历整个数据源,即使集合本身支持快速获取大小
  • 对已排序或过滤过的流(如 list.stream().filter(...).count()),无法绕过计算,此时 count() 是唯一选择
  • 如果只是想知道原始集合大小,用 size();只有在流式处理链中需要“计数”时,才用 count()

尤其注意:对并行流调用 count() 不会提升性能,反而增加调度开销 —— 计数操作本身无法真正并行化。

集合大小看似简单,但 null 检查、流与集合语义混淆、以及对线程安全边界的忽视,才是实际出问题最多的地方。