Why do I need 2 loops: for and foreach?


Questions:

  1. Why do I need foreach, if I can iterate through an array, for example, through the for loop?

  2. Is it possible to do a task with arrays, for example, on foreach and on a regular loop for, in order to get the same result?

  3. Why do we need foreach if there is for?

I found this example, but for some reason I can't implement it in foreach:

public class Test {
    public static void main(String[] args) {
        int numer[] = {4, 8, 16, 32, 64, 128};
        int denom[] = {2, 2, 4, 4, 2, 8};

        for (int i = 0; i < numer.length; i++) {
            System.out.println(numer[i] + " / " + denom[i] + " равно " + numer[i] / denom[i]);
        }
    }
}
Author: Anton Sorokin, 2018-11-13

3 answers

  1. foreach shortens the code for iterating through collections (lists, arrays, etc.), when we only need to get elements from them, without working with indexes.

    Examples for foreach:

    int numer[] = {4, 8, 16, 32, 64, 128};
    for (int i : numer) {
        System.out.println(i);
    }
    
    List<String> items = Arrays.asList("1", "abc");
    for (String word : items) {
        System.out.println(word);
    }
    
    Map<String, String> nameByValue = new HashMap<>();
    nameByValue.put("name", "Vasya");
    nameByValue.put("email", "[email protected]");
    
    for (Map.Entry<String, String> entry : nameByValue.entrySet()) {
        System.out.println(entry.getKey() + " = " + entry.getValue());
    }
    

    Through the standard loop:

    int numer[] = {4, 8, 16, 32, 64, 128};
    for (int i = 0; i < numer.length; i++) {
        System.out.println(numer[i]);
    }
    
    List<String> items = Arrays.asList("1", "abc");
    for (int i = 0; i < items.size(); i++) {
        String word = items.get(i);
        System.out.println(word);
    }
    
    Map<String, String> nameByValue = new HashMap<>();
    nameByValue.put("name", "Vasya");
    nameByValue.put("email", "[email protected]");
    
    // Через for:
    // for (Iterator<Map.Entry<String, String>> it = nameByValue.entrySet().iterator(); it.hasNext();) {
    // 
    // Через while более предпочтительнее чем через for
    Iterator<Map.Entry<String, String>> it = nameByValue.entrySet().iterator();
    while (it.hasNext()) {
        Map.Entry<String, String> entry = it.next();
        System.out.println(entry.getKey() + " = " + entry.getValue());
    }
    
  2. Can. But we will have to generate a collection with indexes for foreach.

  3. To make the collection iteration code shorter. Example:

    int numer[] = {4, 8, 16, 32, 64, 128};
    
    for (int i = 0; i < numer.length; i++) {
        System.out.println(numer[i] + " * 2 -> " + numer[i] * 2);
    }
    
    System.out.println();
    
    for (int i : numer) {
        System.out.println(i + " * 2 -> " + i * 2);
    }
    

Code:

static List<Integer> getRange(int length) {
    List<Integer> items = new ArrayList<>();

    for (int i = 0; i < length; i++) {
        items.add(i);
    }

    return items;
}

public static void main(String[] args) throws Exception {
    int numer[] = {4, 8, 16, 32, 64, 128};
    int denom[] = {2, 2, 4,   4,  2, 8};

    for (int i = 0; i < numer.length; i++) {
        System.out.println(numer[i] + " / " + denom[i] + " равно " + numer[i] / denom[i]);
    }

    System.out.println();

    for (int i : getRange(numer.length)) {
        System.out.println(numer[i] + " / " + denom[i] + " равно " + numer[i] / denom[i]);
    }
}

Console:

4 / 2 равно 2
8 / 2 равно 4
16 / 4 равно 4
32 / 4 равно 8
64 / 2 равно 32
128 / 8 равно 16

4 / 2 равно 2
8 / 2 равно 4
16 / 4 равно 4
32 / 4 равно 8
64 / 2 равно 32
128 / 8 равно 16
 5
Author: gil9red, 2018-11-13 09:39:49

foreach works with iterators.

List<String> someIterable = List.of("1", "2");
for (Iterator<String> i = someIterable.iterator(); i.hasNext();) {
    String item = i.next();
    System.out.println(item);
}

This loop is equivalent to writing:

for(String str : someIterable){
    System.out.println(item);
}

A regular array has no iterator.

Entry of the form:

for (int numeri : numer) {
    System.out.println(numeri);
}

Is syntactic sugar, since it is converted to the following form

int len = numer.length;
for (int i = 0; i < len; i++) {
    int numeri = numer[i];
    System.out.println(numeri);
}

But nevertheless, foreach is designed to work with the current element of a single structure, and you need to take the i-th element from two arrays numer and denom

 4
Author: Komdosh, 2018-11-13 09:23:11

I will supplement @gil9red's answer with information on other for-each usage scenarios.

  1. What is foreach for, if you can iterate through an array, for example, through a for loop?

For-each, or rather the improved for (enhanced for loop) loop, was conceived primarily to facilitate working with collections through an iterator. Support for arrays is added for code uniformity.

Not all collections that support iterator iteration, they support access by index. For example, the set can be iterated through for-each:

Set<String> letters = new HashSet<>(Arrays.asList("a", "b"));
for(String letter : letters) {
     //...
}

In this case, the loop will pass through all the elements of the set, but the order of the elements is not guaranteed. Accessing an element of the set by index does not make sense:

for(int i=0; i<letters.size(); i++) { 
     letters.get(i); //такого метода нет
}

So, at least for for-each collections, you can't replace it with a for loop on the index. For collections, for-each corresponds to a for loop with an iterator:

Collection c = ... ;
for (Iterator i = c.iterator(); i.hasNext(); ) {  
    String s = (String) i.next();
}

Iterating through a collection is an operation that is performed very often, so in the language and introduced syntactic sugar, which allows you to reduce the code and, accordingly, avoid subtle errors when constantly using the same template code. This justification is given in the amendment to the Java specification (JSR-201), which introduced an improved for loop:

Enhanced for loops allow convenient iteration over collections, without the need for an explicitly defined iterator. This reduces the need for boilerplate iteration code and the corresponding opportunities for errors.

The improved for loop provides a convenient way to iterate through collections, without the need to explicitly specify an iterator. This reduces the need to create boilerplate code for iteration and reduces the likelihood of errors associated with it.

Actually, for the same reason, Java has three different loop statements (for, while, do-while), although, technically, you could do with any of them them.

  1. Is it possible to do a task with arrays, for example, on foreach and on a regular for loop, in order to get the same result?

You can get out of it, of course, using a list of indexes, as in the answer @gil9red, or using a counter:

int counter = 0;
for (int n : numer) {
    System.out.println(n + " / " + denom[counter] + " равно " + n / denom[counter]);
    counter++;
}

Or by creating an entire class hierarchy:

DivisionBatch divisions = new DivisionBatch(numer, denom);
for(Division division : divisions) {
     System.out.println(division.getNumerator() + "/" + division.getDenominator() + " равно " + divison.getResult());
}

But, in my opinion, in this example, the advantages of for-each (code reduction for brute force) do not manifest themselves and it is more appropriate to use for.

 3
Author: default locale, 2020-06-12 12:52:24