user7471732
user7471732

Reputation: 23

What is the equivalent of this tradition for loop to a for each loop

I have a tradition for loop below and I just wondering what the equivalent loop would be for each loop.

for (int i = 0; i < words.size(); i++)
{
    words.set(i, words.get(i).toUpperCase());
}

In addition, for those, who are wondering, words is an arrayList of type String.

Upvotes: 1

Views: 173

Answers (4)

Andy Turner
Andy Turner

Reputation: 140534

I'm surprised that nobody has pointed out the following structure, using an enhanced for loop:

int i = 0;
for (String str : words) {
  words.set(i++, str.toUpperCase());
}

Now, this is pretty gross, and inefficient unless words is an instance of RandomAccess; I'd much prefer to use the ListIterator approach proposed by Weston.

This works for ArrayList and LinkedList etc without a ConcurrentModificationException because that is only thrown following structural modification of the list:

A structural modification is any operation that adds or deletes one or more elements, or explicitly resizes the backing array; merely setting the value of an element is not a structural modification.

Note that there is no safe approach for a general List implementation (including the basic for loop in the original question): set is an optional operation, and you can't tell if it is implemented for a List without trying it.

Upvotes: 1

weston
weston

Reputation: 54811

The for loop with indexes is fine, but just so you know, you can also use a ListIterator which allows replacing of the current item via set:

for (ListIterator<String> iterator = words.listIterator(); iterator.hasNext();) {
  String word = iterator.next();
  iterator.set(word.toUpperCase());
}

Which is not an enhanced for-loop, but is very close to what an enhanced for loop actually is with non-array Iterables.

Upvotes: 3

Andreas
Andreas

Reputation: 5103

Perhaps you would be interested in the java 8 way of doing this:

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

public class Class {
  public static void main(String... args) {
    List<String> words = new ArrayList<String>();
    words.add("hello");
    words = words.stream()
      .map(String::toUpperCase)
      .collect(Collectors.toList());
    System.out.println(words);
  }
}

Upvotes: 1

Jack
Jack

Reputation: 133639

for-each construct doesn't allow you to set an element. This because the syntactic sugar it provides hides the Iterator<E> completely.

for (String word : words)
 ...

is equivalent to

for (Iterator<String> it = words.iterator(); it.hasNext(); /**/) {
  String word = it.next();
  ...
}

This could work if String instances were mutable object such that you can modify the content without modifying the reference but that's not the case. To be able to do what you need with a for-each you'd need a wrapper class, eg:

List<AtomicReference<String>> words = ...;
for (AtomicReference<String> word : words)
  word.set(word.get().toUpperCase());

Upvotes: 3

Related Questions