有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java是一个“无限”迭代器——糟糕的设计?

通常认为提供Iterator个“无限”的实现是不好的做法;i、 e.对hasNext()的调用始终(*)返回true的位置

通常我会说“是”,因为调用代码的行为可能不稳定,但在下面的实现中hasNext()将返回true,除非调用方从迭代器初始化时使用的列表中删除所有元素;i、 e.存在终止条件。你认为这是对Iterator的合法使用吗?这似乎没有违反合同,尽管我想有人会说这是不直观的

public class CyclicIterator<T> implements Iterator<T> {
  private final List<T> l;
  private Iterator<T> it;

  public CyclicIterator<T>(List<T> l) {
    this.l = l;
    this.it = l.iterator();
  }

  public boolean hasNext() {
    return !l.isEmpty();
  }

  public T next() {
    T ret;

    if (!hasNext()) {
      throw new NoSuchElementException();
    } else if (it.hasNext()) {
      ret = it.next();
    } else {
      it = l.iterator();
      ret = it.next();
    }

    return ret;
  }

  public void remove() {
    it.remove();
  }
}

(学究式)编辑

一些人评论了如何使用Iterator从无界序列(如斐波那契序列)生成值。但是,Java{}文档指出迭代器是:

An iterator over a collection.

现在您可以认为斐波那契序列是一个无限集合,但在Java中,我将集合等同于java.util.Collection接口,它提供了size()等方法,这意味着集合必须是有界的。因此,使用Iterator作为无界序列的值生成器是否合法


共 (6) 个答案

  1. # 1 楼答案

    这可能是语义问题,但迭代器应该努力返回下一项,而不考虑它何时结束。结尾对一个系列来说是一个副作用,尽管它可能看起来像是一个常见的副作用

    不过,无限和一个10万亿物品的集合有什么区别?来电者要么想要全部,要么不想要。让来电者决定归还多少物品或何时结束

    我不会说调用者不能使用for-each构造。他可以,只要他想要所有的东西

    集合文档中的某些内容,比如“可能是一个无限集合”,是合适的,但不是“无限迭代器”

  2. # 2 楼答案

    一个Iterator要点在于它是懒惰的,也就是说,它只给你想要的东西。如果用户要求无限Iterator的所有对象,那是他们的问题,而不是你的问题

  3. # 3 楼答案

    这是一种完全合法的使用方式-只要有适当的文档记录

    使用名称CyclicIterator是一个好主意,因为它可以推断,如果没有正确定义循环出口情况,迭代器上的循环很可能是无限的

  4. # 4 楼答案

    我认为这是完全合法的-an Iterator只是一连串的“东西”。为什么溪流一定要有边界

    许多其他语言(例如Scala)都内置了无限流的概念,并且可以对其进行迭代。例如,使用scalaz

    scala> val fibs = (0, 1).iterate[Stream](t2 => t2._2 -> (t2._1 + t2._2)).map(_._1).iterator
    fibs: Iterator[Int] = non-empty iterator
    
    scala> fibs.take(10).mkString(", ") //first 10 fibonnacci numbers
    res0: String = 0, 1, 1, 2, 3, 5, 8, 13, 21, 34
    

    编辑:就最小惊喜原则而言,我认为这完全取决于上下文。例如,我希望这个方法返回什么

    public Iterator<Integer> fibonacciSequence();
    
  5. # 5 楼答案

    无限迭代器在创建无限数据时非常有用,例如Fibonacci sequence这样的线性循环序列

    所以,使用这样的方法是完全可以的

  6. # 6 楼答案

    虽然我也认为这是合理的,但我想补充一点,这样的Iterator(或者更准确地说:一个Iterable产生这样的Iterator)将不能很好地与增强的for循环(也就是每个循环的a)配合使用:

    for (Object o : myIterable) {
       ...
    }
    

    由于增强for循环中的代码无法直接访问迭代器,因此无法在迭代器上调用remove()

    因此,要结束循环,必须执行以下操作之一:

    • 获取对Iterator的内部List的访问权,并直接删除对象,可能会引发ConcurrentModificationException
    • 使用break退出循环
    • “使用”an Exception退出循环
    • 使用return离开循环

    除了最后一个选项之外,所有这些选项都不是留下增强for循环的最佳方式

    “normal”for循环(或者任何其他循环加上一个显式的Iterator变量)可以正常工作,当然:

    for (Iterator it = getIterator(); it.hasNext();) {
      Object o = it.next()
      ...
    }