我会说是的,这是一个设计缺陷。该漏洞位于 。此问题可能与尝试创建不可变实现属于同一类别。Iterator
Collection
它违反了接口隔离原则,并迫使开发人员在JavaDocs(臭名昭著)中包含一个角落案例,以避免违反Liskov Subsitution原则。您也可以在Collection#remove
methods中找到它。UnsupportedOperationException
我相信设计可以通过分解接口,隔离并放入一个新的(不可变的)接口并让(可变的)接口从中派生来改进: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
Iterator
Scanner
不是遍历集合意义上的迭代器。但是 a 的想法是为其提供要“扫描”的输入,从某种意义上说,这是在迭代某些内容(a 中的字符)。Scanner
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并导致合同混乱。这只是一种吉加甘特代码的气味。真正的问题是该语言缺乏对不可变性的支持,这应该允许开发人员指定行为是否应该改变状态,从而允许行为契约被剥夺其可变性。或类似的东西。
JDK充满了这样的东西(糟糕的设计选择,例如公开数组和我上面提到的尝试),现在更改它会导致代码中断。length
ImmutableMap