Java Stream Operations
Stream operations reshape a flow or fold it into one answer. An Optional is a box that holds a value or holds nothing.
reduce folds a stream to one value
The sum fold starts from 0 and adds each number. The product fold starts from 1 and multiplies each number.
import java.util.List;
public class Main {
public static void main(String[] args) {
List<Integer> numbers = List.of(2, 3, 4);
int sum = numbers.stream().reduce(0, (a, b) -> a + b);
int product = numbers.stream().reduce(1, (a, b) -> a * b);
System.out.println(sum);
System.out.println(product);
}
}sorted and distinct reshape the flow
distinct drops the repeated 5 and the repeated 2. sorted then prints the survivors in rising order.
import java.util.List;
public class Main {
public static void main(String[] args) {
List<Integer> numbers = List.of(5, 2, 5, 8, 2, 9);
numbers.stream()
.distinct()
.sorted()
.forEach(System.out::println);
}
}min and max answer an Optional
The filled list gives a max that is present. The empty list gives a min that holds nothing, and orElse supplies -1.
import java.util.List;
import java.util.Optional;
public class Main {
public static void main(String[] args) {
List<Integer> scores = List.of(72, 95, 61);
Optional<Integer> max = scores.stream().max(Integer::compare);
System.out.println(max.isPresent());
System.out.println(max.orElse(-1));
List<Integer> empty = List.of();
Optional<Integer> min = empty.stream().min(Integer::compare);
System.out.println(min.isPresent());
System.out.println(min.orElse(-1));
}
}findFirst takes the first match
The first filter finds a name starting with B. The second finds no name starting with Z, and orElse supplies the word none.
import java.util.List;
import java.util.Optional;
public class Main {
public static void main(String[] args) {
List<String> names = List.of("Ben", "Ana", "Bob");
Optional<String> first = names.stream()
.filter(name -> name.startsWith("B"))
.findFirst();
System.out.println(first.orElse("none"));
Optional<String> missing = names.stream()
.filter(name -> name.startsWith("Z"))
.findFirst();
System.out.println(missing.orElse("none"));
}
}Example
import java.util.List;
import java.util.Optional;
public class Main {
public static void main(String[] args) {
List<Integer> prices = List.of(30, 10, 30, 50, 20);
int total = prices.stream()
.distinct()
.reduce(0, (a, b) -> a + b);
System.out.println(total);
Optional<Integer> firstBig = prices.stream()
.filter(price -> price >= 40)
.findFirst();
System.out.println(firstBig.orElse(-1));
}
}Key points
- reduce folds a stream into one value, starting from an identity value.
- The identity is the answer an empty stream would give for that fold.
- sorted orders the values in the flow, and distinct drops repeated values.
- min and max answer an Optional, because an empty stream has no extreme.
- isPresent reports whether an Optional holds a value.
- orElse answers a fallback value when the Optional holds nothing.
- findFirst answers the first value of the flow as an Optional.
In this example, distinct removes the repeated 30 before reduce adds the prices into 110. A second pipeline finds the first price of 40 or more. The search answers 50 through orElse.
Note
get reads the value from an Optional, and it throws an exception when the box is empty.
Try it Yourself
Edit the code, then press Run.
Running is simulated
Exercise
What does orElse answer when an Optional holds nothing?