For loop ou Foreach – qual é mais rápido em Java?
Fonte: Medium Quando eu estava procurando emprego há alguns anos, uma das perguntas que me fizeram em uma entrevista foi se deveríamos iterar em um ArrayList usando for ou forEach ? O debate sobre a diferença de preferências entre forEach e for já existe há muito tempo. Fiquei com a impressão de que forEach é mais rápido. Mas no final percebi que estava errado. Para sua informação, o loop forEach (ou loop for aprimorado ) introduzido no Java 1.5 elimina a confusão e a possibilidade de erro, ocultando completamente o iterador ou a variável de índice. Acredito que a única diferença prática entre for e forEach é que no caso de objetos indexados, não temos acesso ao índice.for(int i = 0; i < mylist.length; i++) {
if(i < 5) {
//do something
} else {
//do other stuff
}
}
No entanto, podemos criar uma variável de índice separada do tipo int usando forEach . Por exemplo:
int index = -1;
for(int myint : mylist) {
index++;
if(index < 5) {
//do something
} else {
//do other stuff
}
}
Vamos escrever uma classe simples que possui um método foreachTest() que itera por uma lista usando forEach .
import java.util.List;
public class ForEachTest {
List<Integer> intList;
public void foreachTest(){
for(Integer i : intList){
}
}
}
Quando compilamos esta classe, o compilador converte internamente o código em uma implementação de iterador. Descompilei o código compilado executando 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 */
No bytecode acima, vemos:
-
O comando getfield é usado para obter variáveis inteiras.
-
Chame List.iterator para obter uma instância do iterador.
-
Chame iterator.hasNext . Se retornar verdadeiro, o método iterator.next deverá ser chamado .
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);
}
}
E aqui está o resultado: Como podemos ver, o desempenho do loop for é melhor que o do loop forEach . Se você usar LinkedList em vez de ArrayList , poderá ver que o desempenho de forEach é melhor para LinkedList . ArrayList usa arrays internamente para armazenar elementos. Como os arrays são regiões contíguas de memória, a complexidade de tempo é O(1). Isso ocorre porque os dados são recuperados por meio de índices. LinkedList usa uma lista duplamente vinculada. Quando usamos um loop for para implementar a travessia, ele sempre começa no nó principal da lista vinculada, portanto, a complexidade do tempo é O (n * n).
8 maneiras eficientes de percorrer cada entrada em um mapa Java
Fonte: Medium Na semana passada, um estagiário me perguntou como iterar um mapa Java. Respondi que por ser muito simples, a resposta para essa pergunta está sempre no Google. Depois de algum tempo, ela me enviou o endereço da página no StackOverflow e descobri que um grande número de pessoas estava prestando atenção nesse problema. Portanto, decidi me debruçar sobre a questão da iteração e compartilhar com vocês várias maneiras de fazer isso.1. Usando iterador e 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 e 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 do 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 e 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. Usando for e 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. Usando Java 8 Stream API
@Test
public void test7_UsingJava8StreamApi(){
System. out .println(map.entrySet().stream().mapToLong(e -> e.getKey() + e.getValue()).sum());
}
8. Uso paralelo da API Java 8 Stream
@Test
public void test8_UsingJava8StreamApiParallel(){
System. out .println(map.entrySet().parallelStream().mapToLong(e -> e.getKey() + e.getValue()).sum());
}
Comparação de cada método em termos de velocidade:
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;
}
Nós temos:
GO TO FULL VERSION