In Java 8, we can use the new forEach to loop or iterate a Map, List, Set, or Stream.
Topics
- Loop a Map
- Loop a List
- forEach and Consumer
- forEach and Exception handling
- forEach vs forEachOrdered
1. Loop a Map
1.1 Below is a normal way to loop a Map.
public static void loopMapClassic() {
Map<String, Integer> map = new HashMap<>();
map.put("A", 10);
map.put("B", 20);
map.put("C", 30);
map.put("D", 40);
map.put("E", 50);
map.put("F", 60);
for (Map.Entry<String, Integer> entry : map.entrySet()) {
System.out.println("Key : " + entry.getKey() + ", Value : " + entry.getValue());
}
}
1.2 In Java 8, we can use forEach to loop a Map and print out its entries.
public static void loopMapJava8() {
Map<String, Integer> map = new HashMap<>();
map.put("A", 10);
map.put("B", 20);
map.put("C", 30);
map.put("D", 40);
map.put("E", 50);
map.put("F", 60);
// lambda
map.forEach((k, v) -> System.out.println("Key : " + k + ", Value : " + v));
}
Output
Key : A, Value : 10
Key : B, Value : 20
Key : C, Value : 30
Key : D, Value : 40
Key : E, Value : 50
Key : F, Value : 60
1.3 For the Map‘s key or value containing null, the forEach will print null.
public static void loopMapJava8() {
Map<String, Integer> map = new HashMap<>();
map.put("A", 10);
map.put("B", 20);
map.put("C", 30);
map.put(null, 40);
map.put("E", null);
map.put("F", 60);
// ensure map is not null
if (map != null) {
map.forEach((k, v) -> System.out.println("Key : " + k + ", Value : " + v));
}
}
Output
Key : null, Value : 40
Key : A, Value : 10
Key : B, Value : 20
Key : C, Value : 30
Key : E, Value : null
Key : F, Value : 60
P.S The normal way to loop a Map will print the same above output.
1.4 If we do not want to print the null key, add a simple null checking inside the forEach.
public static void loopMapJava8() {
Map<String, Integer> map = new HashMap<>();
map.put("A", 10);
map.put("B", 20);
map.put("C", 30);
map.put(null, 40);
map.put("E", null);
map.put("F", 60);
map.forEach(
(k, v) -> {
// yes, we can put logic here
if (k != null){
System.out.println("Key : " + k + ", Value : " + v);
}
}
);
}
Output
Key : A, Value : 10
Key : B, Value : 20
Key : C, Value : 30
Key : E, Value : null
Key : F, Value : 60
2. Loop a List
2.1 Below is a normal way to loop a List.
public static void loopListClassic() {
List<String> list = new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");
list.add("D");
list.add("E");
// normal loop
for (String l : list) {
System.out.println(l);
}
}
2.2 Java 8 forEach to loop a List.
public static void loopListJava8() {
List<String> list = new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");
list.add("D");
list.add("E");
// lambda
// list.forEach(x -> System.out.println(x));
// method reference
list.forEach(System.out::println);
}
Output
A
B
C
D
E
2.3 This example filters the null value of a List.
public static void loopListJava8() {
List<String> list = new ArrayList<>();
list.add("A");
list.add("B");
list.add(null);
list.add("D");
list.add("E");
// filter null value
list.stream()
.filter(Objects::nonNull)
.forEach(System.out::println);
}
Output
A
B
D
E
P.S The forEach for Set and Stream works the same way.
3. forEach and Consumer
3.1 Review the forEach method signature, it accepts a functional interface Consumer.
public interface Iterable<T> {
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
//..
}
public interface Stream<T> extends BaseStream<T, Stream<T>> {
void forEach(Consumer<? super T> action);
//...
}
3.2 This example creates a Consumer method to print String to its Hex format. We can now reuse the same Consumer method and pass it to the forEach method of List and Stream.
package com.mkyong.java8.misc;
import java.util.*;
import java.util.function.Consumer;
import java.util.stream.Stream;
public class ForEachConsumer {
public static void main(String[] args) {
List<String> list = Arrays.asList("abc", "java", "python");
Stream<String> stream = Stream.of("abc", "java", "python");
// convert a String to a Hex
Consumer<String> printTextInHexConsumer = (String x) -> {
StringBuilder sb = new StringBuilder();
for (char c : x.toCharArray()) {
String hex = Integer.toHexString(c);
sb.append(hex);
}
System.out.print(String.format("%n%-10s:%s", x, sb.toString()));
};
// pass a Consumer
list.forEach(printTextInHexConsumer);
stream.forEach(printTextInHexConsumer);
}
}
Output
abc :616263
java :6a617661
python :707974686f6e
abc :616263
java :6a617661
python :707974686f6e
4. forEach and Exception handling.
4.1 The forEach is not just for printing, and this example shows how to use forEach method to loop a list of objects and write it to files.
package com.mkyong.java8.misc;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;
public class ForEachWriteFile {
public static void main(String[] args) {
ForEachWriteFile obj = new ForEachWriteFile();
obj.save(Paths.get("C:\\test"), obj.createDummyFiles());
}
public void save(Path path, List<DummyFile> files) {
if (!Files.isDirectory(path)) {
throw new IllegalArgumentException("Path must be a directory");
}
files.forEach(f -> {
try {
int id = f.getId();
// create a filename
String fileName = id + ".txt";
Files.write(path.resolve(fileName),
f.getContent().getBytes(StandardCharsets.UTF_8));
} catch (IOException e) {
e.printStackTrace();
}
});
}
public List<DummyFile> createDummyFiles() {
return Arrays.asList(
new DummyFile(1, "hello"),
new DummyFile(2, "world"),
new DummyFile(3, "java"));
}
class DummyFile {
int id;
String content;
public DummyFile(int id, String content) {
this.id = id;
this.content = content;
}
public int getId() {
return id;
}
public String getContent() {
return content;
}
}
}
The above program will create three text files.
hello
world
java
4.2 The Files.write may throws IOException, and we must catch the exception inside the forEach; thus, the code looks ugly. The common practice is to extract the code to a new method.
public void save(Path path, List<DummyFile> files) {
if (!Files.isDirectory(path)) {
throw new IllegalArgumentException("Path must be a directory");
}
// extract it to a new method
/*files.forEach(f -> {
try {
int id = f.getId();
// create a filename
String fileName = id + ".txt";
Files.write(path.resolve(fileName),
f.getContent().getBytes(StandardCharsets.UTF_8));
} catch (IOException e) {
e.printStackTrace();
}
});*/
// nice!
files.forEach(f -> saveFile(path, f));
}
public void saveFile(Path path, DummyFile f) {
try {
int id = f.getId();
// create a filename
String fileName = id + ".txt";
Files.write(path.resolve(fileName),
f.getContent().getBytes(StandardCharsets.UTF_8));
} catch (IOException e) {
e.printStackTrace();
}
}
Now, we also can write code like this:
ForEachWriteFile obj = new ForEachWriteFile();
Path path = Paths.get("C:\\test");
obj.createDummyFiles().forEach(o -> obj.saveFile(path, o));
5. forEach vs forEachOrdered
5.1 The forEach does not guarantee the stream’s encounter order, regardless of whether the stream is sequential or parallel. The result is obvious when run in a parallel mode.
Stream<String> s = Stream.of("a", "b", "c", "1", "2", "3");
s.parallel().forEach(x -> System.out.println(x));
Each run will generate different result:
1
2
b
c
3
a
5.2 The forEachOrdered guarantees the stream’s encounter order; thus, it sacrifices the benefit of parallelism.
Stream<String> s = Stream.of("a", "b", "c", "1", "2", "3");
// keep order, it is always a,b,c,1,2,3
s.parallel().forEachOrdered(x -> System.out.println(x));
The result is always a,b,c,1,2,3
a
b
c
1
2
3
Download Source Code
$ git clone https://github.com/mkyong/core-java
$ cd java8
Thanks for the additional examples. This was the most thorough tutorial I’ve seen, and the only one to address the need for null checks.
and I am always watching your example when I am getting error in my work.
Hi mkyong,
given all examples are simple and point to point, Thanks a lot.
forEach() is orderd ,while parallel() may not
can you please give me some examples how to replace the items in the list using Stream().
Hi Mkyong,
I really inspired by your way of explanation, very simple to understand.
Great examples. Thanks.
It really helped me.. thank you so much
The only think I don’t like using forEach is when you want to call inside it a service that throws exceptions, because you must catch them inside forEach loop. It doesn’t happen with “for” sentence, as you can have the try outside it.
Thanks, I was iterating a forEeah loop and instead of sysout. I want to perform few operations but I was getting an error. Your post help me identify what should I do.
hello, thanks for this tutorial. In Java 8 possible to use ‘::’ ?
items.forEach(System.out::println);
I checked it. It is equals the– items.forEach(item->System.out.println(item)); –?
Because the parameter and the return type is the same?
Sorry for dump question .
yes, method reference
https://mkyong.com/java8/java-8-method-references-double-colon-operator/
Clear and simple examples.
Keep it up!
Hi:
I keep learning a lot from your examples.. they are simple and to the point..thank you and keep it up.
Thanks, I updated the article with more examples.
When I do this, I am getting a null pointer exception when the value in the map is null (v is null). How can I avoid that?
items.forEach((k,v)->System.out.println(“Item : ” + k + ” Count : ” + v));
if (items != null) items.forEach((k,v)->System.out.println(“Item : ” + k + ” Count : ” + v));
Optional.ofNullable(items).orElse(Collections.emptyMap())
.forEach((k, v) -> System.out.println(“Item : ” + k + ” Count : ” + v));
The
Optional.ofNullable(items).orElse(Collections.emptyMap())is good for return type.For this case, a simple
if(items!=)is sufficient.Good page. Clear and simple examples. Thanks!