Master Java Stream API: From Basics to Advanced Operations
This comprehensive guide explains the Java Stream API, covering its purpose, creation methods, intermediate and terminal operations, and the Optional class, with clear examples and code snippets to help developers write cleaner, more efficient functional-style code.
1. Overview of Stream API
Java 8 introduced two major features: Lambda expressions and the Stream API, which brings functional programming concepts into Java, greatly improving developer productivity by enabling concise, clean data processing.
1.1 Why Use Stream API
Streams allow operations on data sources such as collections, arrays, and databases (including NoSQL) without storing elements, providing a pipeline for filtering, mapping, and aggregating data.
1.2 What Is a Stream
A Stream is a sequence of elements generated from a data source, focusing on computation rather than storage.
Streams do not store elements.
Streams do not modify the source; they produce a new Stream.
Stream operations are lazy and execute only when a terminal operation is invoked.
2. Creating Streams
Since Stream is an interface, you cannot instantiate it directly. Four creation methods are provided:
2.1 From Collections
default Stream<T> stream(): returns a sequential stream. default Stream<T> parallelStream(): returns a parallel stream.
package blogs.blog13;
import day33.java.Employee;
import day33.java.EmployeeData;
import java.util.List;
import java.util.stream.Stream;
public class StreamAPITest {
public static void main(String[] args) {
List<Employee> employeeList = EmployeeData.getEmployees();
Stream<Employee> stream = employeeList.stream();
System.out.println(stream);
Stream<Employee> employeeStream = employeeList.parallelStream();
System.out.println(employeeStream);
}
}2.2 From Arrays
static Stream<T> stream(T[] array): creates a stream from an array.
Overloads for primitive arrays: IntStream stream(int[]), LongStream stream(long[]), DoubleStream stream(double[]).
import java.util.Arrays;
import java.util.stream.IntStream;
public class StreamAPITest {
public static void main(String[] args) {
int[] arr = {1,2,3,4,5,6};
IntStream stream = Arrays.stream(arr);
System.out.println(stream);
}
}2.3 Using Stream.of()
import java.util.stream.Stream;
public class StreamAPITest {
public static void main(String[] args) {
Stream<Integer> stream = Stream.of(1,2,3,4,5,6);
System.out.println(stream);
}
}2.4 Creating Infinite Streams
Stream.iterate(seed, UnaryOperator): generates an iterative infinite stream. Stream.generate(Supplier): generates an infinite stream of supplied values.
Stream.iterate(0, t -> t + 2).limit(10).forEach(System.out::println);
Stream.generate(Math::random).limit(10).forEach(System.out::println);3. Intermediate Operations
3.1 Filtering and Slicing
stream.filter(e -> e.getSalary() > 7000).forEach(System.out::println);
stream.distinct();
stream.limit(3);
stream.skip(3);3.2 Mapping
Stream<String> upper = list.stream().map(String::toUpperCase);
Stream<Character> chars = stream.flatMap(s -> fromStringToStream(s));3.3 Sorting
stream.sorted(); // natural order (requires Comparable
stream.sorted((e1,e2) -> Integer.compare(e1.getAge(), e2.getAge()));4. Terminal Operations
4.1 Matching and Finding
allMatch(Predicate) anyMatch(Predicate) noneMatch(Predicate) findFirst() findAny()4.2 Reduction
Integer sum = list.stream().reduce(0, Integer::sum);
Optional<Double> total = salaries.reduce((a,b) -> a + b);4.3 Collecting
List<Employee> highEarners = list.stream()
.filter(e -> e.getSalary() > 6000)
.collect(Collectors.toList());5. Optional Class
Optional is a container that may hold a non‑null value or be empty, helping to avoid NullPointerException. Creation methods include Optional.of(value), Optional.empty(), and Optional.ofNullable(value). Common methods: isPresent(), ifPresent(), get(), orElse(), orElseGet(), and orElseThrow().
Optional<Girl> opt = Optional.ofNullable(girl);
String name = opt.orElse(new Girl(new Boy("Default"))).getBoy().getName();6. Summary
Streams provide a functional way to process collections and arrays.
Operations follow three steps: create, intermediate, terminal.
Four ways to create streams: from collections, arrays, Stream.of(), and infinite streams.
Streams are single‑use; after a terminal operation a new stream must be created.
Intermediate operations are lazy; terminal operations trigger processing.
Optional helps handle potentially null values safely.
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 Captain
Focused on Java technologies: SSM, the Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading; occasionally covers DevOps tools like Jenkins, Nexus, Docker, ELK; shares practical tech insights and is dedicated to full‑stack Java 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.
