为什么hasNext() 对只有一个元素的集合返回 true?90%初学者都有的疑问

先看一段再简单不过的代码:

java 复制代码
List<String> list = Arrays.asList("A");
Iterator<String> it = list.iterator();

while (it.hasNext()) {
    String s = it.next();
    System.out.println(s);
}

运行一下,控制台打印出了A。这没什么奇怪的,遍历集合并打印每个元素,这是我们从学 Java 第一天就会写的代码。

但有一天我突然盯着这段代码出了神:集合明明只有一个元素,hasNext() 第一次判断怎么就返回了 true 呢?

hasNext() 翻译过来是"有下一个",A 后面明明什么都没有,凭什么告诉我"有"?难道迭代器在骗我?

带着这个疑问,我开始追溯迭代器的工作方式,结果发现:不是迭代器骗了我,而是我一直理解错了它问问题的对象。


如果站在"当前元素"的角度去理解 hasNext(),那它的逻辑应该是这样的:先看看我当前在哪个元素,再问问这个元素后面还有没有东西。可问题是,在第一次调用 hasNext() 的时候,迭代器根本还不站在任何元素上------它还没开始遍历,哪来的"当前元素"?没有当前元素,又怎么判断它后面有没有?

这套理解在第一步就卡住了。

那 Java 的迭代器到底是怎么想的呢?我们打开 ArrayList 内部迭代器 Itr 的源码看看:

java 复制代码
private class Itr implements Iterator<E> {
    int cursor;       // 下一个要返回的元素索引
    int lastRet = -1;

    public boolean hasNext() {
        return cursor != size;
    }

    public E next() {
        int i = cursor;
        cursor = i + 1;
        return get(i);
    }
}

注意这个 cursor------它叫"游标",但它存的不是"我目前在哪个位置",而是 "下一个要返回的元素在哪个位置" 。初始值是 0,意思是:我还没开始呢,下一个要给你的是索引 0 那个元素。

所以 hasNext() 真正在问的问题是:cursor 有没有走到头? 也就是:还有没有"下一个要返回的元素"没给你?

回到那个只有一个元素的集合:cursor 初始是 0size10 != 1 成立,所以 hasNext() 返回 true。它告诉你的不是"A 后面还有东西",而是 "我手上还有一个叫 A 的元素还没给你呢"

next() 被调用后,先取出索引 0 的 A 交给你,然后把 cursor 变成 1。下一次再问 hasNext()1 != 1 不成立,返回 false,遍历结束。

这下清楚了:hasNext() 从头到尾就不是对着某个元素在问,它是对着整个集合在问------"集合里还有我没给你的元素吗?"


想通这一点之后,我发现 Java 之所以这么设计,其实是为了让遍历的逻辑对每一个元素都一视同仁。

假设真的按"对着元素问"的方式来设计,代码会变成什么样?我们得先想办法拿到第一个元素,然后才能问它后面还有没有,再然后才能移动到下一个。那第一个元素就成了"特殊元素",需要单独处理:

java 复制代码
if (it.hasCurrent()) {
    String first = it.current();
    while (it.hasNext()) {
        String next = it.next();
    }
}

光是看着就比 while(hasNext()) { next() } 啰嗦得多。而且空集合的时候还得额外判断"有没有当前元素",边界条件一下子就多了起来。


说到底,hasNext() 的语义很简单,只是我们习惯性地把"下一个"理解成了对着当前元素说"还有没有下一个"。而迭代器里的"下一个"意思是 对着整个集合说还有没有下一个

理解了这一点,再去写 while (it.hasNext()) 的时候,心里就透亮多了。

相关推荐
evans在进步13 分钟前
Java 常用设计模式(二):装饰器、适配器、责任链、模板方法、策略与观察者
java·开发语言·设计模式
jvmind_dev35 分钟前
频繁 new JedisCluster 之后,对象池为什么回不去了?
java·后端
AKA__Zas1 小时前
文件 I/O(速通版
java·intellij-idea·学习方法
学长毕业设计1 小时前
基于SpringBoot的咖啡馆管理系统的设计与实现(源码+文档+讲解视频)
java·spring boot·后端
骇客野人1 小时前
SpringBoot业财一体化系统设计和落地实施方案
java·spring boot·后端
学长毕业设计1 小时前
基于SpringBoot的教学资源推荐系统的设计与实现(源码+文档+讲解视频)
java·spring boot·后端
名字还没想好☜1 小时前
Java Cleaner 实战:替代废弃的 finalize() 做堆外资源清理,以及强引用导致永不回收的坑
java·后端·spring
LaughingZhu1 小时前
Product Hunt 每日热榜 | 2026-09-02
java·ide·intellij-idea
旧梦95271 小时前
Java EnumMap 详解:原理、用法与实战
java·开发语言
兜里ヌ有糖1 小时前
java Date时间格式工具类DateUtil
java