4 formas de hacer un bucle for en Java

Escrito por el , actualizado el .
java planeta-codigo programacion
Enlace permanente Comentarios

La forma habitual en Java de hacer un bucle es con una sentencia for o while pero con el añadido de los iteradores en Java 5 no hace falta tener una variable para conservar el índice del bucle. Ya en Java 8 se han añadido los streams que ofrecen otras nuevas formas de iterar sobre los elementos de una colección en este último caso con técnicas propias de lenguajes funcionales.

Java

Hasta Java 5 para hacer un bucle desde 0 a N elementos había que usar una variable para mantener un contador, hacer una comparación para comprobar si se había llegado al límite e incrementar la variable en la siguiente ejecución. El código era bastante verboso y dado que los bucles son una construcción básica de cualquier lenguaje de programación es empleada numerosas veces en cualquier algoritmo.

Algunos de estos ejemplos de bucles son utilizables a partir de Java 5, en versiones más recientes se han añadido muchas otras novedades como las lambdas, streams, métodos en interfaces y nueva API para fechas en Java 8, la modularidad, try-with-resource mejorado, jlink o un nuevo modelo de publicación en Java 9, inferencia de tipos para variables locales en Java 10, un cliente HTTP en Java 11 y otras novedades en el lenguaje y la plataforma Java.

Los bucles son uno de los tipos de sentencias y estructuras de control de flujo básicas de Java que permiten repetir la ejecución de un bloque de sentencias mientras se cumpla la expresión de condición de repetición, en cada iteración del bucle se evalúa la expresión de condición y en el momento que no se cumple se continua con la siguiente sentencia del programa.

Bucle for

Antes de Java 5 un bucle for de 0 a 5 y de una colección se realizaba de la siguiente manera manteniendo una variable normalmente de nombre i que hace de contador y j si el bucle for está anidado en otro. Además de la variable de contador requiere establecer la condición que permita salir del bucle cuando se llegue al final de la iteración, la condición es muy importante para no crear un bucle infinito.

1
2
3
for (int i = 0; i < 5; ++i) {
    System.out.println(i);
}
For.java
1
2
3
4
5
Collection<Integer> = Arrays.asList(0, 1, 2, 3, 4);
Iterable it = collection.iterable();
while (it.hasNext()) {
    System.out.println(it.next());
}
Iterator.java

Bucle foreach

En Java 5 el bucle for se enriqueció notablemente, el bucle foreach es un bucle for mejorado con el que se puede recorrer una colección y cualquier objeto que implemente la interfaz Iterable. Este bucle tiene la ventaja de que no hay que mantener una variable que haga de contador ni requiere establecer una condición para comprobar si se ha llegado al final de la iteración, esto evita la posibilidad de crear un bucle infinito. Con el bucle foreach una Collection se recorre de la siguiente manera.

1
2
3
for (int i : Arrays.asList(0, 1, 2, 3, 4)) {
    System.out.println(i);
}
Foreach.java

Bucle con Iterable

Pero el forearch es para las colecciones si se quiere hacer un bucle de un número fijo de iteraciones como en el primer caso, de 0 a 5, conociendo que para usar el foreach basta que le indiquemos un objeto que implemente la interfaz Iterable podemos usar la siguiente expresión y su implementación que tiene la ventaja de no tener que incluir el valor inicial del contador, la expresión de condición y el incremento o decremento de la variable. La clase Counter implementa la interfaz Iterable y devuelve un Iterator sobre los valores del rango indicado.

1
2
3
for (int i : new Counter(0, 5)) {
    System.out.println(i);
}
CounterIterable.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package io.github.picodotdev.blogbitix.javaforeach;

import java.util.Iterator;

public class Counter implements Iterable<Integer> {

    private int start;
    private int end;

    public Counter(int start, int end) {
        this.start = start;
        this.end = end;
    }

    public Iterator<Integer> iterator() {
        return new Iterator<Integer>() {
            private int i = start;

            public boolean hasNext() {
                return i < end;
            }

            public Integer next() {
                return i++;
            }

            public void remove() {
                throw new UnsupportedOperationException();
            }
        };
    }
}
Counter.java

