Java中Iterator接口的好处是什么?
我刚刚了解了Java Collections Framework如何在链表中实现数据结构。据我了解,"迭代器"是一种遍历列表等数据结构中各项的方式。为什么使用此接口?为什么方法hasNext(),next()和remove()没有直接编码到数据结构实现本身?
从Java网站:链接文本
public interface Iterator<E> An iterator over a collection. Iterator takes the place of Enumeration in the Java collections framework. Iterators differ from enumerations in two ways: Iterators allow the caller to remove elements from the underlying collection during the iteration with well-defined semantics. Method names have been improved. This interface is a member of the Java Collections Framework.
我尝试在Google上四处搜寻,但似乎找不到确切的答案。有人可以阐明Sun为什么选择使用它们吗?是因为设计更好吗?增加安全性?好的OO实践?
任何帮助将不胜感激。谢谢。
解决方案
好吧,第一个要点似乎允许多线程(或者单线程,如果我们搞砸了)应用程序,无需为并发冲突而锁定集合。例如,在.NET中,如果没有锁定或者继承IEnumerable和重写方法(我们会得到例外),则无法同时枚举和修改集合(或者列表或者任何IEnumerable)。
一篇有趣的论文,讨论了使用迭代器的优缺点:
http://www.sei.cmu.edu/pacc/CBSE5/Sridhar-cbse5-final.pdf
我认为这只是很好的面向对象做法。我们可以拥有处理各种迭代器的代码,甚至为我们提供创建自己的数据结构或者仅实现迭代器接口的通用类的机会。我们不必担心其背后的实现方式。
迭代器只是添加了一种遍历项目集合的通用方法。 i.remove()是不错的功能之一,我们可以在其中从要迭代的列表中删除元素。如果我们只是尝试从列表中正常删除项目,则会产生怪异的效果或者引发异常。
接口就像实现它的所有事物的契约。我们基本上是说..保证实现迭代器的所有对象都具有这些行为相同的方法。如果我们只想在代码中处理迭代器类型,则还可以使用它来传递迭代器类型。 (我们可能不关心列表的类型是什么。我们只想传递一个Iterator)可以将所有这些方法独立地放入集合中,但不能保证它们的行为相同或者什至具有相同的名称,签名。
因为我们可能正在遍历不是数据结构的内容。假设我有一个联网的应用程序,可以从服务器获取结果。我可以围绕这些结果返回一个Iterator包装器,并通过任何接受Iterator对象的标准代码将其流式传输。
将其视为良好的MVC设计的关键部分。数据必须以某种方式从模型(即数据结构)到达视图。使用Iterator作为过渡,可确保永远不会暴露Model的实现。我们可能将LinkedList保留在内存中,从解密算法中提取信息或者包装JDBC调用。它对视图无所谓,因为视图仅在乎Iterator接口。
如果我们不知道,则只是M2C:在for-each循环就足够的情况下,可以避免直接使用迭代器接口。
迭代器是Java中可用的许多设计模式之一。设计模式可以被认为是方便的构建块,样式,代码/结构的用法。
要了解有关Iterator设计模式的更多信息,请访问有关Iterator以及其他许多设计模式的网站。以下是Iterator网站上的摘录:http://www.patterndepot.com/put/8/Behavioral.html
The Iterator is one of the simplest and most frequently used of the design patterns. The Iterator pattern allows you to move through a list or collection of data using a standard interface without having to know the details of the internal representations of that data. In addition you can also define special iterators that perform some special processing and return only specified elements of the data collection.
迭代器可用于任何种类的集合。它们使我们可以针对项目集合定义算法,而与基础实现无关。这意味着我们可以处理列表,集合,字符串,文件,数组等。
从现在开始的十年后,我们可以将List实现更改为更好的实现,并且该算法仍将针对该实现无缝运行。
使用Iterator
接口允许任何实现其方法的类充当迭代器。 Java接口的概念应以某种方式承担合同义务,即在"实现"接口的类中提供某些功能,以接口所要求的方式起作用。由于必须履行合同义务才能成为有效类,因此其他类(通过类实现接口)因此可以放心地知道该类将具有某些特定功能。
在此示例中,与其在LinkedList类本身中实现方法(hasNext(),next(),remove()),LinkedList类将声明其实现了Iterator接口,因此其他人都知道LinkedList可以用作迭代器。反过来,LinkedList类将从Iterator接口(例如hasNext())实现方法,因此它可以像迭代器一样工作。
换句话说,实现接口是一种面向对象的编程概念,旨在让其他人知道某个类具有它所声称的要具备的功能。
通过具有必须由实现接口的类实现的方法来强制执行此概念。这样可以确保希望使用实现Iterator接口的类的其他类确实具有Iterators应该具有的方法,例如hasNext()。
另外,应该注意的是,由于Java没有多重继承,因此可以使用接口来模拟该功能。通过实现多个接口,一个人可以拥有一个类,该类是继承某些功能的子类,并且还可以通过实现一个接口来"继承"另一个功能。一个例子是,如果我想拥有一个名为ReversibleLinkedList的LinkedList类的子类,它可以以相反的顺序进行迭代,那么我可以创建一个名为ReverseIterator的接口并强制它提供一个previous()方法。由于LinkedList已经实现了Iterator,因此新的可逆列表将同时实现Iterator和ReverseIterator接口。
我们可以从什么是接口中阅读有关接口的更多信息。来自Sun的Java教程。
Why is this interface used?
因为它支持允许客户端程序员迭代任何种类的集合的基本操作(注意:不一定是"对象"意义上的"集合")。
Why are the methods... not directly coded to the data structure implementation itself?
它们是,它们只是标记为"私人",因此我们无法进入它们并与它们混为一谈。进一步来说:
- 我们可以实现或者继承"迭代器",使其能够执行标准迭代器无法执行的操作,而不必更改迭代的实际对象。
- 可以遍历的对象不需要使用遍历方法(尤其是任何高度专业化的方法)来弄乱它们的接口。
- 我们可以将"迭代器"分发给任意数量的客户,每个客户可以自己的速度遍历自己的时间。
- 如果在仍然有Iterator的情况下修改了支持它们的存储,则java.util包中的Java Iterators将抛出异常。这个异常让我们知道
Iterator
现在可能正在返回无效的对象。
对于简单的程序,这似乎都不值得。但是,使它们有用的那种复杂性很快就会浮现出来。
当我们使用Java处理集合时,迭代器非常有用。
使用For-Each循环(Java1.5)遍历集合,数组或者列表。
最终,因为Iterator捕获了适用于大量数据结构的控件抽象。如果我们对类别理论感到满意,那么我们可以被这篇论文震惊:迭代器模式的本质。
我们会问:"为什么方法hasNext(),next()和remove()没有直接编码到数据结构实现本身?"。
Java Collections框架选择将Iterator接口定义为集合本身的外部化接口。通常,由于每个Java集合都实现了" Iterable"接口,因此Java程序会调用" iterator"来创建自己的迭代器,以便可以在循环中使用它。正如其他人指出的那样,Java 5允许我们通过for-each循环直接使用迭代器。
将迭代器外部化为其集合可允许客户端控制一个迭代器如何通过一个集合。我可以想到的一个用例是,当一个人拥有一个不受限制的集合时,例如Internet上所有要索引的网页。
在经典的GoF书中,非常清楚地阐明了内部和外部迭代器之间的对比。
A fundamental issue is deciding which party conrols the iteration, the iterator or the client that uses the iterator. When the client controls the iteration, the iterator is called an external iterator, and when the iterator controls it, the iterator is an internal iterator. Clients that use an external iterator must advance the traversal and request the next element explicitly from the iterator. In contrast, the client hands an internal iterator an operation to perform, and the iterator applies that operation to every element .... External iterators are more flexible than internal iterators. It's easy to compare two collections for equality with an external iterator, for example, but it's practically impossible with internal iterators ... But on the other hand, internal iterators are easier to use, because they define the iteration logic for you.
有关内部迭代器如何工作的示例,请参见Ruby的" Enumerable" API,该API具有内部迭代方法,例如" each"。在Ruby中,其想法是将代码块(即闭包)传递给内部迭代器,以便集合可以处理自己的迭代。
可以同时使用Interator的多个实例。将它们作为基础数据的本地游标进行处理。
顺便说一句:优先于具体实现的接口松散耦合
寻找迭代器设计模式,然后在这里:http://en.wikipedia.org/wiki/Iterator
重要的是要使集合与指针分开。迭代器指向集合中的特定位置,因此不是集合的组成部分。这样,对于一个实例,我们可以在同一个集合上使用多个迭代器。
这种分离的不利之处在于,迭代器不知道对其进行迭代的集合所做的更改。因此,我们不能更改集合的结构,不能期望迭代器在没有"投诉"的情况下继续进行工作。