Iterator<String> iterator=...
//right way
for (Iterator<String> i = iterator; i.hasNext(); ){
System.out.println(i.next());
}
//why can't?
for(String i:iterator){
}
Reference:
http://docs.oracle.com/javase/1.5.0/docs/guide/language/foreach.html
http://docs.oracle.com/javase/6/docs/api/java/util/Iterator.html
You can do more compactly:
for(String i:list){
}
The syntax is only for Iterables (and arrays), not for their Iterators directly (and also not for Enumerations).
Why not? I don't know... Maybe too much complexity/effort (in the compiler implementation) for a "rare" case. Or edge-cases that would cause trouble (such as an Iterable that is also an Iterator, I think some people make such beasts).
Maybe try libraries like Google Guava to get some more convenient ways to work with Iterators, Collections, and friends.
The compiler checks the syntax for the for enhanced and requires that the expression after the colon returns an object that implements the Iterable interface. Iterator doesn't implement it.
You can only use the for loop syntax with objects that implement the Iterable interface.
Iterators are not iterable.
for(String i:list){
//
}
Related
I am aware of the conventional iterator creation-usage for a List<String> list as below:
//Conventional-style
Iterator<String> iterator = list.iterator()
while(iterator.hasNext()){
String string = iterator.next();
//...further code goes here
}
However, in the accepted answer of Iterating through a Collection, avoiding ConcurrentModificationException when removing in loop, I came across this unusual for loop usage with Iterator:
//Unconventional for loop style
for (Iterator<String> iterator = list.iterator(); iterator.hasNext();) {
String string = iterator.next();
//...further code goes here
}
Now, I'd like to know:
Does this unconventional style create the iterator on the collection for each iteration over and over again? Or is it somehow a special kind of intelligent for-loop, which creates the iterator once and reuses it?
If it creates an iterator each time, shouldn't it be a performance concern?
Can we replace the while loop line in the conventional style with
for(;iterator.hasNext();), if I were to use a for loop only?
PS: I am well aware of the enhanced for loop use on a collection. I am looking at this with the intention of 'safe' removal of elements, without causing a ConcurrentModificationException.
The idiom you call "unconventional" is actually the recommended one because it restricts the scope of the iterator variable to the loop where it is used.
The iterator is created once, before the loop begins. This follows from the general semantics of the for loop, which I warmly advise you get acquainted with.
You can, but you would not be recommended to. Such an idiom would be a pointless obfuscation of the while idiom.
Finally, note that for 99% of use cases all of the above is moot because you really should be using either the enhanced for loop or Java 8 forEach.
Java is derived from C, and thus for (A; B; C) { P; } has the same semantics as A; while (B) { P; C; }. The only difference is the scope of the variables. In particular, the A part is only executed once. So your two code examples do exactly the same, but in the for-variant the scope of the variable is restricted.
The more modern way of iterating through a collection is the enhance for loop:
for (String string : list) {
...
}
However, if you want to delete or change items while iterating through it, you still need the iterator version. For example:
for (Iterator<String> it = list.iterator(); it.hasNext();) {
String string = it.next();
if (someFunction(string)) {
it.delete();
}
}
has no enhanced for-loop equivalent.
1.
No, it does not create an iterator over and over again.. This was the perfectly fine style before Java included the interface Iterable<T>.
If you want to remove an item while iterating over the collection you have to use the iterator.remove() method if it is provided.. Because otherwise a ConcurrentModificationException will be thrown.
If you do not want to remove an Item while iterating over the collection then you should just use the for each concept, which is provided by every collection that implements the Iterable<T> interface. (link in the end for more information)
for (String s : yourList) {
... // do something with the string
}
2.
Yes!! Use the for loop idiom. But as I said, if you do not want to use the iterator.remove() operation, but just want to iterate over the collection, you should use the provided for each concept.
You can find a lot of information on the downsides of the iterator.next() approach here and why the newly integrated for:each concept is better:
https://docs.oracle.com/javase/1.5.0/docs/guide/language/foreach.html
Just need a quick clarification:
While using the iterator class, can I create a iterator object like below:
Option1: <Class-name>Iterator [Iterator-object] = <object-name>.iterator();
or should i be sticking to
Option2: Iterator<Class-name> [Iterator-object] = <object-name>.iterator();
Can you briefly explain why the suggested one is correct?
Use Option 2. As syntactically correct Java, it will enable your program to be compiled.
Iterator<T> iter = someObject.iterator() is correct.
But if someObject is Iterable (like, for example, a java.util.List) and all you need to do is actually iterator over it, use a 'for-each' loop:
for(T thing : someObject) { /* do stuff with 'thing' */ }
Did you look at the documentation?
Iterator<E> iterator()
...
all depends on what you exaclty wanted to itrate either a ArrayList/List or any other collection of string /object.
eg you wanted to itrate on a ArrayList then you take
ArrayList al =(you data );
Itrator itr=al.itrator ();
also you can view how to use itrators for help http://www.javapractices.com/topic/TopicAction.do?Id=125
I very much like the for-each-loop construction (for(T e : iterable)) in Java which works on any Iterable<T> because it makes in many cases very easy to read and to write code.
I wonder though if there is any way that I can access the underlying iterator from such a loop. This can be mandatory if I want to use the remove() from the iterator.
No, the whole point of the for-each-loop is to abstract away the underlying iterator.
If you need it, you must declare it.
No, you cannot remove objects in a for each loop.
Use this instead:
Iterator<Type> it = collection.iterator();
while (it.hasNext()) {
if (it.next().shouldBeRemoved()) {
it.remove();
}
}
Use a for loop instead.
If the collection is reasonably small, you can alternatively use a copy of the collection to iterate if you want to be able to remove elements so you won't have to act as if you have two collections.
for(T e : collection.clone())
if(e.shouldBeRemoved())
collection.remove();
Even better, Apache CollectionUtils (and there is probably a Google alternative and a generics alternative) provides filter(java.util.Collection collection, Predicate predicate). This example returns the whole list. You can store a predicate for reuse.
CollectionUtils.filter(collection, new Predicate(){
boolean evaluate(Object object){return true;}
});
You are correct, using an Iterator supports the ability to remove an object from a source collection safely, by calling remove() on the Iterator itself. The point here is to avoid a ConcurrentModifiedException which implies that a collection was modified while an Iterator was open against it. Some collections will let you get away with removing or adding elements to a Collection while iterating across it, but calling remove() on the Iterator is a safer practice.
But Iterator supports a derived and more powerful cousin ListIterator, only available from Lists, supports both adding and removing from a List during iteration, as well as bidirectional scrolling through Lists.
modifying data has a wrong feel to it, Just create a new Iterable(or collection) and add the items you want to keep to it, the other times are lost in the for loop ((kinda**
I read Why is Java's Iterator not an Iterable? and Why aren't Enumerations Iterable?, but I still don't understand why this:
void foo(Iterator<X> it) {
for (X x : it) {
bar(x);
baz(x);
}
}
was not made possible. In other words, unless I'm missing something, the above could have been nice and valid syntactic sugar for:
void foo(Iterator<X> it) {
for (X x; it.hasNext();) {
x = it.next();
bar(x);
baz(x);
}
}
Most likely the reason for this is because iterators are not reusable; you need to get a fresh Iterator from the Iterable collection each time you want to iterate over the elements. However, as a quick fix:
private static <T> Iterable<T> iterable(final Iterator<T> it){
return new Iterable<T>(){ public Iterator<T> iterator(){ return it; } };
}
//....
{
// ...
// Now we can use:
for ( X x : iterable(it) ){
// do something with x
}
// ...
}
//....
That said, the best thing to do is simply pass around the Iterable<T> interface instead of Iterator<T>
but I still don't understand why this [...] was not made possible.
I can see several reasons:
Iterators are not reusable, so a for/each would consume the iterator - not incorrect behavior, perhaps, but unintuitive to those who don't know how the for/each is desugared.
Iterators don't appear "naked" in code all that often so it would be complicating the JLS with little gain (the for/each construct is bad enough as it is, working on both Iterables and arrays).
There's an easy workaround. It may seem a little wasteful to allocate a new object just for this, but allocation is cheap as it is and escape analysis would rid you even of that small cost in most cases. (Why they didn't include this workaround in an Iterables utility class, analogous to Collections and Arrays, is beyond me, though.)
(Probably not true - see the comments.) I seem to recall that the JLS can only reference things in java.lang[citation needed], so they'd have to create an Iterator interface in java.lang which java.util.Iterator extends without adding anything to. Now we have two functionally equivalent iterator interfaces. 50% of the new code using naked iterators will choose the java.lang version, the rest use the one in java.util. Chaos ensues, compatibility problems abound, etc.
I think points 1-3 are very much in line with how the Java language design philosophy seems to go: Don't surprise newcomers, don't complicate the spec if it doesn't have a clear gain that overshadows the costs, and don't do with a language feature what can be done with a library.
The same arguments would explain why java.util.Enumeration isn't Iterable, too.
The for(Type t : iterable) syntax is only valid for classes that implement Iterable<Type>.
An iterator does not implement iterable.
You can iterate over things like Collection<T>, List<T>, or Set<T> because they implement Iterable.
The following code is equivalent:
for (Type t: list) {
// do something with t
}
and
Iterator<Type> iter = list.iterator();
while (iter.hasNext()) {
t = iter.next();
// do something with t
}
The reason this was not made possible, is because the for-each syntax was added to the language to abstract out the Iterator. Making the for-each loop work with iterators would not accomplish what the for-each loop was created for.
Actually, you can.
There is very short workaround available on java 8:
for (X item : (Iterable<X>) () -> iterator)
See How to iterate with foreach loop over java 8 stream for the detailed explanation of the trick.
And some explanations why this was not natively supported can be found in related question:
Why does Stream<T> not implement Iterable<T>?
Iterators are not meant be reused (i.e.: used in more than one iteration loop). In particular, Iterator.hasNext() guarantees that you can safely call Iterator.next() and indeed get the next value from the underlying collection.
When the same iterator is used in two concurrently running iterations (let's assume a multi-threading scenario), this promise can no longer be kept:
while(iter.hasNext() {
// Now a context switch happens, another thread is performing
// iter.hasNext(); x = iter.next();
String s = iter.next();
// A runtime exception is thrown because the iterator was
// exhausted by the other thread
}
Such scenarios completely break the protocol offered by Iterator. Actually, they can occur even in a single threaded program: an iteration loop calls another method which uses the same iterator to perform its own iteration. When this method returns, the caller is issuing an Iterator.next() call which, again, fails.
Because the for-each is designed to read as something like:
for each element of [some collection of elements]
An Iterator is not [some collection of elements]. An array and an Iterable is.
In Java 5 and above you have the foreach loop, which works magically on anything that implements Iterable:
for (Object o : list) {
doStuff(o);
}
However, Enumerable still does not implement Iterable, meaning that to iterate over an Enumeration you must do the following:
for(; e.hasMoreElements() ;) {
doStuff(e.nextElement());
}
Does anyone know if there is a reason why Enumeration still does not implement Iterable?
Edit: As a clarification, I'm not talking about the language concept of an enum, I'm talking a Java-specific class in the Java API called 'Enumeration'.
As an easy and clean way of using an Enumeration with the enhanced for loop, convert to an ArrayList with java.util.Collections.list.
for (TableColumn col : Collections.list(columnModel.getColumns()) {
(javax.swing.table.TableColumnModel.getColumns returns Enumeration.)
Note, this may be very slightly less efficient.
It doesn't make sense for Enumeration to implement Iterable. Iterable is a factory method for Iterator. Enumeration is analogous to Iterator, and only maintains state for a single enumeration.
So, be careful trying to wrap an Enumeration as an Iterable. If someone passes me an Iterable, I will assume that I can call iterator() on it repeatedly, creating as many Iterator instances as I want, and iterating independently on each. A wrapped Enumeration will not fulfill this contract; don't let your wrapped Enumeration escape from your own code. (As an aside, I noticed that Java 7's DirectoryStream violates expectations in just this way, and shouldn't be allowed to "escape" either.)
Enumeration is like an Iterator, not an Iterable. A Collection is Iterable. An Iterator is not.
You can't do this:
Vector<X> list = …
Iterator<X> i = list.iterator();
for (X x : i) {
x.doStuff();
}
So it wouldn't make sense to do this:
Vector<X> list = …
Enumeration<X> i = list.enumeration();
for (X x : i) {
x.doStuff();
}
There is no Enumerable equivalent to Iterable. It could be added without breaking anything to work in for loops, but what would be the point? If you are able to implement this new Enumerable interface, why not just implement Iterable instead?
Enumeration hasn't been modified to support Iterable because it's an interface not a concrete class (like Vector, which was modifed to support the Collections interface).
If Enumeration was changed to support Iterable it would break a bunch of people's code.
AFAIK Enumeration is kinda "deprecated":
Iterator takes the place of
Enumeration in the Java collections
framework
I hope they'll change the Servlet API with JSR 315 to use Iterator instead of Enumeration.
If you would just like it to be syntactically a little cleaner, you can use:
while(e.hasMoreElements()) {
doStuff(e.nextElement());
}
It is possible to create an Iterable from any object with a method that returns an Enumeration, using a lambda as an adapter. In Java 8, use Guava's static Iterators.forEnumeration method, and in Java 9+ use the Enumeration instance method asIterator.
Consider the Servlet API's HttpSession.getAttributeNames(), which returns an Enumeration<String> rather than an Iterator<String>.
Java 8 using Guava
Iterable<String> iterable = () -> Iterators.forEnumeration(session.getAttributeNames());
Java 9+
Iterable<String> iterable = () -> session.getAttributeNames().asIterator();
Note that these lambdas are truly Iterable; they return a fresh Iterator each time they are invoked. You can use them exactly like any other Iterable in an enhanced for loop, StreamSupport.stream(iterable.spliterator(), false), and iterable.forEach().
The same trick works on classes that provide an Iterator but don't implement Iterable. Iterable<Something> iterable = notIterable::createIterator;