'Refactor foreach to for loop
I have a foreach loop in Java (simplified version here)
List<String> names = getNames();
for(String name:names) {
doSomething(name);
}
Is there an automated way to refactor this to a traditional for
loop?
I know how to do it manually
List<String> names = getNames();
for(int i=0; i<names.size(); i++) {
String name = names.get(i);
doSomething(name);
}
As you can see, there is a bit of typing needed in the for
statement itself as well as introducing the variable name
again and assign it the value names.get(i)
. In total, the manual edit is too error-prone for me.
Why do I want to do this? I have to fix a bug and the fix is to start at index 1 instead of index 0 and end at index n-1 instead of the end (unfortunately I can't fix the input right away, I need to wait for a library update if that's recognized as a bug).
What have I tried? I right-clicked on the for
keyword and clicked on "Refactor", but as far as I can get from the context menu entries, nothing in there would do the work for me.
Why do I think this could theoretically work? Because similar functionality exists in Resharper for Visual Studio (C#).
FYI: I'm using Eclipse Luna SR 2 (4.4.2)
Solution 1:[1]
Mouseover the for
statement, right-click, Quick fix (Ctrl+1), convert to indexed loop.
Should work!
Solution 2:[2]
List<String> names = getNames();
names = names.subList(1, names.size() - 1);
for(String name : names) {
doSomething(name);
}
Of course, you could put that into a reusable method if you need to do it several times:
public static List<String> fixList(List<String> names) {
return names.subList(1, names.size() - 1);
}
and then use it as
List<String> names = fixList(getNames());
for(String name : names) {
doSomething(name);
}
Solution 3:[3]
In my eclipse (Kepler RC2) it works to select the for
keyword and either use the quick fix from the context menu or hit CTRL+1 for the shortcut. Eclipse then offers me "Convert to indexed 'for' loop" or "Convert to Iterator-based 'for' loop".
Solution 4:[4]
You can use either:
names = names.subList(1, names.size()-1);
for (String name : names) {
doSomething(name);
}
or in manually:
for (int i = 1; i < names.size()-1; i++) {
String name = names.get(i);
doSomething(name);
}
But the first one I prefer to use.
Solution 5:[5]
Be careful with this refactoring.
The reason is that for a traditional linked list, your second for
loop formulation is O(N * N) since you're having to traverse the linked list in order to evaluate names.get(i);
. That could become expensive.
Do consider performance implications when moving from for(String name:names) {
. There may well be a better way of fixing your immediate bug, and retaining the current "Big O".
for(String name : names.subList(1, names.size() - 1)) {
is one such way (Acknowledge @JB Nizet).
Solution 6:[6]
Don't go for indexed iteration!
This does not perform well with all implementations of List
.
It is much better to go for an Iterator
and let the JIT optimize the Iterator
away if this code is hot.
So either write this:
List<String> names = getNames();
for (String name : names.subList(1, names.size() - 1)) {
doSomething(name);
}
Or that (one allocation less):
Iterator<String> it = getNames().iterator();
it.next(); // You seem to be sure there is more than one element in the list
while (it.hasNext()) {
String name = it.next();
doSomething(name);
}
Solution 7:[7]
In my case, I need to transform the foreach to use an index . This is my two cents
Integer index=0;
for (final String OneCell :CellList){
// Your code use the index
index=index+1;
}
Solution 8:[8]
When using java 8 you could use the stream api
names.stream().skip(1).reverse().skip(1).reverse().foreach(
name -> do something(name)
);
Something like this...
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | |
Solution 3 | Holger |
Solution 4 | E Do |
Solution 5 | |
Solution 6 | JnRouvignac |
Solution 7 | grojas123 |
Solution 8 | Stefaan Neyts |