- 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/
我正在尝试表达以下内容: 给定一个矩阵和两个索引增量,返回矩阵中所有数字的四倍体:沿行,列或对角线的四倍体。 use std::iter::Iterator; use std::iter::Peeka
假设我们有以下类组成角色 Iterable : class Word-Char does Iterable { has @.words; method !pairize($item)
我编写了一个 ADT 排序二叉树,其功能如下: public Iterator getInorderIterator(){ return new InorderIterator(); } 有效
在包装(内部)迭代器时,通常必须将 __iter__ 方法重新路由到底层可迭代对象。考虑以下示例: class FancyNewClass(collections.Iterable): def
尽管如此,我遍历了以下 NSSet , NSMutableArray , NSFastEnumeration文档,我找不到下面提到的场景的令人满意的来源: 此处,NSMutableArray、NSAr
我发现在 Python 中 collections.Iterable 和 typing.Iterable 都可以用于类型注释和检查对象是否可迭代,即 >isinstance(obj, collecti
我想拆分实现 Iterator 的对象的输出分为两个实现 Iterator 的对象和 Iterator .由于其中一个输出的迭代次数可能比另一个多,因此我需要缓冲 Iterator 的输出。 (因为我
我正在尝试用 Rust 编写一个简单的迭代器: #[derive(Debug)] pub struct StackVec { storage: &'a mut [T], len: us
什么意思: Separator.Iterator.Element == Self.Iterator.Element.Iterator.Element 在this (Swift 标准库)swift 实例
调用 anIterable.iterator() 会返回新的迭代器还是现有的迭代器?它依赖于 Iterable 的实现吗? 更具体地说,以下代码是否按预期工作(即内部循环将从头开始迭代)? for (
我正在尝试转换 &str 的矢量对成一个 HashMap使用以下代码片段: use std::collections::HashMap; fn main() { let pairs = vec!(
这将使安全地迭代同一元素两次成为可能,或者为在项目类型中迭代的全局事物保持某种状态。 类似于: trait IterShort where Self: Borrow, { type I
我在 String 的字符上使用迭代器: pub fn is_yelling(message: &str) -> bool { let letters = message.chars().fi
这将使安全地迭代同一元素两次成为可能,或者为在项目类型中迭代的全局事物保持某种状态。 类似于: trait IterShort where Self: Borrow, { type I
要在 Rust 中实现迭代器,我们只需要实现 next 方法,如 in the documentation 所解释的那样.但是,Iterator 特征 has many more methods .
我正在为多个结构实现 Iterator 特性并遇到了一些问题。为什么为 Rows 实现 Iterator 显示错误?这是一个链接:link to playground 基本上为什么这不起作用? str
我将集合转储到磁盘上。当请求时,应该检索这些集合(没问题)和 iterator应该为它构建返回对检索到的值的引用。 iterator之后被丢弃了,我不再需要收藏了。我也希望它被删除。 到目前为止我尝试
我正在尝试为实现特征的结构实现默认迭代器。我的特征称为 DataRow,代表一行表格单元格,如下所示: pub trait DataRow { // Gets a cell by index
Rust 中是否有提供 iter() 的 Trait方法?我只找到了特征 IntoIterator ,供应into_iter() . 这里要明确一点:我不想要 Iterator特性,提供 next()
我想在迭代器上定义一个 .unique() 方法,使我能够在没有重复的情况下进行迭代。 use std::collections::HashSet; struct UniqueState {
我是一名优秀的程序员,十分优秀!