- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我只是想知道为什么 java.util.Scanner工具 java.util.Iterator ?
Scanner
实现了 remove方法并抛出 UnsupportedOperationException .
但是类在实现接口(interface)时不应该履行接口(interface)的契约吗?
实现iterator
并添加一个抛出异常的方法有什么用?
为什么不直接避免接口(interface)的实现并保持简单呢?
有人可能会争辩说,它的定义是为了让可能扩展 Scanner
的类可以实现该方法,例如 AbstractList有一个 add抛出 UnsupportedOperationException
的方法。但是 AbstractList
是一个 abstract
类,而 Scanner
是一个 final
类。
这不是一个糟糕的设计实践吗?
最佳答案
我会说是的,这是一个设计缺陷。该缺陷存在于 Iterator
中。此问题可能与尝试创建不可变的 Collection
实现属于同一类别。
它违反了Interface Segregation Principle并强制开发人员包含 corner case进入JavaDocs (臭名昭著的 UnsupportedOperationException
)以避免违反 Liskov Subsitution Principle .您会在 Collection#remove
中找到它方法也是如此。
我相信可以通过分解接口(interface)、将 hasNext()
和 next()
分离到一个新的(不可变的)接口(interface)并让(可变的)Iterator
接口(interface)派生自它:
interface Traversable<E> {
boolean hasNext();
E next();
}
interface Iterator<E> extends Traversable<E> {
void remove();
}
final class Scanner implements Traversable<String> {
}
绝对可以使用更好的名称。由于我错误的命名选择,请不要关闭这篇文章。
Scanner
首先要实现Iterator
?Scanner
不是遍历集合意义上的迭代器。但是 Scanner
的想法是为其提供“scanned”输入,这在某种意义上是迭代某些东西(中的字符一个 String
)。
我明白为什么 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
项,这也会起作用,因为以这种方式从集合中删除可能会抛出ConcurrentModificationException
,导致改用迭代器。
那么它是好的设计吗?没有。它违反了 ISP 并导致契约(Contract)困惑。这简直就是一种巨大的代码味道。真正的问题是该语言缺乏对不变性的支持,这应该允许开发人员指定行为是否应该改变状态,从而允许行为契约被剥夺其可变性。或者类似的东西..
JDK 充满了这样的东西(糟糕的设计选择,例如为数组公开 length
并尝试我上面提到的 ImmutableMap
),现在改变它会导致破坏代码。
关于java - Scanner 为什么要实现 Iterator<String>?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31153006/
scanner.Scanner 之间有什么区别?来自包裹text/scanner ,和一个 bufio . Scanner ? 最佳答案 text/scanner更适合阅读源代码,主要是 Go 源代码
我有以下代码: Scanner in = new Scanner (System.in); String[] data = new String[5]; System.out.println("Ple
我有 Java 代码,它要求用户输入,然后将此数据存储在字符串变量中。下面的函数是“number”类的一部分,并在主函数中调用。 public static void setVal(i
我正在编写一个java程序,它运行一个循环并不断询问用户输入。然后程序用该字符串执行一系列操作,并请求另一个字符串并重复。 问题是许多字符串非常相似,所以我想用循环中上次的输入填充提示。例如:如果用户
我在 O'Reillys Java Cookbook(第 2 版)中寻找一些好东西,发现 Scanner.create() 方法大约 10 次。但是在 API 或类声明\实现中没有这样的东西。例如:P
这个问题在这里已经有了答案: Scanner is skipping nextLine() after using next() or nextFoo()? (25 个答案) 关闭 4 年前。 im
这样做有什么好处/坏处吗? 通常,从流中读取时会抛出异常: try { inputStream.read(); }catch(IOException e) { e.printStack
Scanner console=new Scanner(System.in); System.out.print("how many:"); int n=console.nextInt(); cons
这个问题已经有答案了: Scanner is skipping nextLine() after using next() or nextFoo()? (25 个回答) 已关闭 6 年前。 我最近刚刚
Scanner input = new Scanner(System.in); 你能详细解释一下上面的代码一步一步做了什么吗?我真的不明白它是如何工作的以及它如何链接到我以后能够做这个声明: int
这个问题在这里已经有了答案: Scanner is skipping nextLine() after using next() or nextFoo()? (24 个答案) 关闭 6 年前。 我必
如果我在 java.util 上调用 scanner.hasNext(pattern),然后使用相同的模式调用 scanner.next(pattern),我会扫描两次吗?扫描仪 假设我有很多案例的这
这是我的问题: 我正在尝试使用 Scanner 和 System.in 从键盘获取输入并将其分配给 int 变量。 这就是我所拥有的(完整的程序如下): // this program will us
使用 try(Scanner scan = new Scanner(System.in)) { } 导致 Exception in thread "main" java.util.NoSuchElem
很难说出这里问的是什么。这个问题是含糊的、模糊的、不完整的、过于宽泛的或修辞性的,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开它,visit the help center 。 已关
此问题仅用于教育目的。我从 Java 教科书中获取了以下代码,我很好奇为什么在 catch block 中使用了 input.nextLine()。 我尝试使用 input.nextInt() 代替它
这个问题已经有答案了: How to use java.util.Scanner to correctly read user input from System.in and act on it?
我的教授倾向于执行以下操作以从用户那里获取数字: Scanner scanner = new Scanner(System.in); Integer.parseInt(scanner.nextLine
我在使用 Scanner 时出现奇怪的行为。当我使用 Scanner(FileInputStream) 构造函数时,它将与我正在使用的一组特定文件一起使用,但它不适用于 Scanner(File) 构
D 中是否有类似于 Java 扫描仪的流解析器?您可以去哪里nextInt()获取 int和 nextLong()对于 long , 等等。 最佳答案 std.conv.parse 类似: http:
我是一名优秀的程序员,十分优秀!