当前位置: 首页 > 知识库问答 >
问题:

扫描仪为什么实现迭代器?

周云
2023-03-14

我只是想知道为什么是java。util。扫描器实现java。util。迭代器?

Scanner实现删除方法,并抛出一个不支持的操作异常。

但是一个类在实现接口时,不应该履行接口的契约吗?

实现迭代器并添加引发异常的方法有什么用?

为什么不直接避免接口的实现并保持简单呢?

有人可能会争辩说,它的定义是为了让可能扩展Scanner的类能够实现该方法,就像AbstractList有一个add方法抛出一个UnsupportedOperationException。但是AbstractList是一个abstract类,而Scanner是一个final类。

这不是一个糟糕的设计实践吗?


共有3个答案

宰父俊彦
2023-03-14

有关官方答案,请参阅集合框架概述。向下滚动至底部以查看设计目标。

为了保持核心接口的数量较小,这些接口不试图捕捉诸如可变性、可修改性和可调整性等细微差别。相反,核心接口中的某些调用是可选的,使实现能够抛出UnsupportedOperationException,以指示它们不支持指定的可选操作。集合实现者必须清楚地记录实现支持哪些可选操作。

正如前面的答案所指出的那样,集合框架可以通过将其接口分解为许多更小的接口来支持Liskov substation。为了尽量减少框架中核心接口的数量,考虑并拒绝了这种方法。

马弘益
2023-03-14

因为实现迭代器允许在任何可以使用只读迭代器的地方使用扫描器。

此外,它确实执行了合同。从迭代器文档(我的重点):

remove()从基础集合中移除此迭代器返回的最后一个元素(可选操作)。

安承教
2023-03-14

我会说是的,这是一个设计缺陷。该漏洞位于迭代器中。此问题可能与试图创建不可变的集合实现的问题属于同一类别。

它违反了接口隔离原则,并迫使开发人员在JavaDocs中包含一个角落大小写(臭名昭著的Unsupport tedoperationExc0019),以避免违反Liskov Subsittion原则。您可以在集合#移除方法中找到这一点。

我相信设计可以通过分解接口来改进,将hasNext()Next()分离到一个新的(不可变的)接口中,并让(可变的)Iterator接口从中派生:

interface Traversable<E> {
    boolean hasNext();
    E next();
}

interface Iterator<E> extends Traversable<E> {
    void remove();
}

final class Scanner implements Traversable<String> {

}

当然可以用更好的名字。请不要因为我糟糕的命名选择而写下这篇文章。

Scanner不是遍历集合的迭代器。但是扫描器的想法是为它提供“扫描”的输入,从某种意义上说,这是对某些东西(字符串中的字符)的迭代。

我可以理解为什么Scanner将实现Iterator(您要求使用用例)。例如,如果您想创建自己的Iterable类型来迭代指定分隔符的String

class ScannerWrapper implements Iterable<E> {
    public Scanner scanner;

    public ScannerWrapper(Scanner scanner) {
        this.scanner = scanner;
    }

    public Iterator<String> iterator() {
        return scanner;
    }
} 

Scanner scanner = new Scanner("one,two,three");
scanner.useDelimiter(",");
ScannerWrapper wrapper = new ScannerWrapper(scanner);

for(String s : wrapper) {
    System.out.println(s);
}

但是,如果JDK支持Traversable类型并允许增强的循环接受Traversable项,这也会起作用,因为以这种方式从集合中删除可能会抛出一个ConnettModificationExc0019,这导致使用迭代器相反。

那么这是一个好的设计吗?不。它违反了ISP,导致合同混乱。这只是一种巨大的代码味道。真正的问题是该语言缺乏对不变性的支持,这应该允许开发人员指定行为是否应该改变状态,从而使行为契约不再具有可变性。或者类似的东西。。

JDK中充满了这样的东西(糟糕的设计选择,比如为数组暴露length,尝试ImmutableMap),现在更改它会导致代码中断。

 类似资料:
  • 我写了一个小程序,它检查字符串是否按照用户输入的字母顺序排序,并用空白隔开一行。它的工作,这是伟大的,但我不明白的是,为什么我可以使用扫描器创建数组时,大小还没有设置。任何见解都将不胜感激。

  • 因此,我是一个新的Java程序员,我正试图弄清楚为什么一段代码不能工作。我遇到的问题是“String interests=input.nextLine();”这一行,它跳过了用户的输入并跳转到下一个System.out,所以它只显示“Your Profile...”。在允许用户输入任何数据之前。抱歉,如果这是一个愚蠢的问题,我是很新的!

  • 问题内容: 我的Java作业有问题。我遇到了意外的异常,特别是: java.util.NoSuchElementException:找不到行 我正在使用,该程序不断读取任何内容,并重复“无效格式”异常文本。如果输入正确的值,则第一部分通过,然后该部分立即进入此异常。如果输入的值不正确,则它将开始循环异常。 这是我的代码: 问题答案: 您关闭了多个库,这些库关闭了底层库,因此另一个库将不再从同一库和

  • 问题内容: 使用Scanner类中的useDelimiter时遇到一些问题。 如果我有这个输入 美国广播公司 输出将是 AB 然后等到我键入另一个“-”以打印出最后一个字符 但是,如果我没有用户输入数据,而是将字符串插入到Scanner中,则代码将起作用。原因是什么?如何解决?我不想使用StringTokenzier 问题答案: 如果没有等待您输入另一个,则将错误地假定您已完成输入。 我的意思是,

  • 我做了一个程序,要求3个整数来输出三角形的类型。所有内容都成功运行和编译,但是,在要求用户查看是否要再次循环的部分,联机编译器会输出错误: 异常线程"main"java.util.NoSuchElement异常在java.util.Scanner.throwFor(Scanner.java:838)在java.util.Scanner.next(Scanner.java:1347)在Assignm

  • 问题内容: 我不明白为什么第15行不做任何输入,将不胜感激:3 输出量 请输入您的问题的第一个数字!2552所以您选择了2552选择您的第二个数字41您选择了第二个数字41现在输入ur运算符 由于某种原因,输出在最后一行结束并停止,并且不接收任何信息! 问题答案: 您需要在调用行的后面立即调用,原因是仅要求下一个整数不会占用输入中的整个行,因此您需要通过调用来跳至输入中的下一个新行字符。 每次您需