BitSet的nextSetBit是稀疏位图遍历核心方法,它跳过连续0直接定位下一个1,时间复杂度接近O(k);正确写法为for (int i = bs.nextSetBit(0); i != -1; i = bs.nextSetBit(i + 1)),避免死循环或遗漏。

BitSet 的 nextSetBit 是稀疏位图遍历的核心方法,它跳过连续的 0,直接定位下一个 1 的位置,避免逐位扫描,时间复杂度接近 O(k),k 是实际置位的数量。
nextSetBit 的基本用法
该方法签名是 int nextSetBit(int fromIndex),从 fromIndex(含)开始向后查找第一个值为 true 的位索引;如果找不到,返回 -1。
典型遍历模式:
- 起始调用
bs.nextSetBit(0)获取第一个置位位置 - 后续每次以
current + 1为起点继续查找:bs.nextSetBit(current + 1) - 循环直到返回 -1
为什么适合稀疏位图
稀疏位图中 1 很少、0 极多。传统 for 循环检查每个 bit(O(n))会大量浪费在 0 上;而 nextSetBit 内部基于 word-level 跳跃(按 long 数组逐字查找空 word,再在非空 word 中用位运算找最低置位),实际只访问含 1 的字和少量边界字。
立即学习“Java免费学习笔记(深入)”;
例如:一个 100 万位的 BitSet 只有 100 个 1,nextSetBit 平均只需几十次操作,而非百万次判断。
正确遍历的写法(避免常见错误)
错误写法(可能跳过第一个位或陷入死循环):
- 从 -1 开始并用
nextSetBit(i+1)—— 起始点错,-1+1=0 没问题,但逻辑易混淆 - 用
i = bs.nextSetBit(i)且未更新 i —— 导致重复返回同一位置
推荐写法:
for (int i = bs.nextSetBit(0); i != -1; i = bs.nextSetBit(i + 1)) {
// 处理索引 i
}
这个结构清晰、安全、无边界风险,i 始终指向有效置位索引,且每次推进到下一个可能位置。
结合业务场景的小技巧
实际使用时可进一步优化语义表达:
- 若位索引代表 ID(如用户 ID、文档 ID),可直接用作业务键,无需额外映射
- 配合
cardinality()预判循环次数,便于预分配集合或数组 - 多线程下注意 BitSet 非线程安全;如需并发遍历,应加锁或使用
ConcurrentBitSet(第三方库)
不复杂但容易忽略:nextSetBit 不保证原子性,遍历时若其他线程修改 BitSet,结果可能不一致 —— 稀疏遍历前建议冻结或快照。


















