Master Java 8 Streams: Simplify Collections with Powerful Functional Operations
This article explains Java 8 Stream API concepts, showing how to filter, sort, map, and group collections with concise lambda expressions and functional operations, providing before‑and‑after code examples that reduce boilerplate and improve readability for common data‑processing tasks.
01 How Streams Simplify Code
If a requirement needs to process dishes retrieved from a database, the steps are to filter dishes with calories less than 400, sort the filtered dishes, and extract their names.
public class Dish {
private String name;
private boolean vegetarian;
private int calories;
private Type type;
// getters and setters
}Java 8 Before
private List<String> beforeJava7(List<Dish> dishList) {
List<Dish> lowCaloricDishes = new ArrayList<>();
// 1. filter calories < 400
for (Dish dish : dishList) {
if (dish.getCalories() < 400) {
lowCaloricDishes.add(dish);
}
}
// 2. sort by calories
Collections.sort(lowCaloricDishes, new Comparator<Dish>() {
@Override
public int compare(Dish o1, Dish o2) {
return Integer.compare(o1.getCalories(), o2.getCalories());
}
});
// 3. extract names
List<String> lowCaloricDishesName = new ArrayList<>();
for (Dish d : lowCaloricDishes) {
lowCaloricDishesName.add(d.getName());
}
return lowCaloricDishesName;
}Java 8 After
private List<String> afterJava8(List<Dish> dishList) {
return dishList.stream()
.filter(d -> d.getCalories() < 400) // filter
.sorted(comparing(Dish::getCalories)) // sort
.map(Dish::getName) // extract name
.collect(Collectors.toList()); // collect to list
}The Stream API reduces the implementation from 24 lines to just 5.
New requirement: group dishes by type and return a Map<Type, List<Dish>> result.
Java 8 Before Grouping
private static Map<Type, List<Dish>> beforeJDK8(List<Dish> dishList) {
Map<Type, List<Dish>> result = new HashMap<>();
for (Dish dish : dishList) {
if (result.get(dish.getType()) == null) {
List<Dish> dishes = new ArrayList<>();
dishes.add(dish);
result.put(dish.getType(), dishes);
} else {
result.get(dish.getType()).add(dish);
}
}
return result;
}Java 8 After Grouping
private static Map<Type, List<Dish>> afterJDK8(List<Dish> dishList) {
return dishList.stream().collect(groupingBy(Dish::getType));
}02 What Is a Stream
A stream is a sequence of elements generated from a source that supports data‑processing operations (arrays, files, collections, functions). It is not a data structure and does not store data; its purpose is computation.
03 How to Create Streams
There are five main ways to generate a stream:
1. From a Collection
List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5);
Stream<Integer> stream = integerList.stream();2. From an Array
int[] intArr = new int[]{1, 2, 3, 4, 5};
IntStream stream = Arrays.stream(intArr);3. From Values
Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);4. From a File
Stream<String> lines = Files.lines(Paths.get("data.txt"), Charset.defaultCharset());5. From Functions (iterate / generate)
Stream<Integer> stream = Stream.iterate(0, n -> n + 2).limit(5);
Stream<Double> stream = Stream.generate(Math::random).limit(5);04 Stream Operation Types
Streams have two kinds of operations: intermediate (lazy) and terminal (eager). Intermediate operations such as filter, map, distinct, limit, skip, flatMap transform the stream without consuming it. Terminal operations like count, collect, findFirst, reduce trigger the actual processing.
Intermediate Operations
filter : keep elements that match a predicate.
distinct : remove duplicate elements.
limit : truncate the stream to a given size.
skip : discard the first n elements.
map : transform each element to another type.
flatMap : replace each element with a stream and flatten.
Terminal Operations
count : count elements.
collect : accumulate results into a collection or other container.
findFirst / findAny : retrieve an element.
reduce : combine elements into a single value.
min / max : obtain minimum or maximum element.
05 Using Streams
Examples of common intermediate and terminal operations:
// filter values greater than 3
List<Integer> integerList = Arrays.asList(1,1,2,3,4,5);
Stream<Integer> stream = integerList.stream().filter(i -> i > 3);
// distinct values
Stream<Integer> distinctStream = integerList.stream().distinct();
// limit to first 3 elements
Stream<Integer> limited = integerList.stream().limit(3);
// skip first 2 elements
Stream<Integer> skipped = integerList.stream().skip(2);
// map strings to their lengths
List<String> strings = Arrays.asList("Java 8", "Lambdas", "In", "Action");
Stream<Integer> lengths = strings.stream().map(String::length);
// flatMap example
List<String> words = Arrays.asList("Hello", "World");
List<String> distinctWords = words.stream()
.map(w -> w.split(" "))
.flatMap(Arrays::stream)
.distinct()
.collect(Collectors.toList());
// match operations
boolean allGreater = integerList.stream().allMatch(i -> i > 3);
boolean anyGreater = integerList.stream().anyMatch(i -> i > 3);
boolean noneGreater = integerList.stream().noneMatch(i -> i > 3);
// findFirst / findAny
Optional<Integer> first = integerList.stream().filter(i -> i > 3).findFirst();
Optional<Integer> any = integerList.stream().filter(i -> i > 3).findAny();
// reduce to sum
int sum = integerList.stream().reduce(0, Integer::sum);
// min / max
OptionalInt min = integerList.stream().mapToInt(Integer::intValue).min();
OptionalInt max = integerList.stream().mapToInt(Integer::intValue).max();07 Summary
The Stream API dramatically simplifies collection processing by providing declarative, chainable operations that improve code readability and reduce boilerplate. By mastering streams, developers can write concise, efficient, and maintainable Java code.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Java Backend Technology
Focus on Java-related technologies: SSM, Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading. Occasionally cover DevOps tools like Jenkins, Nexus, Docker, and ELK. Also share technical insights from time to time, committed to Java full-stack development!
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
