I. Summary
The iterator pattern is associated with a collection of co-deaths. Generally speaking. We just have to implement a container and we need to provide an iterator to the container at the same time. The advantage of using iterators is that they encapsulate the internal implementation details of the container and provide a unified way of traversing for different collections, simplifying client access and retrieving data within the container. On this basis. We can use Iterator to complete the traversal of the collection. In addition The For loop and the foreach syntax can also be used to traverse the collection class. Listiterator is a bidirectional iterator unique to the container list container family. The main points of this paper include:
- Iterator mode
- Iterator Iterators and Iterable interfaces
- Cyclic traversal: Similarities and differences of foreach,iterator,for
- Listiterator Brief (detailed explanation of container List)
Second, the iterator mode
The iterator pattern is associated with a collection of co-deaths. in general, we only want to implement a container. It is necessary to provide an iterator for this container at the same time. Like Collection in Java (list, Set, and so on). These containers have their own iterators. If we're going to implement a new container. Of course, we also need to introduce an iterator pattern to implement an iterator to our container. The advantage of using iterators is that they encapsulate the internal implementation details of the container. For different collections, it is possible to provide a unified traversal approach, simplifying client access and obtaining data within the container.
However, because the container is too close to the iterator, most languages also provide the corresponding iterator at the same time as the container is implemented, and in most cases. These languages provide containers and iterators that meet our needs. So. The reality of the scenario where we need to implement the iterator pattern is still rare, and we often just need to use the containers and iterators that are already in the language.
1. Definition and structure
Defined
Iterator (Iterator) mode. Also called cursor mode.
Gof gives a way to access individual elements in a container (container) object without exposing the inner details of the container object.
The iterator pattern is visible from the definition and is for the container. we know that access to container objects must involve a traversal algorithm.
You can plug the Traversal method into the container object in a single brain, or not provide any traversal algorithms at all. Let the person who uses the container implement it by himself.
Both of these situations seem to solve the problem. In the former case, however, the container was overloaded with functionality. It is not only responsible for the maintenance of the elements within the "container" (Add, delete, change, check, etc.). and also provide an interface to traverse itself. And the most important thing is. because of the problem of traversing state preservation, you cannot perform multiple traversal of the same container object at the same time, and you need to add a reset operation .
Another way is easy, but the inside details of the container are exposed.
Iterator Pattern Role composition
iterator Role (Iterator): The iterator role is responsible for defining an interface for access and traversal of elements .
Verbose iterator role (concrete Iterator): The detailed iterator role implements the iterator interface and records the current position in the traversal .
container Role (Container): The container role is responsible for defining the interface that creates the detailed iterator role ;
verbose container Role (concrete Container): detailed container role implementation creates an interface for the detailed iterator role -the detailed iterator role and the structure of the container related .
structure Diagram
As can be seen from the structure, the iterator pattern adds an iterator role between the client and the container. The join of the iterator role. Can be very good to avoid the internal details of the container exposure, and also make the design in line with the principle of single responsibility.
It is particularly important to note that in the iterator pattern. The detailed iterator role and the detailed container role are coupled together -the traversal algorithm is closely related to the internal details of the container. In order to get the client program out of the dilemma of coupling with the detailed iterator role, avoiding the change of the detailed iterator role to the client, the iterator pattern abstracts the detailed iterator role, which makes the client program more general and reusable, which is called a polymorphic iteration .
Applicability
1. Access to the contents of a container object without exposing its internal representation;
2. supports multiple traversal of the container object;
3. provides a unified interface for traversing different container structures (that is, support for polymorphic iterations).
2. Example
Because the iterator pattern itself is loosely defined, detailed implementations are also very varied. Let us just cite one example here. Before giving an example, let's start by enumerating how the iterator pattern is implemented.
The iterator role defines the traversed interface. But there is no rule as to who will control the iteration.
In the Java Collection framework, it is the process that the client program controls the traversal, which is called an external iterator . Another implementation is to control the iteration by itself, called an internal iterator .
External iterators are more flexible and powerful than internal iterators, and internal iterators are very weak in the Java language environment;
There is no rule in the iterator pattern to implement the traversal algorithm, as if it were to be implemented in the iterator role as a matter of course.
Because it facilitates the use of different traversal algorithms on a single container, it facilitates the application of a traversal algorithm to different containers. But this destroys the encapsulation of the container-the container role exposes its own private properties, which in Java means exposing its own private properties to other classes;
Well, let's put it in the container role and get it done. The iterator role is raised to simply hold a function that traverses the current location. However, the traversal algorithm is tightly bound to a specific container. In the Java Collection framework, the detailed iterator role provided is the inner class that is defined in the container role. This protects the encapsulation of the container. But at the same time, the container also provides a traversal algorithm interface. And you can expand your own iterators.
Let's look at the implementation of iterators in Java Collection:
//Iterator role that simply defines the traversal interface Public interface Iterator<E> { BooleanHasnext (); E next ();voidRemove ();//Container role, here is an example of a List, which indirectly implements the Iterable interface Public interface Collection<e> extends iterable<E > {... Iterator<e> Iterator (); ...} Public interface List<e> extends Collection<e> { }//detailed container role, is the implementation of the List interface ArrayList and other classes.
In order to highlight the focus here refers to listing and iterator-related content public abstract class abstractlist <e > extends abstractcollection <e > implements list <e > { ... //This is the factory method responsible for creating the detailed iterator role public iterator<e> iterator () {return new Itr ();} //the detailed iterator role. It comes out in the form of an inner class. The abstractlist is intended to extract the public parts of each detailed container role.
//As the detailed iterator role for the inner classPrivate class Itr implements Iterator<E> { intcursor =0;intLastret =-1;a "high-speed failure" mechanism in a collection iteration, which provides the security of the collection during the iteration. There are modcount attributes in ArrayList, and adding and removing operations will make modcount++. //Through the comparison of the two, the iterator can know at a high speed whether there are List.add () similar operations in the iterative process. If there is a high speed failure! intExpectedmodcount = Modcount; Public Boolean Hasnext() {returnCursor! = size (); } PublicObjectNext() {checkforcomodification ();//high-speed failure mechanism Try{Object next = get (cursor); Lastret = cursor++;returnNext }Catch(Indexoutofboundsexception e) {checkforcomodification ();//high-speed failure mechanism Throw NewNosuchelementexception (); } } Public void Remove() {if(Lastret = =-1)Throw NewIllegalStateException (); Checkforcomodification ();//high-speed failure mechanism Try{abstractlist. This. Remove (Lastret);if(Lastret < cursor) cursor--; Lastret =-1; Expectedmodcount = Modcount;//high-speed failure mechanism}Catch(Indexoutofboundsexception e) {Throw NewConcurrentmodificationexception (); } }//high-speed failure mechanism Final voidCheckforcomodification () {if(Modcount! = expectedmodcount)Throw NewConcurrentmodificationexception ();//Throws an exception, iteration terminates}}
use of the iterator pattern
The client program gets the detailed container role first, and then the detailed iterator role through the detailed container role. This allows you to use the detailed iterator role to traverse the container ...
3. Applicable situation
We can see that the iterator pattern brings the following advantages to the application of the container:
1) supports traversing a container role in different ways. Depending on the implementation, there will be differences in effect (e.g.. List of iterator and Listiterator).
2) simplifies the interface of the container.
In Java Collection, however, the container provides a traversal interface for extensibility.
3) simplifies the traversal approach. For the traversal of the collection of objects, it is still more troublesome, for arrays or lists of sequences, we can still get through cursors, but the user needs to walk through the objects on the premise that the set knows very well. But for a hash table. It's more cumbersome for users to traverse them. When the iterator method is introduced. It's a lot easier for users to use.
4) can provide a variety of traversal methods. For example, for an ordered list, we can iterate through the two iterators in reverse order, based on the need to provide a positive sequence traversal. The user simply needs to get the iterator that we have implemented so that we can easily traverse the collection.
5) to the same container object. Able to perform multiple traversal at the same time. Because the traversal state is saved in each iterator object.
6) Good encapsulation, the user only need to get an iterator to be able to traverse. The traversal algorithm does not need to be cared for.
7) in Java Collection, iterators provide a high-speed failure mechanism (ArrayList is thread insecure, after the ArrayList class creates an iterator, unless the list structure is altered by the iterator itself remove or add. Otherwise, the list is changed in any form in any other thread. An iterator immediately throws an exception. High-speed failure) to prevent unsafe operation of iterations under multithreading.
Resulting It is also possible to derive the applicable scope of the iterator pattern:
1) Access the contents of a container object without exposing its internal representation;
2) supports multiple traversal of the container object;
3) provides a unified interface for traversing different container structures (polymorphic iterations).
Three, Iterator iterators and Iterable interfaces
1,Iterator iterator interface: Java.util package
Java provides a dedicated iterator interface Iterator, which enables us to implement the Interface for a container to provide a standard Java iterator.
Traversing a collection with Iterator mode
The Iterator pattern is a standard access method for traversing collection classes. It abstracts the access logic from different types of collection classes. This avoids exposing the internal structure of the collection to the client.
For example, suppose you don't use Iterator. The way to traverse an array is to use an index:
for(int i=0
While traversing a hashset, you must use a while loop or foreach, but you cannot use a For loop:
while((e=e.next())!=null
For both of these methods. The client must know in advance the type of the collection (internal structure), the access code and the collection itself is tightly coupled, unable to separate the access logic from the collection class and the client code, resulting in each collection corresponding to a traversal method, the client code can not be reused. What's more scary is. Suppose you need to change ArrayList to LinkedList later. The original client code must be completely rewritten.
To solve these problems, the iterator pattern always uses the same logic to iterate through the collection:
for
The secret is that the client itself does not maintain a "pointer" that iterates through the collection. All internal states, such as the current element position and whether there is a next element, are maintained by Iterator. And this Iterator is generated by the collection class through the factory method, so. It knows how to traverse the entire collection. And. The client does not deal directly with the collection class. It always controls iterator. Send it a "forward", "backward", "Fetch current element" instruction. It is possible to traverse the entire collection indirectly.
First look at the definition of the Java.util.Iterator interface:
publicinterface Iterator { boolean hasNext(); Object next(); void// 可选操作
Relying on the first two methods can be completed traversal, typical code such as the following:
for// 对o的操作... }
polymorphic iterations: Each collection class may return a different Iterator detail type, and an Array may return arrayiterator. The Set may return Setiterator,tree may return treeiterator, but they all implement the Iterator interface, so the client doesn't care what kind of Iterator it is, it just needs to get this Iterator interface, This is the power of object-oriented.
2. Iterable Interface: Java.lang bag
Java also provides a iterable interface, the function of the Iterable interface is "return" an iterator . The sub-interfaces that we often use to implement this interface are: Collection<e> series, including List<e>, Queue<e>, set<e>. in particular, it is worth mentioning. The Map interface does not implement the Iterable interface. the iterator () method of the interface returns a standard iterator implementation.
Implementing the Iterable interface to implement its own definition class for foreach traversal
The Iterable interface includes a Iterator () method that produces Iterator. And the Iterable interface is used by foreach to implement movement in the sequence. Therefore, implementing this interface allows the object to be the target of a foreach statement, and it can traverse your underlying sequence through the foreach syntax.
In JDK1.5 once, the syntax for traversing a sequence with Iterator:
for// 对o的操作... }
In the JDK1.5 and later versions, foreach was introduced, simplifying the syntax of the above code (but limited to just reading, assuming remove is required). or direct use of Iterator):
for
3. Speculation
Why do you have to implement iterable this interface? Why not implement the iterator interface directly?
Take a look at the collection classes in the JDK. For example, a list or set of family. The Iterable interface is implemented, but the Iterator interface is not implemented directly. it makes sense to think about this: because the core method of the Iterator interface next () or Hasnext () is dependent on the current iteration position of the iterator.
if the Collection directly implements the Iterator interface, it is bound to cause data (pointers) in the collection object to include the current iteration position. When the collection is passed between different methods, the current iteration position is not pre-provisioned. Then the result of the next () method becomes unpredictable. Unless you add a reset () method to the iterator interface. Used to reset the current iteration position. But even then, Collection can only have a current iteration position at the same time (it cannot iterate the same sequence multiple times at the same time: it must wait until the current iteration is complete and reset, and then the ability to iterate again from scratch). The choice to implement the Iterable interface does not mean that each call returns an iterator (Iterator) that counts from the beginning, so that there is no interference between multiple iterators.
Four, Foreach,iterator. For
The format is as follows:
for(variable:collection){ statement; }
Defines a variable that is used to stage each element in the collection and runs the corresponding statement (block).
Collection must be an array or a class object that implements the Lterable interface.
It can be seen that the advantage of using a Foreach Loop statement is that it is more concise, less prone to error, and does not care about the starting and ending values of the subscript. ForEach is not a keyword, a keyword or a for, statements are implemented by iterator, and their greatest difference lies in the Remove () method.
In particular. The general call to delete and join methods is a detailed collection of methods. Like what:
new ArrayList(); list.add(...); list.remove(...);...
But. Assuming that the remove () method of the collection is called during the loop, it causes a loop error, resulting in an error () due to the size of the list.size () during the loop. Iterator的高速失败机制
So, the false idea is to delete an element of the collection in a looping statement, using the Remove () method of the iterator iterator, because its remove () method not only removes the element, but also maintains a flag to record whether it is currently a deleted state, for example, You cannot call its remove () method two times in a row. Called at least once before the next () method. As a result, foreach is intended to make the form of iterator circular access simple. It's more convenient to write.
Of course, the function is not too full, so if you need to use the delete operation, then it should be used in its original form.
Using a For loop versus using an iterator iterator
From the efficiency point of view:
The use of ArrayList is faster for random access , and the Get () method in the For loop. A random access method is used, so the For loop is faster in ArrayList.
The use of LinkedList is a faster sequential access, iterator in the next () method, which is a sequential approach, so in LinkedList, using iterator faster.
From the data structure angle analysis:
Use the For loop for an ordered structure. Can obtain the specified element at high speed according to subscript. The Iterator is suitable for visiting unordered structures, because iterators are positioned by next () and Pre (). The ability to access a collection without order.
The advantage of using Iterator is the ability to iterate through the elements of the collection in the same way, regardless of the internal implementation of the collection class (only if it implements the Java.lang.Iterable interface). Suppose you use Iterator to iterate through the elements in the collection, and once you no longer use the List to organize the data using set, the code that traverses the elements does not have to be changed. If you use for to traverse, then all the algorithms that traverse this collection have to do the corresponding adjustment, because the list is ordered, set unordered, the structure is different, their access algorithm is not the same.
V. Brief introduction of Listiterator
1. Brief introduction
The Listiterator Series table iterator implements the Iterator<e> interface.
The iterator agrees that the ape is traversing the list in either direction, changing the list during iteration, and getting the iterator's current position in the list. The listiterator has no current element, and its cursor position is always located between the element returned by the call to previous () and the element returned by the call next (). an iterator with a list of length n has n+1 a possible pointer position, as illustrated by the following caret example:
Attention. The Remove () and set (Object) methods are not defined according to the cursor position; they are defined by the operation of the last element returned by the call to next () or previous ().
2. Differences with Iterator
The main differences between Iterator and Listiterator are:
Listiterator has the Add () method to add an object to the list, and Iterator cannot;
Both the Listiterator and the Iterator have the Hasnext () and Next () methods to enable sequential backward traversal. However, Listiterator has hasprevious () and previous () methods to enable reverse (sequential forward) traversal, while Iterator is not able;
Listiterator can use Nextindex () and Previousindex () to locate the current index position, while Iterator does not have this function;
Listiterator can be obtained through the Listiterator () method and the Listiterator (int index) method, and Iterator can only be obtained by the Iterator () method;
Both can implement delete objects, but listiterator can use the set () method to implement object changes. Iterator can only traverse and cannot be changed. Due to these features of Listiterator. Can implement the LinkedList, ArrayList and so on list data structure operation.
Reference:
JDK APK 1.6.0
An iterative pattern for Java design patterns in layman's
23 Design Modes (13): Iterator mode
Java program Ape from a dumb bird to a rookie (45) Big Talk design mode (ix) iterator mode and command mode
Java iterators in-depth understanding and use
Java iterators
Iterator and Iterable
Java iterable interface and iterator iterators
Iterator and Listiterator
Overview of Java iterators