For loop o Foreach: ¿cuál es más rápido en Java?
Fuente: Medio Cuando estaba buscando trabajo hace un par de años, una de las preguntas que me hicieron en una entrevista fue si deberíamos iterar sobre un ArrayList usando for o forEach . El debate sobre la diferencia en las preferencias entre forEach y for existe desde hace mucho tiempo. Tenía la impresión de que forEach es más rápido. Pero al final me di cuenta de que estaba equivocado. Para su información, el bucle forEach (o bucle for mejorado ) introducido en Java 1.5 elimina el desorden y la posibilidad de error al ocultar por completo el iterador o la variable de índice. Creo que la única diferencia práctica entre for y forEach es que en el caso de objetos indexados, no tenemos acceso al índice.for(int i = 0; i < mylist.length; i++) {
if(i < 5) {
//do something
} else {
//do other stuff
}
}
Sin embargo, podemos crear una variable de índice separada de tipo int usando forEach . Por ejemplo:
int index = -1;
for(int myint : mylist) {
index++;
if(index < 5) {
//do something
} else {
//do other stuff
}
}
Escribamos una clase simple que tenga un método foreachTest() que itere a través de una lista usando forEach .
import java.util.List;
public class ForEachTest {
List<Integer> intList;
public void foreachTest(){
for(Integer i : intList){
}
}
}
Cuando compilamos esta clase, el compilador convierte internamente el código en una implementación de iterador. Descompilé el código compilado ejecutando javap -verbose IterateListTest .
public void foreachTest();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=3, args_size=1
0: aload_0
1: getfield #19 // Field intList:Ljava/util/List;
4: invokeinterface #21, 1 // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;
9: astore_2
10: goto 23
13: aload_2
14: invokeinterface #27, 1 // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
19: checkcast #33 // class java/lang/Integer
22: astore_1
23: aload_2
24: invokeinterface #35, 1 // InterfaceMethod java/util/Iterator.hasNext:()Z
29: ifne 13
32: return
LineNumberTable:
line 9: 0
line 12: 32
LocalVariableTable:
Start Length Slot Name Signature
0 33 0 this Lcom/greekykhs/springboot/ForEachTest;
StackMapTable: number_of_entries = 2
frame_type = 255 /* full_frame */
offset_delta = 13
locals = [ class com/greekykhs/springboot/ForEachTest, top, class java/util/Iterator ]
stack = []
frame_type = 9 /* same */
Del código de bytes anterior vemos:
-
El comando getfield se utiliza para obtener variables enteras.
-
Llame a List.iterator para obtener una instancia de iterador.
-
Llame a iterator.hasNext . Si devuelve verdadero, se debe llamar al método iterator.next .
import java.util.ArrayList;
import java.util.List;
public class IterateListTest {
public static void main(String[] args) {
List<Integer> mylist = new ArrayList<>();
for (int i = 0; i < 1000000; i++) {
mylist.add(i);
}
long forLoopStartTime = System.currentTimeMillis();
for (int i = 0; i < mylist.size(); i++) {mylist.get(i);}
long forLoopTraversalCost =System.currentTimeMillis()-forLoopStartTime;
System.out.println("for loop traversal cost for ArrayList= "+ forLoopTraversalCost);
long forEachStartTime = System.currentTimeMillis();
for (Integer integer : mylist) {}
long forEachTraversalCost =System.currentTimeMillis()-forEachStartTime;
System.out.println("foreach traversal cost for ArrayList= "+ forEachTraversalCost);
}
}
Y aquí está el resultado: Como podemos ver, el rendimiento del bucle for es mejor que el del bucle forEach . Si usa LinkedList en lugar de ArrayList , puede ver que el rendimiento de forEach es mejor para LinkedList . ArrayList utiliza internamente matrices para almacenar elementos. Dado que las matrices son regiones contiguas de la memoria, la complejidad temporal es O (1). Esto se debe a que los datos se recuperan a través de índices. LinkedList utiliza una lista doblemente enlazada. Cuando usamos un bucle for para implementar el recorrido, comienza desde el nodo principal de la lista vinculada cada vez, por lo que la complejidad del tiempo es O (n * n).
Ocho formas eficientes de recorrer cada entrada en un mapa de Java
Fuente: Medio La semana pasada, un pasante me preguntó cómo iterar un mapa de Java. Le respondí que como es muy sencillo la respuesta a esta pregunta siempre está en Google. Después de un tiempo, me envió la dirección de la página en StackOverflow y resultó que una gran cantidad de personas estaban prestando atención a este problema. Por lo tanto, decidí detenerme en el tema de la iteración y compartir con ustedes varias formas de hacerlo.1. Usando iterador y Map.Entry
@Test
public void test1_UsingWhileAndMapEntry(){
long i = 0;
Iterator<Map.Entry<Integer, Integer>> it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<Integer, Integer> pair = it.next();
i += pair.getKey() + pair.getValue();
}
System.out.println(i);
}
2. Usando foreach y Map.Entry
@Test
public void test2_UsingForEachAndMapEntry(){
long i = 0;
for (Map.Entry<Integer, Integer> pair : map.entrySet()) {
i += pair.getKey() + pair.getValue();
}
System.out.println(i);
}
3. Usando foreach de Java 8
@Test
public void test3_UsingForEachAndJava8(){
final long[] i = {0};
map.forEach((k, v) -> i[0] += k + v);
System.out.println(i[0]);
}
4. Usando keySet y foreach
@Test
public void test4_UsingKeySetAndForEach(){
long i = 0;
for (Integer key : map.keySet()) {
i += key + map.get(key);
}
System.out.println(i);
}
5. Usando keySet e iterador
@Test
public void test5_UsingKeySetAndIterator(){
long i = 0;
Iterator<Integer> it = map.keySet().iterator();
while (it.hasNext()) {
Integer key = it.next();
i += key + map.get(key);
}
System.out.println(i);
}
6. Uso de for y Map.Entry
@Test
public void test6_UsingForAndIterator(){
long i = 0;
for (Iterator<Map.Entry<Integer, Integer>> entries = map.entrySet().iterator(); entries.hasNext(); ) {
Map.Entry<Integer, Integer> entry = entries.next();
i += entry.getKey() + entry.getValue();
}
System.out.println(i);
}
7. Uso de la API de secuencia de Java 8
@Test
public void test7_UsingJava8StreamApi(){
System. out .println(map.entrySet().stream().mapToLong(e -> e.getKey() + e.getValue()).sum());
}
8. Uso paralelo de Java 8 Stream API
@Test
public void test8_UsingJava8StreamApiParallel(){
System. out .println(map.entrySet().parallelStream().mapToLong(e -> e.getKey() + e.getValue()).sum());
}
Comparación de cada método en términos de velocidad:
public final static Integer SIZE = 1000000;
public Map<Integer, Integer> map = toMap();
public Map<Integer, Integer> toMap(){
map = new HashMap<>(SIZE);
for (int i = 0; i < SIZE; i++) {
map.put(i, i);
}
return map;
}
Obtenemos:
GO TO FULL VERSION