How to store object inside Iterator<object>? - java

So I have a variable string and I want to store it inside an Iterator of type string, but I keep getting an error stating that it is incompatible types. How can I store a string variable inside an iterator?
Incompatible Types:
Required: java.util.Iterator <java.lang.String>
Found: java.lang.String
This is what I've done so far:
Iterator<?> perEntry = entries.iterator();
Iterator<String> ids;
while (perEntry.hasNext()) {
ids = perEntry.next().getId();
}
Any help would be appreciated thank you!
P.S. I forgot to include this, but how do I return this Iterator? I get an error stating that it found java.util.ObjectType, and it requires java.util.Iterator.

You misunderstood iterators. An iterator is not equivalent to an object in a collection being iterated. Instead, it acts like a "pointer" to such an object.
If you have Iterator<Entity>, you can get an Entity out of it by calling next(). However, an iterator itself would remain an iterator on Entity. It cannot be converted into an iterator of String.
However, you can harvest all strings from an iterator into a collection, like this:
List<String> idList = new ArrayList<>();
while (perEntry.hasNext()) {
idList.add(perEntry.next().getId());
}
Once you have your idList list filled with data, you can get its iterator. It would be an Iterator<String>, because idList element is of type String:
Iterator<String> ids = idList.iterator();

Related

UnsupportedOperationException vs ConcurrentModificationExcetion

I have a code that adds data to a list. What I do not understand is why
the UnsupportedOperationException is thrown in one case and
ConcurrentModificationException in the other.
I am adding data in list in both the case and then trying to remove list
data while iterating over the list.
What i have read so far is that whenever any modification is made to
fail- fast collection,ConcurrentModificationException is thrown. So why this
different behavior in both these cases?
List<String> animalList = new ArrayList<>();
animalList.add("cat");
animalList.add("dog");
animalList.add("bear");
animalList.add("lion");
Iterator<String> iter = animalList.iterator();
while(iter.hasNext()){
String animal = iter.next();
System.out.println(animal);
animalList.remove(3);
}
This code throws ConcurrentModificationException
String[] strings = { "Java", "Honk", "Test" };
List<String> list = Arrays.asList(strings);
Iterator<String> iterator = list.iterator();
while(iterator.hasNext()){
String name = iterator.next();
System.out.println(name);
list.remove(3);
}
while this one throws UnsupportedOperationException
For the code block, where you get ConcurrentModificationException , you get that exception because you created an iterator on List then removing directly from list from within loop so iterator has issues. You should use remove() method of iterator itself - Iterator.remove().
You should directly remove an element from list when removing from outside iterator loop. See this another SO Question
In second case, with Arrays.asList , you get a List but actual list object might not be an ArrayList and remove(int index) operation is optional at List interface. See this
All in all, as far as UnsupportedOperationException is concerned, in first case you are guaranteed to working with an ArrayList and for that class, remove operation is supported , See this
For second case, you can't be so sure. Refer documentation of Arrays.asList where it says that returned list of fixed size so certain operations are not supported.
Arrays.asList does not return an ArrayList. In fact, the list returned is not modifiable, thus when you try to modify it, it throws the UnsupportedOperationException.

ArrayList gets manipulated by called method

