1. 概述

在Java开发中,我们经常会遇到需要获取一个 Iterable 对象元素个数的场景。但问题来了:**Iterable 接口本身并没有提供 size() 方法**,这就导致我们必须通过其他手段来“曲线救国”。

本文将系统性地介绍几种获取 Iterable 大小的常用方法,涵盖原生Java方案和主流第三方库的实现,帮你避开“遍历全集数数”的低效陷阱。


2. Iterable 与 Iterator 的关系

Iterable 是Java集合体系中的核心接口之一。

所有实现了 Collection 接口的类(比如 ListSet)都间接实现了 Iterable,因此天然支持增强for循环。

Iterable 接口只定义了一个方法:

public interface Iterable<T> {
    public Iterator<T> iterator();    
}

这个 iterator() 方法返回一个 Iterator,用于遍历集合中的元素。⚠️ 重点来了:它只负责“遍历”,不负责“计数”。


3. 使用原生Java获取Iterable大小

3.1 使用 for-each 循环手动计数

最简单粗暴的方式:遍历一遍,边走边数。

int counter = 0;
for (Object i : data) {
    counter++;
}
return counter;

✅ 优点:通用,适用于任何 Iterable
❌ 缺点:时间复杂度 O(n),如果只是想查个长度却把整个数据源拉一遍,性能上可能踩坑,尤其在数据量大或后端是远程流式接口时。


3.2 判断是否为 Collection 并调用 size()

大多数情况下,你拿到的 Iterable 其实是 Collection 的实例(比如 ArrayListHashSet)。

Collection 接口是有 size() 方法的,且通常是 O(1) 时间复杂度。

因此可以先判断类型,能走捷径就走捷径:

if (data instanceof Collection) {
    return ((Collection<?>) data).size();
}

⚠️ 注意强转时的泛型安全,使用 <?> 避免警告。

结合上面两种方式,我们可以写出一个兼顾性能与通用性的工具方法:

public static int size(Iterable<?> data) {
    if (data instanceof Collection<?>) {
        return ((Collection<?>) data).size();
    }
    int counter = 0;
    for (Object i : data) {
        counter++;
    }
    return counter;
}

✅ 推荐做法:先判断是否是 Collection,是则直接返回 size(),否则退化为遍历计数。


3.3 使用 Stream.count()

Java 8 引入了 Stream,我们可以通过 StreamSupportIterable 转为 Stream,然后调用 count()

return StreamSupport.stream(data.spliterator(), false).count();

✅ 优点:函数式风格,代码简洁
⚠️ 注意:false 表示不并行执行。如果传 true,在某些可分割的数据结构上会并行处理,但多数场景没必要,反而增加开销。

❌ 实际性能:底层仍然是遍历,不会比手动 for-each 快,只是写法更现代。


4. 使用第三方库

4.1 Apache Commons Collections:IterableUtils.size()

Apache Commons Collections 提供了 IterableUtils 工具类,封装了对 Iterable 的常用操作。

首先引入依赖:

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-collections4</artifactId>
    <version>4.1</version>
</dependency>

使用方式极其简单:

return IterableUtils.size(data);

✅ 底层实现:正是我们上面推荐的“先判断 Collection,再遍历”的组合策略,既安全又高效。


4.2 Google Guava:Iterables.size()

Guava 作为Java开发的“标配”库之一,也提供了类似功能。

引入依赖:

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>31.0.1-jre</version>
</dependency>

调用方式:

return Iterables.size(data);

✅ 同样,Iterables.size() 内部也是先判断是否为 Collection,再决定是否遍历,逻辑清晰,性能最优。

📌 小结:**IterableUtils.size()Iterables.size() 本质实现几乎一致**,选哪个取决于你项目中已引入的依赖。


5. 总结

方法 是否推荐 说明
Collection.size() + 类型判断 强烈推荐 性能最优,应作为首选策略
✅ 第三方库(Commons/Guava) 推荐 封装良好,代码简洁,适合已有依赖的项目
⚠️ Stream.count() 可用但非最优 写法现代,但性能无优势
❌ 纯遍历计数 仅作兜底 仅在无法判断类型时使用

📌 最佳实践:优先判断是否为 Collection,是则调用 size(),否则遍历计数。这个逻辑已被 Commons 和 Guava 完美封装,直接调用即可。

示例代码已上传至 GitHub:https://github.com/baeldung/core-java-modules/tree/master/core-java-collections-2


原始标题:Getting the Size of an Iterable in Java | Baeldung