如何包装库类迭代器,避免NoSuchElementException并返回null
通用解决方案:包装迭代器实现Null安全的遍历
这问题问得很到位!其实不管集合有没有索引(比如TreeSet这种无索引的,或者ArrayList这种有索引的),我们都可以通过包装原迭代器的思路来实现需求——核心就是在调用next()前先检查hasNext(),没有元素时返回null而非抛出NoSuchElementException。
步骤1:实现Null安全的迭代器包装类
我们先写一个通用的NullSafeIterator,它持有原集合的迭代器,重写next()方法做null安全处理:
import java.util.Iterator; public class NullSafeIterator<T> implements Iterator<T> { private final Iterator<T> originalIterator; public NullSafeIterator(Iterator<T> originalIterator) { this.originalIterator = originalIterator; } @Override public boolean hasNext() { // 直接复用原迭代器的hasNext判断 return originalIterator.hasNext(); } @Override public T next() { // 先检查是否还有元素,有就返回原迭代器的结果,没有就返回null return hasNext() ? originalIterator.next() : null; } @Override public void remove() { // 移除操作直接委托给原迭代器 originalIterator.remove(); } }
步骤2:包装Iterable接口
为了让任何实现Iterable的集合都能方便使用这个迭代器,我们再写一个NullSafeIterable包装类:
import java.util.Iterable; public class NullSafeIterable<T> implements Iterable<T> { private final Iterable<T> originalIterable; public NullSafeIterable(Iterable<T> originalIterable) { this.originalIterable = originalIterable; } @Override public Iterator<T> iterator() { // 返回我们的Null安全迭代器 return new NullSafeIterator<>(originalIterable.iterator()); } }
步骤3:实际使用示例(以TreeSet为例)
现在不管是TreeSet还是其他集合,都可以轻松包装成Null安全的遍历对象:
import java.util.TreeSet; public class Demo { public static void main(String[] args) { TreeSet<String> treeSet = new TreeSet<>(); treeSet.add("Java"); treeSet.add("Python"); treeSet.add("Go"); // 包装成Null安全的Iterable Iterable<String> nullSafeSet = new NullSafeIterable<>(treeSet); var iterator = nullSafeSet.iterator(); // 正常获取元素 System.out.println(iterator.next()); // Java System.out.println(iterator.next()); // Python System.out.println(iterator.next()); // Go // 无元素时返回null,不会抛异常 System.out.println(iterator.next()); // null System.out.println(iterator.next()); // null } }
Java 8+简化写法:无需单独定义类
如果不想写额外的类,也可以用Lambda表达式直接创建包装后的Iterable,更灵活:
TreeSet<String> treeSet = new TreeSet<>(); treeSet.add("Apple"); treeSet.add("Banana"); // 直接用Lambda包装Iterable Iterable<String> nullSafeTreeSet = () -> new Iterator<String>() { private final Iterator<String> original = treeSet.iterator(); @Override public boolean hasNext() { return original.hasNext(); } @Override public String next() { return hasNext() ? original.next() : null; } }; // 遍历使用 for (String item : nullSafeTreeSet) { if (item == null) break; // 遇到null就终止遍历 System.out.println(item); }
注意事项
- 虽然返回
null避免了异常,但使用时一定要注意处理null值,防止后续代码出现NullPointerException。 - 如果是在循环遍历中,推荐用
while循环来判断:var iterator = nullSafeSet.iterator(); String item; while ((item = iterator.next()) != null) { // 处理非null元素 System.out.println(item); }
内容的提问来源于stack exchange,提问作者Sahand
相关产品推荐
相关产品推荐