I'm currently having problems with the following, using Java 8:
I want to pass an ArrayList<String> as argument to another method. This method, among other things, removes an object from the ArrayList it was given:
public static void calledMethod(String item, ArrayList<String> list) {
list.remove(item);
}
Now I tried calling this method like this from main:
ArrayList<String> list = new ArrayList<String>();
list.add("abc");
Iterator<String> itr = list.iterator();
while (itr.hasNext()) {
String item = itr.next(); //<-
calledMethod(item, list);
}
In this case, the JVM returns a java.util.ConcurrentModificationException at the marked line in the code above (//<-). As far as my knowledge goes, this means that the list was modified while it was iterated. But how can this happen? As far as I know, Java hands method arguments by value, not by reference. If I call calledMethod using the following code in my main method, no error occurs:
ArrayList<String> list = new ArrayList<String>();
list.add("abc");
Iterator<String> itr = list.iterator();
while (itr.hasNext()) {
String item = itr.next(); //<-
calledMethod(item, (ArrayList<String>) list.clone());
}
So passing a cloned object to calledMethod works. What is wrong here?
java -version: Java SE Runtime Environment (build 1.8.0_20-b26)
I'm using Oracle Java on a Linux Mint 64bit.
Yes, Java is pass by value. But what is list? It's a reference to the actual ArrayList object. When it's passed to the method, it's copied, but the copy still refers to the same object, so the method's modification is visible to the calling method, and a ConcurrentModificationException occurs.
When you clone the object, only then is a copy of the object made, preventing the ConcurrentModificationException.
What happens here is that your iterator got "lost" due to "concurrent" modification on the list (it's not actually concurrent, but it's a modification made on the list without notifying the iterator. So from Iterator point of view, it's as if the list was modified at the same time)
While iterating through a list, you should never remove an element with List.remove. Use Iterator.remove instead, this way the iterator won't have an invalid state due to removing:
Iterator<String> itr = list.iterator();
while (itr.hasNext()) {
String item = itr.next();
itr.remove(); // will remove "item" and keep iterator in a correct state
}
Yes you pass it by value, but you are passing an object which is actually passing the reference of the object in that case. Thus you are still modifying the actualy list in the calledMethod.

generics collections.mixin raw and generic type. Integer -> String - exception but String -> Integer works good

I am confusing with two code snippets:
snippet 1
List list = new ArrayList();
list.add("1");
Iterator<Integer> iterator = list.iterator();
System.out.println(iterator.next());
this code executes normally and outs 1 to console
snippet 2
List list = new ArrayList();
list.add(1);
Iterator<String> iterator = list.iterator();
System.out.println(iterator.next());
Result of it - RuntimeException
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
I am confusing because both these rows are wrong:
Integer integer = "123";
String string = 1;
It is compile error.
Why does for generis behaviour is different?
P.S.
I am prepare for scjp exam and don't mix raw type and generics;
PrintStream, the class of System.out, has a number of println overloads. In particular, it has an overload that takes an Object and an overload that takes a String.
In the first example,
List list = new ArrayList();
list.add("1");
Iterator<Integer> iterator = list.iterator();
System.out.println(iterator.next());
the compiler expects iterator.next() to produce an Integer, and the best match for that is the Object version of println. The compiler generates a call to the Object version of the method, which happens to work just fine for the String that actually comes out of the iterator.
In the second example,
List list = new ArrayList();
list.add(1);
Iterator<String> iterator = list.iterator();
System.out.println(iterator.next());
the compiler expects iterator.next() to produce a String, and the best match for that is the String version of println. The compiler generates a call to the String version of the method, and due to type erasure (which makes the runtime type of iterator.next() Object), it generates a runtime cast from Object to String. This cast fails for the Integer that actually comes out of the iterator, causing the exception you see.

(Java) Iterating over a Vector<String[]>, why is .next() an Object, not a String[]?

In Java, when you iterator over a Vector<String[]>, why is .next() an Object that needs to be casted to String[], to use each element as a String[]?
EDIT:
Here is my code:
Iterator itr = getIdAndName().iterator();
while( itr.hasNext() ) {
String[] stringArray = (String[])itr.next();
String id = stringArray[0];
String name = stringArray[1];
System.out.println(id + ": " + name);
}
getIdAndName() returns Vector<String[]>.
It isn't. The only thing I can think of is you're not typing your iterator, i.e. you're doing this:
Vector<String[]> vector;
Iterator it = vector.iterator();
Object obj = it.next();
when you should be doing:
Vector<String[]> vector;
Iterator<String[]> it = vector.iterator();
String[] next = it.next();
Well, in most cases you don't actually need the iterator directly, so you could just use:
Vector<String[]> vector;
for (String[] element : vector) {
//...
}
The iterator() method returns an Iterator<String[]> when called on a variable whose declared type is Vector<String[]>.
I suspect that you are calling it on a variable that is declared as Vector or Vector<?> or something else. Or maybe you are assigning the iterator to an Iterator or Iterator<?> variable instead of an Iterator<String[]>. Obviously, this is just conjecture, because you didn't show us the source code.
(Note that it is the declared type of the variable that determines whether a cast is required ... not the actual type of the instance.)
When you get iterator from your vector, example vector.iterator(); your iterator should have parameterized. This way, the iterator will know the object that it stored is of type String[], if you do not tell iterator of the type it stored, it will have to resort to the object.
When you properly parameterized the type, for example Iterator<String[]> iter = vector.iterator(); , and then the iteration over iter will not need to be cast explicitly.
Please refer here about generic.
When you iterate over a Vector, you are using an implementation of the Iterator interface. By DEFINITION, the Iterator interface returns an Object when its next() method is called. You can see this definition here -
http://docs.oracle.com/javase/1.4.2/docs/api/java/util/Iterator.html
So it doesn't matter what you iterate over, the Iterator will always return an Object when you call its next() method.
And by the way, .next() does not HAVE to be casted to a String[]. It is just the case that in your specific case the Vector contains String[] as its elements, and therefore they are casted to String[] in order to use them.

Not sure how to avoid this ClassCastException

The following code throws a ClassCastException. The collection in question actually does hold ArrayList<String>.
HashMap listing = (HashMap) data.get(s);
Collection<ArrayList<String>> collection = listing.entrySet();
int count = 0;
for ( ArrayList al : collection ) // exception occurs here
{
count += al.size();
}
I am assuming that this must be converted to Object and
a) I can't seem to figure out how to convert from Object to ArrayList properly
b) I'm not even sure if thats the issue..
Perhaps someone can provide some insight?
Edit: HashMap listing is a HashMap<String, ArrayList<String>>
Your code has problem in second line
listing.entrySet() always return Set<MapEntry<Key,Value>>
That cannot be casted to Collection<ArrayList<String>> even though set is a subtype of collection because the generics are differ.
And then in the HashMap(listing) what is the type of key and value?
HashMap.entrySet() returns Set<Map.Entry<K,V>>. This is not compatible with Collection<ArrayList<String>>.
As a side note, your HashMap is a raw type and should be parameterized.
I think the most pluasible place where the exception is occuring is at the following line :
HashMap listing = (HashMap) data.get(s);
Are you sure data.get(s) is suppose to return hashmap.
Also entrySet returns a set that is incompatible incompatible to your assignment.

Categories