Table of Contents
- Java Streams: 1. API Overview and Stream Creation
- Java Streams: 2. Intermediate Operations
- Java Streams: 3. Terminal Operations
- Java Streams: 4. Examples
- Java Streams: 5. Common Mistakes
Stream API Examples
This post walks through practical stream examples.
Assume the Person class below exists:
class Person {
private String name;
private int age;
private String phoneNumber;
public Person(String name, int age, String phoneNumber) {
this.name = name;
this.age = age;
this.phoneNumber = phoneNumber;
}
// getters and setters omitted
}
List<V> to Map<K, V>
Convert a list of objects into a map keyed by one of their fields.
List<Person> personList = new ArrayList<>();
personList.add(new Person("Alice", 23, "010-1234-1234"));
personList.add(new Person("Yuri", 24, "010-2341-2341"));
personList.add(new Person("Chris", 29, "010-3412-3412"));
personList.add(new Person("Mango", 25, null));
// Function.identity is t -> t
Map<String, Person> personMap = personList.stream()
.collect(Collectors.toMap(Person::getName, Function.identity()));
When you first learn streams, the concise form can be hard to read. Here is the expanded version:
Map<String, Person> personMap = personList.stream()
.collect(Collectors.toMap(new Function<Person, String>() {
@Override
public String apply(Person person) {
return person.getName();
}
}, new Function<Person, Person>() {
@Override
public Person apply(Person person) {
return person;
}
}));
You can also use filter to keep only certain elements.
Map<String, Person> personMap = personList.stream()
.filter(person -> person.getAge() > 24) // 25+ only
.collect(Collectors.toMap(Person::getName, Function.identity()));
If multiple values map to the same key, Collectors.toMap throws IllegalStateException.
You can provide a BinaryOperator to resolve conflicts.
Map<Integer, Person> personMap = personList.stream()
.collect(Collectors.toMap(
o -> o.getAge(),
Function.identity(),
(oldValue, newValue) -> newValue)); // keep new value
If you want duplicate keys, use groupingBy and collect values into a list:
// collect values into a list
Map<Integer, List<Person>> duplicatedMap = personList.stream()
.collect(Collectors.groupingBy(Person::getAge));
Filter out nulls
Use filter with Objects::nonNull to remove null values.
Stream<String> stream = Stream.of("Alice", "Hoon", null, "Yuri", null);
List<String> filteredList = stream.filter(Objects::nonNull)
.collect(Collectors.toList());
Find the First Match
Use filter with findFirst.
List<Person> personList = new ArrayList<>();
personList.add(new Person("Alice", 23, "010-1234-1234"));
personList.add(new Person("Yuri", 24, "010-2341-2341"));
personList.add(new Person("Mango", 23, "010-3412-3412"));
// Alice
Person person = personList.stream()
.filter(p -> p.getAge() == 23)
.findFirst().get();
You can also use findAny. In sequential streams, it returns the same element.
In parallel streams, it may return any matching element.
// Alice or Mango
Person person = personList.parallelStream()
.filter(p -> p.getAge() == 23)
.findAny().get();
Sort a Stream
Sort by age ascending:
List<Person> personList = new ArrayList<>();
personList.add(new Person("Alice", 25, "010-1234-1234"));
personList.add(new Person("Yuri", 24, "010-2341-2341"));
personList.add(new Person("Mango", 23, "010-3412-3412"));
personList.add(new Person("Hoon", 26, "010-4123-4123"));
// Mango, Yuri, Alice, Hoon
personList.stream()
.sorted(Comparator.comparing(Person::getAge))
.forEach(p -> System.out.println(p.getName()));
Reverse the order with reversed().
// Hoon, Alice, Yuri, Mango
personList.stream()
.sorted(Comparator.comparing(Person::getAge).reversed())
.forEach(p -> System.out.println(p.getName()));
Reduce
Use reduce to fold elements into one result.
List<Integer> list = List.of(5, 4, 2, 1, 6, 7, 8, 3);
// 36
Integer result = list.stream()
.reduce(0, (value1, value2) -> value1 + value2);
For primitives, use IntStream to avoid boxing.
// 36
int intResult = list.stream()
// or .mapToInt(x -> x).sum();
.mapToInt(Integer::intValue).sum();
You can also apply custom conditions, such as “the longest string longer than Swift.”
List<String> list = List.of("Java", "C++", "Python", "Ruby");
// Python
String result = list.stream()
.reduce("Swift", (val1, val2) ->
val1.length() >= val2.length() ? val1 : val2);
Flatten a Nested Collection
Use flatMap to collapse nested structures.
String[][] names = new String[][]{
{"Alice", "Chris"}, {"Hoon", "Mango"}
};
// to list
List<String> list = Arrays.stream(names)
.flatMap(Stream::of)
.collect(Collectors.toList());
// to array
String[] flattedNames = Arrays.stream(names)
.flatMap(Stream::of).toArray(String[]::new);
Next
We covered practical stream examples. The next post discusses common mistakes when using the Stream API.