Bucle con streams

En Java 8 con la introducción de los Stream y de IntStream podemos usar el método range y rangeClosed para obtener un Stream de enteros y hacer un bucle con un comportamiento similar a los anteriores.

1
2
3
IntStream.range(0, 5).forEach( i -> {
    System.out.println(i);
});
Stream.java

Los Stream de Java 8 están muy bien para simplificar algunas operaciones complejas pero para un bucle for sencillo tiene sus inconvenientes como ofuscar significativamente el stacktrace en caso de producirse alguna excepción. Se puede usar cualquier opción pero la primera con el tradicional bucle for sea la menos recomendable teniendo a nuestra disposición la clase Counter con Java 5 o los Stream y lambdas con Java 8.

Cómo salir de un bucle inmediatamente o continuar con la siguiente iteración

Cuando se hace un bucle hay que definir una condición que es evaluada en cada iteración del bucle, una vez se cumple la condición el bucle termina y se continua con la siguiente sentencia del programa.

En ocasiones sin embargo se desea terminar un bucle inmediatamente sin evaluar la condición de fin de bucle. Java posee la palabra reservada break que dentro de un bucle permite finalizarlo inmediatamente. El siguiente bucle imprime los números 0, 1 y 2, al evaluar la condición if como cierta para el valor 3 de la variable contador i se ejecuta la sentencia break y se termina el bucle.

1
2
3
4
5
6
for (int i = 0; i < 5; ++i) {
    if (i == 3) {
        break;
    }
    System.out.println(i);
}
For-break.java

Al mimo tiempo en otras ocasiones se desea no terminar con el bucle sino continuar con la siguiente iteración del mismo, para ello se utiliza la palabra reservada continue. En este caso el bucle imprime los números 0, 1, 2 y 4, al evaluar la condición if como cierta para el valor 3 de la variable contador i se ejecuta la sentencia continue y se continua el bucle en la siguiente iteración.

1
2
3
4
5
6
for (int i = 0; i < 5; ++i) {
    if (i == 3) {
        continue;
    }
    System.out.println(i);
}
For-continue.java

Ejemplo con los distintos tipos de bucle

El siguiente programa muestra las cuatro opciones, su salida en la consola sería el siguiente:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
package io.github.picodotdev.blogbitix.javaforeach;

import java.util.Arrays;
import java.util.stream.IntStream;

public class Main {

    public static void main(String[] args) {
        System.out.println("for i");
        for (int i = 0; i < 5; i++) {
            System.out.println(i);
        }

        System.out.println("foreach");
        for (int i : Arrays.asList(0, 1, 2, 3, 4)) {
            System.out.println(i);
        }

        System.out.println("for counter");
        for (int i : new Counter(0, 5)) {
            System.out.println(i);
        }

        System.out.println("stream foreach");
        IntStream.range(0, 5).forEach(i -> {
            System.out.println(i);
        });

        System.out.println("Sentencia break");
        for (int i = 0; i < 5; ++i) {
             if (i == 3) {
                break;
            }
            System.out.println(i);
        }

        System.out.println("Sentencia continue");
        for (int i = 0; i < 5; ++i) {
            if (i == 3) {
                continue;
            }
            System.out.println(i);
        }
    }
}
Main.java

Para cualquiera de las formas de hacer el bucle for el comportamiento es el mismo, iterar un número finito de veces o sobre los elementos de una colección. Elegir cual usar entre los diferentes tipos de bucles depende del caso y de las preferencias personales pero también considerando la legibilidad y expresividad del código fuente.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
$ ./gradlew run

> Task :run
for i
0
1
2
3
4
foreach
0
1
2
3
4
for counter
0
1
2
3
4
stream foreach
0
1
2
3
4
Sentencia break
0
1
2
Sentencia continue
0
1
2
4

BUILD SUCCESSFUL in 1s
2 actionable tasks: 1 executed, 1 up-to-date
System.out
Terminal

El código fuente completo del ejemplo puedes descargarlo del repositorio de ejemplos de Blog Bitix alojado en GitHub y probarlo en tu equipo ejecutando siguiente comando:
./gradlew run


Comparte el artículo: