Please be aware this is a false issue. I asked it because when I tried to use Iterator, my IntelliJ keeps alarming on "Iterator" saying Iterator could not have type parameters, which is not true.
Somehow, my IntelliJ seems to showing the javadoc of java 1.4. I am still trying to fix it. Thanks.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
I worked on a java program where an api returns a List.
My way of handling this is:
ArrayList<SomeObject> arrayList = new ArrayList<>(apiThatReturnsAList);
for (SomeObject someObject : arrayList) {
...
}
My code reviewer suggests this might be a less efficient way to deal with it because it copies the data. He recommended I use Iterator. But I find the code would be like this:
Iterator iterator = apiThatReturnsAList.iterator();
while (iterator.hasNext()) {
SomeObject someObject = (SomeObject)iterator.next();
}
There is ugly casting here which we don't want to see because it is not safe.
So, is there an efficient way to deal with this api and not copying the data?
Thanks!
To avoid a copying, you can use foreach for apiThatReturnsAList
for (SomeObject someObject : apiThatReturnsAList) {
...
}
In fact, foreach does the same work with iterator under the hood JLS 14.14.2. The enhanced for statement
Just parameterize your iterator with the expected class:
Iterator<SomeObject> iterator = apiThatReturnsAList.iterator();
and you will get a SomeObject instance when you call next() :
Iterator<SomeObject> iterator = apiThatReturnsAList.iterator();
while (iterator.hasNext()) {
SomeObject someObject = iterator.next();
}
Use a for-each to print the contents of the elements in the apiThatReturnsList:
for (SomeObject element : apiThatReturnsList) {
System.out.println(element);
}
There's no need to copy the list into another 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
Is it a matter of preference to use the traditional for loop, the for-each loop or an iterator to go through a List?
1) for(MyClass mc : al){ // do something on mc }
or
2) iter = arrayList.iterator();
while(iter.hasNext()){MyClass mc = iter.Next()}
For most iterations you should use the regular loop:
for (Object o : list) { /* */ }
It is much more readable, intent is clear, and potential bugs are kept to a minimum.
Use an iterator when you need explicit control over the iteration, for example, when you might want to start iteration all over again.
You can use iterators to avoid ConcurrentModificationExceptions.
iter = arrayList.iterator();
while(iter.hasNext()) {
MyClass mc = iter.next();
if(shouldItBeRemoved(mc)) {
iter.remove(); // Will not throw ConcurrentModificationException
// arrayList.remove(mc); // Will throw CME
}
}
That said, I find the for-each loop more readable, so use it whenever you do not modify the list in the loop.
My preference is
1) If I need to move forward through the list without any modification to the List object, for readable and clean code, I will use:
for(MyClass mc : list){
/* code without modification to list */
}
2) If I need modification to the List object, no doubt I will use:
iter = list.iterator();
while(iter.hasNext()) {
MyClass mc = iter.next()
/* code without modification to list */
/* code with modification to list */
}
Additional Information:
Iterator will be useful if you need to create a utility method that can traverse multiple type of collection (e.g. ArrayList, LinkedList, HashSet, TreeSet, LinkedHashSet)
public class Example {
public static void iterateAndDoSomething(Iterator<MyClass> iter) {
while(iter.hasNext()) {
MyClass mc = iter.next();
/* code without modification to list */
/* code with modification to list */
}
}
public static void main(String[] args) {
ArrayList<MyClass> als = new ArrayList<MyClass>();
TreeSet<MyClass> tss = new TreeSet<MyClass>();
iterateAndDoSomething(als.iterator());
iterateAndDoSomething(tss.iterator());
}
}
Some classes doesn't have iterator() method (such as NodeList) then you have to use #1. Other than that, it's a matter of preference I think.
I use for (i=0; if i need the index during the loop, an iterator() if it's the only thing possible or I need to remove() elements (concurrently). For all other cases I use the shortened for loop for(MyClass mc : al) because of its readability.
Traditional loops (indexed based) are useful where you need the index to manipulate the array.
If you don't care about the indexes and you interest is only getting the value out of the array, for..each loop is the best fit.
Some Collection objects doesn't provide a way to get the values using index, in that case iterator() is the only option.
Based on the code snippet you provided, it should be obvious that for-each like iteration produces cleaner code.
With the presence of both, you do have the flexibility on what you would like to choose.
The for-each-loop isn't available on Java 1.4, so this might be eliminated if you need to support Java <1.5.
The other two choices are a matter of use case and style I think. Iterators usually look cleaner, but you might also need to have a counter variable, so a for-loop might fit your needs better. Additionally some list implementations do not provide iterators, so you will have to use an index.
I have read that iterators are very helpful in Swing especially if you iterate through collection in paintComponent(Graphics g) method.
The benefit of iterators is that you can iterate through the same collection from multiple threads and you even remove an element of that collection using the method remove() while the collection is accessed concurrently elsewhere.
The behavior of an iterator is unspecified if the underlying
collection is modified while the iteration is in progress in any way
other than by calling this method.
THIS means that if you modify the same collection concurrently then behavior of method remove is not defined. BUT method remove works well EVEN IF you traverse through the same collection concurrently while calling iterator.remove()!!! I have used this in my GUI.
According to my experience it is necessary to use an iterator in the method paintComponent rather than cycle for or for-each!
I'm completely new to iterators. I have an ArrayList named "Test" with String objects. How would I go about using an iterator class? I've tried everything I can think of, it's just not making sense. Thanks for the help.
Say I have an Iterator named "iter". I need to step through my ArrayList in search of a certain String. When that String is found, I need to add it to a different ArrayList named "test2".
while(iter.hasNext()) {
if(iter.next() == sampleString) {
test2.add(sampleString);
}
}
Only problem with this, is that when I call next() it moves the pointer to the next String, ignoring the first String in the ArrayList. How would I implement this??
You don't need one. The ArrayList is already Iterable! :-D
ArrayList<String> test = new ArrayList<String>();
test.add("Hello");
test.add("world");
for(String str : test) System.out.println(str);
Iterators are generally used like this:
while (iter.hasNext()) {
String nextString = iter.next();
// Do something with the string...
}
Some (myself included) will prefer the enhanced for loop:
for (String nextString : listOfStrings) {
// Do something with the string
}
The for loop avoids the need for getting an explicit Iterator reference and includes the nextString variable declaration, keeping it concise and properly scoped.
The issue is that your not quite 100% on how Iterator.next() works
This is copied directly from the Java API
E next() -- Returns the next element in the iteration.
What this means is that .next() will return an object then move to the next item in the list.
You need to store the returned object when calling next()
while(iter.hasNext())
{
String temp = iter.next();
//this is a more old school method but more true to form.
//== doesn't necessarily do equality checks on all objects the way
//you would think
if(temp.equals(sampleString))
{
test2.add(temp);
}
}
An iterator is simply something that understands how to traverse a given data structure.
What is it that you aren't understanding?
For a List an iterator would keep track of its current position in the list and understand how to get the next element in the list. For something like a list, it's relatively simple, but you could also define an iterator for some other arbitrary data structure that isn't as simple as a list. You could also define one that does something differently like traverse the list backwards. If you have specific questions about iterators, update your question and we'll take a stab at it :-)
Iterator is a means of traversing a collection of items. Adhering to that statement, the java.util.Collection extends Iterable (public interface Collection<E> extends Iterable<E>). i.e all collection classes are Iterable in someway. iterator() is the method to get a handle to that Iterator. Once you have the handle you can traverse through the items.
I highlighted someway because not all Iterator's allow bi-directional traversal. ListIterator allows this.
I'd rewrite your code as below
for(String s : myCollection)
{
if(s.equals(sampleString))
{
test.add(s);
}
}
could not find anything on this, wondering if anyone knew about this or a possible workaround. I am using JDOM and working with an xml schema.
I have created a List of which are just xml tags. The algorithm's aim is to iterate through the List of elements and remove the element if a condition is met (in this case if it starts with a certain string). See below:
for (Element appinfo : appinfos) {
if (appinfo.getText().startsWith(
PARAMETER_DESCRIPTION_APPINFO)) {
removeAppInfoElement(appinfo, name, appinfo.getText());
}
}
However, the loop appears to be attempting to iterate to the element it just removed.
Does anyone see anything wrong with this? Do I need to abandon the enhanced for loop or dig deeper for cause of problem?
I suppose you're talking about ConcurrentModificationException. Try to use iterator instead.
Yes that wont work.
Add all the items you want to remove to a new collection and then do a removeAll with those elements on the original collection.
You cannot remove elements from a Collection directly as you iterate over it - this causes issues because the Iterator has no idea that the element has been removed.
Instead of the enhanced for-loop, use the Iterator directly and call the remove() function, for example:
for (Iterator it = appinfos.iterator(); it.hasNext();) {
Element appinfo : it.next();
if (someCondition) {
it.remove();
}
}
willcodejavaforfood's answer is one way of doing this.
An alternative, which may be better or worse depending on style and what else you want to do in the loop, is to get the Iterator explicitly and use its remove method:
final Iterator<Element> iter = appinfos.iterator();
while (iter.hasNext()) {
if (iter.next().getText().startsWith(
PARAMETER_DESCRIPTION_APPINFO)) {
iter.remove();
}
}
This of course only works if a simple removal from the collection is what you want to do. When invoking potentially complex methods that will directly remove from the underlying collection, the best approach is to take a copy of the collection initially, then iterate over this copy.
In all cases, modifying a collection while you are iterating over it will generally cause Bad Things to happen.