I am having a discussion (read argument!) with one of my colleagues. I maintain that this code is very wrong but he thinks there is nothing wrong with it:
for (Iterator<String> iter = collectionOfStrings.iterator(); iter.hasNext();) {
String item = iter.next();
...
}
I maintain that this code is wrong because there is a duplication of looping. Either use Iterator or use a For loop but there is no need to use them both at the same time.
I would re-write the code as follows:
Iterator<String> iter = collectionOfStrings.iterator();
while (iter.hasNext()) {
String item = iter.next();
...
}
What do you think?
Neither code is not "wrong", in the sense that both do what is expected. The second code, although equivalent, pollutes the local variables, because iter remains defined after the loop ends.
Both of your examples are syntactically correct. One advantage of putting the declaration in the for loop is that the variable is released after the code block ends, whereas the iterator persists after the while loop ends
The second is good.
The first is slightly better. It limits the loop variable's scope.
But since Java 1.5, the foreach loop can sometimes be more elegant than either:
for ( String item : collectionOfStrings ) {
...
}
Actually it's the same. For is just a variation of while, or while is just a variation of for, however you like to put it. You can write a for
for (init;cond;incr){
...
}
like this
init
while(cond){
....
incr
}
Your colleague is right. The first code, with the for loop, should run just fine.
In fact, while is also a loop, so both your code and his contains one loop and iterator.
Related
This is my code to run in android. Sometime throw ArrayIndexOutOfBoundsException(length=0; index=0)
val list = mutableListOf<String>()
for (i in list.indices){
val item = list[i]
}
But when I use forEachIndexed , The code works well.
Does anyone know the reason?
And Which method is usually preferred?
Thanks for help!
Does anyone know the reason?
Both for (i in list.indices) and forEachIndexed should behave the same way.
Your problem might come from places in the code that you haven't shared. Do you manipulate indices? Do you mutate the list in another thread at the same time?
Which method is usually preferred?
If there is a functional shortcut, it's usually preferred over a loop, because it has less boilerplate. This makes it easier to read (we see the intent more clearly) and also there are less opportunities to make mistakes.
So I would definitely prefer:
list.forEachIndexed { i, item ->
// use item and i in the loop body
}
Over:
for (i in list.indices) {
val item = list[i]
// use item and i in the loop body
}
The only exception is when the loops are in very performance sensitive spots (those are quite rare), because using a for can save an Iterator usage.
I couldn't find any topic about this. I want to know if it is safe to change the reference for the list class during a loop like the one bellow:
Tree minimalTree = someTree;
for (Tree st : minimalTree.getSubtrees()) {
if (condition)
minimalTree = st;
}
Does the iterator gets reset and starts again for the new reference?
Edit: I forgot to say: this code is suited for situations where I want to narrow down the search for elements in the tree, let's say, the smaller tree that contains certain elements. In this case, it would be faster to keep looking only for the inner structures of "minimalTree" instead of the entire "someTree" structure.
No, the iteration won't be reset. According to the JLS:
The enhanced for statement is equivalent to a basic for statement of
the form:
for (I #i = Expression.iterator(); #i.hasNext(); ) {
{VariableModifier} TargetType Identifier = (TargetType) #i.next();
Statement
}
The definition makes it obvious that the iterator is only initialised once, before the first iteration of the loop.
The behaviour when iterating across an array with an enhanced for statement is similar in this respect.
However I'd personally consider it poor practice as it makes the code hard to understand.
Actually, there are two questions:
I want to know if it is safe to change the reference for the list class during a loop like the one bellow:
Yes, it is safe. And for safe I mean: changing the reference does not interfere with the already running loop.
Does the iterator gets reset and starts again for the new reference?
No, the iterator is never reset. It would be exactly the opposite of safe.
In my opinion, it is not a good practice to change iterator or collection variables inside a loop. It makes the code harder to understand, and probably the result is not what you expect when you do that (like in your case I understood you expected the loop to start over reevaluating the collection).
In your case, encapsulate in a method and recursively call it on subtree:
Tree findMinimalTree(Tree tree) {
for (Tree st : tree.getSubtrees()) {
if (condition)
return findMinimalTree(st);
}
return tree;
}
I often come across cases where I want to use an enchanced for-loop for some Collection or array that I get from some object.
e.g.
items = basket.getItems();
for (int item : items) {
// Do something
}
Another way to do that is:
for (int item : basket.getItems()) {
// Do something
}
The second one is more compact and improves readability in my opinion, especially when the item variable won't be used anywhere else.
I would like to know whether the getter in the for statement has any impact in performance. Will it be optimized to something similar to the 1st one? Or will it access the getter every time? Of course the getItems() might do something quite slow (e.g. network access, etc)
Question is similar to some others, but is referring to the getter of the collection/array itself and not the size of it. However, it may be the same case in the end.
The getItems() method will be called only once in both cases. There is no difference between the two, apart from one using an extra local variable which you could use somewhere else.
As you can read in JLS 14.14.2, the enhanced for loop is translated roughly to this traditional for loop:
for (I #i = Expression.iterator(); #i.hasNext(); ) {
TargetType Identifier = (TargetType) #i.next();
Statement
}
#i is an automatically generated identifier that is distinct from any other identifiers (automatically generated or otherwise) that are in scope (ยง6.3) at the point where the enhanced for statement occurs.
From here it's clear that Expression is evaluted only once.
As you can see on the following code sample, on the enhanced for, the initialization of the collection on which to iterate is done only once. So, the second choice is more compact, and does not impact performance.
package test;
public class Main {
static class Basket {
int[] items = { 1, 2, 3 };
public int[] getItems() {
System.out.println("in getItems()");
return items;
}
}
public static void main(String[] args) {
Basket basket = new Basket();
for (int item : basket.getItems()) {
System.out.println(item);
}
}
}
Yes second one improves readability of code.
if you are getting the objects from network and then iterating over it in a for loop then I think yes it has performance impact because you are making network access every time and that is inefficient also as for a small/single object doing network access is not recommended. instead of that get it once from network access store it locally and iterate over it
thus 1st option is performance optimized in network access case
if your object is local then any method will do. there wont be much performance difference.
I don't think it will call getter every time. If it does it will get new list every time and Loop wont break. You can test this by putting simple Sysout inside getter method. Performance will be same in these two cases.
I am new in Java and I have a problem in using if statement within while loop.
I wrote the code as follows:
while(lexicalizations.hasNext())
{
myObject = lexicalizations.next().getObject();
language= myObject.getTermLanguage();
if (language.equals(languageCode)) {
System.out.println(lexicalizations.next());
}
}
However, whenever the if condition is true, the program executes its block and then terminates the while loop. So, the rest of items are not checked out.
How could I solve that?
Thanks so much.
Cheers,
Aya.
Each invocation of Iterator.next() moves the iterator to the next element of the collection, therefore you must be very careful not to call this method more than once per iteration. You must save the element into a local variable and work with the variable throughout the loop body.
In order to systematically avoid this kind of pitfalls, always prefer to use the enhanced for loop whenever applicable:
for (String lex : lexicalizations) {
... your code uses lex here ...
}
Note that when you do that println you "consume" the next element, so if there is only one left there will be zero when you get back to the while.
You are moving to the next object in the iterator within if statement block. To avoid this just use myObject and you will 'visit' every object:
while (lexicalizations.hasNext())
{
myObject = lexicalizations.next().getObject();
language= myObject.getTermLanguage();
if (language.equals(languageCode)) {
System.out.println(myObject);
}
}
I've run into this while writing a Traveling Salesman program. For an inner loop, I tried a
for(Point x:ArrayList<Point>) {
// modify the iterator
}
but when adding another point to that list resulted in a ConcurrentModicationException being thrown.
However, when I changed the loop to
for(int x=0; x<ArrayList<Point>.size(); x++) {
// modify the array
}
the loop ran fine without throwing an exception.
Both a for loops, so why does one throw an exception while the other does not?
As others explained, the iterator detects modifications to the underlying collection, and that is a good thing since it is likely to cause unexpected behaviour.
Imagine this iterator-free code which modifies the collection:
for (int x = 0; list.size(); x++)
{
obj = list.get(x);
if (obj.isExpired())
{
list.remove(obj);
// Oops! list.get(x) now points to some other object so if I
// increase x again before checking that object I will have
// skipped one item in the list
}
}
The first example uses an iterator, the second does not. It is the iterator that checks for concurrent modification.
the first code is using an iterator so modifying the collection is not allowed. The second code you are accessing each object with x.get(i), so not using an iterator, modifications thus are allowed
You cannot modify a List while you are iterating over it which you are doing in the first example. In the second you simply have a regular for loop.
If you run the code and observe you find that first iteration of the loop works fine but the second throws ConcurrentModicationException
if is because next() method checks if the number of the elements did not change.
For nice explanation see http://javaadami.blogspot.com/2007/09/enhanced-for-loop-and.html