A Comprehensive Guide to Java Stream API.

Learner, Love to make things simple, Full Stack Developer, StackOverflower, Passionate about using machine learning, deep learning and AI
Search for a command to run...

Learner, Love to make things simple, Full Stack Developer, StackOverflower, Passionate about using machine learning, deep learning and AI
No comments yet. Be the first to comment.
Move beyond traditional RESTful thinking. Learn how to design APIs specifically for MCP (Model Context Protocol) servers. This guide covers the shift in mindset, a practical OpenAPI 3.1 example, and a Spring Boot implementation to make your services ...

Extending Kestra to Every Corner of Your Data Stack. Introduction: The Power of Plugins Imagine you're a master chef. You don't just have one knife - you have specialized tools for every task: a paring knife for delicate work, a chef's knife for chop...
Mastering Complex Orchestration Scenarios. Introduction: The Orchestrator's Toolkit Imagine you're conducting a symphony. You don't just wave your baton - you cue sections, adjust tempo, handle surprises, and ensure harmony. That's what advanced work...
From Data Extraction to Loading - A Practical Guide Introduction: Why ETL Still Matters in the Modern Data Stack Remember when data engineering was "extract, transform, load"? Some say ETL is dead, replaced by ELT, reverse ETL, and data mesh. But her...
Building Blocks of Declarative Orchestration. Introduction: The Power of Simplicity Imagine trying to build a house without understanding bricks, beams, and blueprints. That's what using an orchestration tool without understanding its core concepts f...
The Stream API, introduced in Java 8, is a powerful abstraction for processing collections of data in a functional-style. It enables operations on a sequence of elements (like filtering, mapping, and reducing) and supports parallel execution. Streams make it easier to write concise and efficient code, especially when working with large datasets or complex data processing pipelines.
Java Streams are a series of elements that support aggregate operations. They:
Are not data structures, but rather views of data.
Do not modify the original data.
Use lazy evaluation to execute operations only when necessary.
Support pipelining of operations for cleaner code.
Streams can be created from various sources such as collections, arrays, files, or even manually defined data.
// From a List
Stream<String> stream = List.of("apple", "banana", "cherry").stream();
// From an Array
Stream<Integer> arrayStream = Arrays.stream(new Integer[]{1, 2, 3, 4});
// From a File
Stream<String> fileStream = Files.lines(Paths.get("file.txt"));
// Using Stream.of
Stream<String> streamOfValues = Stream.of("one", "two", "three");
A finite stream has a limited number of elements. Most collections (like lists and arrays) provide finite streams.
Stream<String> finiteStream = List.of("one", "two", "three").stream();
Infinite streams are unbounded, meaning they can generate an infinite sequence of elements, typically created with methods like Stream.iterate() and Stream.generate().
Stream<Integer> infiniteStream = Stream.iterate(0, n -> n + 1);
Stream<Double> randomNumbers = Stream.generate(Math::random);
Infinite streams should generally be limited to avoid resource exhaustion.
Parallel streams allow for concurrent processing, improving performance for large datasets. Use .parallelStream() on collections or .parallel() on any stream to create a parallel stream.
List<String> data = Arrays.asList("apple", "banana", "cherry");
data.parallelStream().forEach(System.out::println);
Intermediate operations transform a stream, returning another stream, and can be chained together. They are lazily evaluated, meaning they only execute when a terminal operation is applied.
filter(Predicate<T>)Filters elements based on a predicate.
Stream<Integer> filtered = Stream.of(1, 2, 3, 4, 5).filter(n -> n % 2 == 0);
map(Function<T, R>)Applies a function to each element, transforming it to a new type.
Stream<String> uppercased = Stream.of("apple", "banana").map(String::toUpperCase);
flatMap(Function<T, Stream<R>>)Transforms each element into a stream and flattens the results.
Stream<String> flattened = Stream.of("apple banana", "cherry").flatMap(s -> Stream.of(s.split(" ")));
sorted(Comparator<T>)Sorts elements based on a comparator.
Stream<Integer> sorted = Stream.of(3, 1, 2).sorted();
distinct()Removes duplicate elements from the stream.
Stream<Integer> distinctValues = Stream.of(1, 2, 2, 3).distinct();
skip(long n)Skips the first n elements.
Stream<Integer> skipped = Stream.of(1, 2, 3, 4, 5).skip(2);
limit(long n)Limits the stream to the first n elements.
Stream<Integer> limited = Stream.of(1, 2, 3, 4, 5).limit(3);
Stream gatherers are not predefined, but you can create custom logic with existing operations. For example, you could combine filter, map, and other operations to create a customized transformation pipeline.
Terminal operations execute the stream pipeline and produce a result.
collect()Collects elements into a collection or other data structure.
List<Integer> collectedList = Stream.of(1, 2, 3).collect(Collectors.toList());
forEach(Consumer<T>)Performs an action on each element.
Stream.of(1, 2, 3).forEach(System.out::println);
reduce(BinaryOperator<T>)Reduces the elements to a single result.
int sum = Stream.of(1, 2, 3).reduce(0, Integer::sum);
count(), average(), min(), max()Aggregation functions.
long count = Stream.of(1, 2, 3).count();
int max = Stream.of(1, 2, 3).max(Integer::compare).orElse(0);
findFirst(), findAny()Finds the first or any element.
Optional<Integer> first = Stream.of(1, 2, 3).findFirst();
allMatch(Predicate), anyMatch(Predicate), noneMatch(Predicate)Checks if all, any, or none of the elements match a condition.
boolean allEven = Stream.of(2, 4, 6).allMatch(n -> n % 2 == 0);
null in StreamsStreams don’t handle null values gracefully. Avoid null elements by removing or transforming them. For instance, you can filter null elements with filter(Objects::nonNull).
Stream.of(1, null, 3)
.filter(Objects::nonNull)
.forEach(System.out::println);
The Java Stream API is a powerful toolkit for handling data in a functional style, making your code more readable and concise. This guide covered the core aspects of Java streams, from creation and transformations to aggregation and filtering. By understanding and applying these concepts, you’ll be well-equipped to process complex data more effectively. Use streams responsibly and remember that parallel streams are not always faster; test thoroughly to ensure efficiency.
More such articles:
https://www.youtube.com/@maheshwarligade