I am trying to understand how the following iteration is working, in other words how can we iterate over the this (I have seen this implemented at someone else's program). The method getEl is part of a class C that implements Iterable. Class C itself does not have any containers of type A, but has a private variable of type A. Class A on the other hand has iterable containers (sets of type A and sets of another type D).
public void getEl() {
for(A el : this) {
//do something
}
}
Can someone help me understand what is going on here?
You can iterate over this (whatever type it is) if this also implements Iterable<T>.
Class C implements Iterable<A>, which contains the method iterator() that returns an Iterator<A>.
You can use the enhanced for loop on any object that implements Iterable.
It's equivalent to :
Iterator<A> iter = this.iterator();
while (iter.hasNext()) {
A el = iter.next();
...
}
for ( : ) is just syntax sugar for calling iterator() on the given object, and using the returned iterator object to go through a set of elements (which is entirely determined by the implementation of said iterator). Since this is an instance of a class that implements Iterable, you would look at its iterator() method.
Mostly, it is confusing to see this being used here. However,
C foo = this;
for (A el : foo) {}
Is just the same.
Related
I have the following code:
HashMap<Integer, String> h = new HashMap<Integer, String>();
h.put(1, "a");
h.put(2, "b");
h.put(3, "c");
h.put(4, "d");
System.out.println(h); //{1=a, 2=b, 3=c, 4=d}
Collection<String> vals = h.values();
System.out.println(vals); //[a, b, c, d]
Iterator<String> itr = vals.iterator();
while (itr.hasNext()) //a b c d
{
System.out.print(itr.next() + " ");
}
My Questions:
h.values() returns a Collection view of values in h. Since vals is an interface, how can we assign some values to an interface (they cannot be instantiated)? Where is the class that is implementing this interface? Where is the object of that class?
Similar question for itr. We know vals.iterator() returns first element of the collection. How can we assign it to an interface instance?
The underlying principle that governs the answers to your questions is called the Liskov's Substitution Principle which applies in this case to assign the value that is of an instance of a given interface (Collection, Iterator) to a reference whose type is a class that implements that interface (e.g. AbstractCollection, Some anonymous class etc).
If you see the HashMap#values() method code, you'll see in Java 8 source code:
public Collection<V> values() {
Collection<V> vs;
return (vs = values) == null ? (values = new Values()) : vs;
}
final class Values extends AbstractCollection<V> {
public final int size() { return size; }
public final void clear() { HashMap.this.clear(); }
...
}
Thus, you are being returned either
an instance of Values class which extends an AbstractCollection which implements Collection, or
an instance of a concrete subclass of AbstractCollection (see: values = new AbstractCollection<V>() at line 386 in AbstractMap.java in Java 8 source code.
Again, according to the LSP, this is all valid. To understand how all this is wired up, you'll need to grok the JDK code base.
More Answers
h.values() returns a Collection view of values in h. Since vals is an interface, how can we assign some values to an interface (they cannot be instantiated)?
To be precise, vals is not an interface, but an instance thereof. It's true that you can not instantiate an interface say Listener using the new operator like listener l = new Listener(), but according to the LSP, you can always instantiate a concrete implementation of the Listener interface and assign it to a variable whose type is Listener, like for example, Listener listener = new SerialListener();
Where is the class that is implementing this interface?
In this case, it is the Values class or AbstractCollection class as shown above.
Where is the object of that class?
In several cases, it is an instance of the anonymous inner class that is instantiated at the time of its definition.
We know vals.iterator() returns first element of the collection.
Not quite right. It returns an instance of a class that implements the Iterator interface. If and when you call the next() method on the returned object, you get the first element of the collection (assuming it is not empty).
How can we assign it to an interface instance?
The idea is the same. If the variable on the left hand side of an assignment statement (left of = sign) refers to an interface, then the right hand side can refer to a reference to an object that implements that interface, directly or indirectly (via inheritance hierarchy).
Given a class of the below structure:
public class Section extends IterableWidgetTemplate<Item>{
private List<WebElement> items1;
// other non iterable methods
private int indexOf(final Item item) {
int i = Iterables.indexOf(this, new Predicate<Item>() {
. . .
});
return i;
}
where Iterables is a Guava com.google.common.collect.Iterables that, according to its documentation, contains static utility methods that operate on objects of type Iterable.
Now in the class that I described above, this is passed as an iterable to the private int indexOf() method.
Questions:
What am I going to iterate over in this object? Am I right in my assumption that the Iterables class will use the only iterable method that is available in the object that is being passed to it? So in this case we have the List<WebElement> variable inside this object.
If the answer to 1. is "yes", what would have happened if the Section class had more than one iterable variable? Which one of them will be used for iteration?
Iterables.indexOf() takes as its first parameter an object which implements the Iterable interface. So, what Iterables.indexOf() iterates over is defined by the object passed in as a parameter, in your example the Section class. It's not using a variable however - it will call the Iterable.iterator() method on your Section object. It's not possible to have more than one of those methods so there can be no cases where there's confusion about what Iterables.indexOf() will iterate over.
My question is: Is it possible to go through a container only by implementing Iterator, i.e. without implementing Iterable?
Is it possible to do this:
//From somewhere
Container c = new Container();
//I add elements to the list in the c object.
for(String s : c){
//Warning: It is not applicable for this expression...
}
class Container implements Iterator<String>{
//Here I implement a single linked list
//Here I implement all of the methods of Iterator
}
Even though this kind of design is nothing but ridiculous, and just to entertain your question, you can write this:
public class Container implements Iterable<String>, Iterator<String> {
#Override public Iterator<String> iterator() { return this; }
... everything else you envision for your class ...
}
Then you'll be able to use
for (String s : container)
You may write this as a learning experience, but I strongly advise you never to try it on a real project. The main reason against it is the expectation on the iterator method to always return a fresh, independent iterator, while this implementation achieves the opposite. To give a specific example, imagine someone needing to iterate over the Cartesian product of your container with itself:
for (String s1 : container)
for (String s2 : container)
processPair(s1, s2);
Every Java programmer will tell you that, beyond any doubt, processPair will be called with each possible pair from the container. The behavior they would instead see from your class would make their heads spin. If a bug in production was ever traced to this implementation, your teammates would... let's just say they wouldn't appreciate it.
There is logical difference between Iterable and Iterator.
Iterable is the collection or data structure that can be iterated upon. It is a data holder.
Iterator is the object that defines the iteration logic (in what way and order to loop trough the elements of the Iterable). It can (and most of the times should) be separate from the logic of the data structure or collection. The purpose is to be able to define more than one Iterator implementation for the same Iterable.
An important point that I missed, but is present in the other answers, is to keep the loop state away from the iterable object. This allows to loop simultaneously trough the same collection, since each loop will work with a separate iterator instance.
A simple example would be to write two iterators to ArrayList, one looping forwards and another backwards. You only need to create the Iterator implementations over an existing class (ArrayList) without the need of modifying the latter. So, it is possible to implement only an iterator.
The for loop construct in the Java language, however, has been designed to work with iterables. The code:
for (Object o : collecton) {
...
}
is translated by the compiler to something like:
Iterator i = collection.iterator();
while (i.hasNext()) {
....
}
Therefore, iterator itself cannot be used wit the for loop in the standard way. Alternatively you can use it like this:
for (Iterator i = collection.iterator(); i.hasNext(); ) {
Object current = i.next();
....
}
What about two successive iterations over the container:
By implementing directly Iterator, since variable's Iterator would be shared by all clients, you wouldn't be able to iterate easily through your collection more than once...
By defining a method Iterator: (like the one on AbstractList):
public Iterator iterator() {
return new Itr(); //new instance each time
}
Creating a new instance of Iterator each time allows you to iterate as many times as you want over it. (of course, preferably not simultanously).
Moreover, it avoids you to violate Single Responsibility principle, since the way of iterating over a container represents another goal than "defining" the container.
Even if you have your class implements Iterator<T> in order to get it iterator() you have to implement iterable and return your iterator
public class MyCollection<E> implements Iterable<E>{
public Iterator<E> iterator() {
return new MyIterator<E>();
}
}
And here is the corresponding implementation skeleton of the MyIterator class:
public class MyIterator <T> implements Iterator<T> {
public boolean hasNext() {
//implement...
}
public T next() {
//implement...;
}
public void remove() {
//implement... if supported.
}
}
In order to use enhanced for-loop (a.k.a fancy for-loop) you have to implement Iterable not Iterator
Of course you can implement Iterator, in that case Your container will be itsef an Iterator
public class Cont<T> implements Iterator<T> {
#Override
public boolean hasNext() {
// TODO implment
return false;
}
#Override
public T next() {
// TODO implment
return null;
}
#Override
public void remove() {
// TODO implment
}
}
and you can use it like that:
public static void main(String... args) {
Cont cont = new Cont<SomeType>();
while(cont.hasNext()) {
SomeType obj = cont.next();
}
}
The usual case is to Implment Iterable, so you can use all language features available for it. Implement an Iterator if you are coding a Collection or you want to have some logic inside some of its methods, for instance lazy loading inside the next() method.
If you want to use simple for-each statement - No. You need to call Iterator<E> object from Iterable<E> object using iterator() method.
I tried to cast an Iterator of a class to an iterator of a subclass of said class. This gave me an "inconvertible types" error. Why is this not possible and what is the most elegant way to work around it? (Or alternatively, why is it a bad idea if it is?)
Using a for-each loop is not a solution in this case: I'm trying to implement iterator() and the easiest way to do this would be to return the iterator() of one of my class' fields, but that one doesn't have the exact required type. I can't change the signature of my iterator()either.
public interface SomeoneElsesInterface {
public Iterator<SomeoneElsesInterface> iterator();
}
public abstract class MyAbstractClass implements SomeoneElsesInterface {
final MyAbstractClass[] things;
public MyAbstractClass(SomeoneElsesInterface... things) {
this.things = (MyAbstractClass[]) things;
}
}
public class MyClass extends MyAbstractClass {
public MyClass(MyAbstractClass thing1, MyAbstractClass thing2) {
super(thing1, thing2);
}
public Iterator<SomeoneElsesInterface>() {
return (Iterator<SomeoneElsesInterface>) Arrays.asList(things).iterator();
}
}
I could, of course, just change the type of things. However, I would need a lot of casts in other places in that case. I do know that my constructor won't be called with objects that are not MyAbstractClasss but I cannot change the interface anyway.
This looks to be as simple as using explicit type argument specification:
public class MyClass extends MyAbstractClass {
// ...
public Iterator<SomeoneElsesInterface> iterator() {
return Arrays.<SomeoneElsesInterface>asList(things).iterator();
}
}
The problem is that Arrays#asList() is inferring that you want a list of type List<MyAbstractClass>, which will yield an iterator of type Iterator<MyAbstractClass>. Since Iterator's type parameter is not covariant, you cannot supply an Iterator<MyAbstractClass> where an Iterator<SomeoneElsesInterface> is required. By forcing Arrays#asList() to create a list of type List<SomeoneElsesInterface>, as shown above, you also wind up with the intended iterator type coming back from your call to Iterable#iterator().
The author of SomeoneElsesInterface would have been kinder to specify the return type of its iterator() method as Iterator<? extends SomeoneElsesInterface>.
I think from your question you're trying to do something like this:
Iterator<Object> original = ...
Iterator<String> converted = (Iterator<String>)original;
Is that correct?
If so, that is, unfortunately, impossible. The problem is that original can contain objects that are not Strings, so allowing that cast would break the generics contract, i.e. converted could contain something that is not a String.
I don't think there is an elegant workaround for this.
You say the easiest way to implement iterator() is to return an instance field's iterator, so I'm guessing you have something like this:
class IterableThing implements Iterable<Foo> {
private Collection<Bar> someStuff;
public Iterator<Foo> iterator() {
return (Iterator<Foo>)someStuff.iterator();
}
}
class Bar {
}
class Foo extends Bar {
}
If someStuff can be guaranteed to contain only instances of Foo, then can you declare someStuff to be a Collection<Foo> rather than a Collection<Bar>? If not, then it doesn't really make sense to just return someStuff's iterator because it might contain something that is not a Foo.
I guess you need to think about what guarantees you can actually make. If you can't guarantee that someStuff only contains Foos then you will probably have to maintain your own state, or filter the contents of someStuff on demand.
EDIT: You've updated your question with code. Awesome.
So it looks like you're actually trying to return an iterator over the superclass of the type. That makes things a lot easier.
In your particular case, you can probably solve it with this:
return Arrays.<SomeoneElsesInterface>asList(things).iterator();
It'll generate some warnings, but that's OK because you know that you've guaranteed type safety.
Use for-each loop instead of Iterator.
for-each was introduced from Java 1.5
See this link for further details:
http://docs.oracle.com/javase/1.5.0/docs/guide/language/foreach.html
What if you change Arrays.asList(things) to Arrays.asList((SomeoneElsesInterface[]) things)? Once the array is cast to the right type the List and Iterator should follow.
Example of Java for-each (complementing Kumar answer):
List<String> strings = new ArrayList<String>();
strings.add( "one" );
strings.add( "two" );
strings.add( "three" );
for ( String item : strings ) {
System.out.println( item );
}
I had two classes: ParentClass and SubClass. SubClass inherit from ParentClass.
I had the following code: (inside class)
List<SubClass> lstSub;
//some initialization
public ListIterator getLstIterator(int i) {
return lstSub.listIterator(i);
}
And client class uses it the following way:
ListIterator<ParentClass> lstParent = getLstIterator(0); //assign ListIterators
So, the question:
What does the program do while assigning ListIterators:
1) it creates a new list and copies there elements from source list, casting them to ParentClass;
2) it simply creates a link to lstSub and from this time this list is interpreted as List for ListIterator?
Or it does something else?
I'm interested in it because of program performance. I'm new to Java and appreciate any help.
It doesn't create another list. If you get a list iterator without knowing the class in the list, that's going to be an error in your generics usage. You should get a warning when you do that assignment, but it's just a warning. When you actually use it it'll cast to whatever class. Properly you'd hold on to that as ListIterator<? extends ParentClass> if you wanted a list iterator, but actually holding on to an iterator is a little weird.
Finally, just a bit of advice, I'd not worry about performance of the language features too much, especially if you're just getting your feet in the language.
A new instance of ListIterator is created. The reference to the new object is copied into lstParent
See here
public ListIterator<E> listIterator(int index) {
if (index < 0 || index > size)
throw new IndexOutOfBoundsException("Index: "+index);
return new ListItr(index);
}
Disclaimer: This example is specific to ArrayList.
Performance-wise, there's no list copying going on.
But to have the compiler check the type-safety of the code, you should declare the type parameters like this:
public ListIterator<SubClass> getLstIterator(int i) {
return lstSub.listIterator(i);
}
...
ListIterator<? extends ParentClass> lstParent = getLstIterator(0);