
Table of Contents
ToggleJava 8 Stream API all methods with examples
Java 8 Stream API Methods revolutionized the way Java developers process collections of data. Introduced in Java 8, the Stream API enables functional-style operations on sequences of elements, such as filtering, mapping, and reducing. It allows concise, readable, and efficient code that performs aggregate operations on data.
In this article, we’ll explore the most commonly used Java 8 Stream API methods, along with easy-to-understand coding examples to help you master functional programming in Java.
What is the Java 8 Stream API?
The Stream API is a part of the java.util.stream
package. A Stream is not a data structure; instead, it represents a sequence of elements from a source, such as a collection or array, that supports aggregate operations.
Key Characteristics of Streams :
No storage: It doesn’t store elements.
Functional in nature: Uses functional interfaces and lambda expressions.
Lazily evaluated: Operations are not executed until a terminal operation is invoked.
Can be parallelized: Use
.parallelStream()
to improve performance.
Types of Stream Operations
There are two main types of operations in the Stream API:
Intermediate operations – Return a new stream and are lazy.
Terminal operations – Produce a result or a side-effect and trigger processing.
Let’s break down all the commonly used Java 8 Stream API methods under each category.
Intermediate Java 8 Stream API Methods
All These methods return another Stream object, allowing chaining of operations.
filter(Predicate predicate)
Filters elements based on a condition.
list.stream()
.filter(s -> s.startsWith("A"))
.collect(Collectors.toList());
map(Function mapper)
map method Transforms each element using a function.java
List list = Arrays.asList("Apple","Orange");
list.stream()
.map(String::toUpperCase)
.collect(Collectors.toList());
//output : APPLE, ORANGE
flatMap(Function> mapper)- what is flatmap in Java
flatmap in Java 8. It helps you flatten nested structures like List
into a single >
Stream
.It is often used when each element can map to multiple values, and you want to handle them in a single stream.
//Flattening a List of Lists
import java.util.*;
import java.util.stream.*;
public class FlatMapExample {
public static void main(String[] args) {
List> listOfLists = Arrays.asList(
Arrays.asList("a", "b"),
Arrays.asList("c", "d"),
Arrays.asList("e", "f")
);
List flattenedList = listOfLists.stream()
.flatMap(List::stream)
.collect(Collectors.toList());
System.out.println(flattenedList); // [a, b, c, d, e, f]
}
}
distinct()
It removes duplicate elements from a stream based on equals()
and hashCode()
.
import java.util.*;
import java.util.stream.*;
public class DistinctExample {
public static void main(String[] args) {
List numbers = Arrays.asList(1, 2, 2, 3, 4, 4, 5);
List distinctNumbers = numbers.stream()
.distinct()
.collect(Collectors.toList());
System.out.println(distinctNumbers); // [1, 2, 3, 4, 5]
}
}
sorted() or sorted(Comparator comparator)
The sorted()
method in Java 8 Streams is used to sort elements. It works with natural order (like numbers or strings), or with a custom comparator.
//sorted example with natural order and custom Comparator
import java.util.*;
import java.util.stream.*;
class Person {
String name;
int age;
Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return name + " (" + age + ")";
}
}
public class AllSortedExamples {
public static void main(String[] args) {
// 1. Sorting Integers (Natural Order)
List numbers = Arrays.asList(5, 3, 8, 1, 4);
List sortedNumbers = numbers.stream()
.sorted()
.collect(Collectors.toList());
System.out.println("Sorted Integers (Asc): " + sortedNumbers);
// 2. Sorting Integers (Descending Order)
List sortedNumbersDesc = numbers.stream()
.sorted(Comparator.reverseOrder())
.collect(Collectors.toList());
System.out.println("Sorted Integers (Desc): " + sortedNumbersDesc);
// 3. Sorting Strings Alphabetically
List names = Arrays.asList("Charlie", "Alice", "Bob");
List sortedNames = names.stream()
.sorted()
.collect(Collectors.toList());
System.out.println("Sorted Names: " + sortedNames);
// 4. Sorting Custom Objects by Age
List people = Arrays.asList(
new Person("Alice", 30),
new Person("Bob", 25),
new Person("Charlie", 35),
new Person("Bob", 28)
);
List sortedByAge = people.stream()
.sorted(Comparator.comparingInt(p -> p.age))
.collect(Collectors.toList());
System.out.println("People Sorted by Age: " + sortedByAge);
// 5. Sorting Custom Objects by Name then Age
List sortedByNameThenAge = people.stream()
.sorted(Comparator.comparing((Person p) -> p.name)
.thenComparingInt(p -> p.age))
.collect(Collectors.toList());
System.out.println("People Sorted by Name then Age: " + sortedByNameThenAge);
}
}
output :
Sorted Integers (Asc): [1, 3, 4, 5, 8]
Sorted Integers (Desc): [8, 5, 4, 3, 1]
Sorted Names: [Alice, Bob, Charlie]
People Sorted by Age: [Bob (25), Bob (28), Alice (30), Charlie (35)]
People Sorted by Name then Age: [Alice (30), Bob (25), Bob (28), Charlie (35)]
peek(Consumer action)
The peek() method in Java 8 Streams is a debugging or intermediate operation that lets you “peek” at the elements in the stream as they flow through the pipeline. It returns a stream with the same elements, but allows you to perform a side-effect operation (like System.out.println).
import java.util.*;
import java.util.stream.*;
public class PeekExample {
public static void main(String[] args) {
List names = Arrays.asList("Alice", "Bob", "Charlie");
List uppercased = names.stream()
.peek(name -> System.out.println("Original: " + name))
.map(String::toUpperCase)
.peek(name -> System.out.println("Uppercased: " + name))
.collect(Collectors.toList());
System.out.println("Final List: " + uppercased);
}
}
output :
Original: Alice
Uppercased: ALICE
Original: Bob
Uppercased: BOB
Original: Charlie
Uppercased: CHARLIE
Final List: [ALICE, BOB, CHARLIE]
limit(long maxSize)
It is used to truncate a stream — it returns only the first N elements of the stream.
import java.util.*;
import java.util.stream.*;
public class LimitExample {
public static void main(String[] args) {
List numbers = Arrays.asList(10, 20, 30, 40, 50);
List limited = numbers.stream()
.limit(3)
.collect(Collectors.toList());
System.out.println("Limited to first 3: " + limited); // [10, 20, 30]
}
}
skip(long n)
The skip()
method in Java 8 is used to skip the first N elements of a stream. It’s often used along with limit()
for things like pagination.
import java.util.*;
import java.util.stream.*;
public class SkipExample {
public static void main(String[] args) {
List items = Arrays.asList("A", "B", "C", "D", "E");
List skipped = items.stream()
.skip(2)
.collect(Collectors.toList());
System.out.println("After skipping 2: " + skipped); // [C, D, E]
}
}
Terminal Stream API Methods
collect(Collector collector)
The collect()
method in Java 8 is a terminal operation that transforms a stream into a collection, string, map, or other result container. It’s often used with Collectors utility methods.
Common use case with Collectors :
toList()
toSet()
toMap()
joining()
groupingBy()
partitioningBy()
import java.util.*;
import java.util.stream.*;
public class CollectExample {
public static void main(String[] args) {
//Collect to List
List names = Arrays.asList("Alice", "Bob", "Charlie");
List collectedList = names.stream()
.collect(Collectors.toList());
System.out.println("List: " + collectedList); // [Alice, Bob, Charlie]
//Collect to Set (removes duplicates)
List items = Arrays.asList("apple", "banana", "apple", "orange");
Set uniqueItems = items.stream()
.collect(Collectors.toSet());
System.out.println("Set: " + uniqueItems); // [banana, orange, apple]
//Collect to Map
List words = Arrays.asList("a", "bb", "ccc");
Map wordLengthMap = words.stream()
.collect(Collectors.toMap(word -> word, word -> word.length()));
System.out.println("Map: " + wordLengthMap); // {a=1, bb=2, ccc=3}
//Joining Strings
List names = Arrays.asList("Java", "Python", "C++");
String joined = names.stream()
.collect(Collectors.joining(", "));
System.out.println("Joined: " + joined); // Java, Python, C++
//Grouping By
List words = Arrays.asList("apple", "banana", "cherry", "apricot");
Map> groupedByFirstChar = words.stream()
.collect(Collectors.groupingBy(word -> word.charAt(0)));
System.out.println("Grouped: " + groupedByFirstChar);
// {a=[apple, apricot], b=[banana], c=[cherry]}
//Partitioning By
List numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
Map> evenOddPartition = numbers.stream()
.collect(Collectors.partitioningBy(n -> n % 2 == 0));
System.out.println("Partitioned: " + evenOddPartition);
// {false=[1, 3, 5], true=[2, 4, 6]}
}
}
Collectors.reducing() – Custom Reduction Logic
Collectors.reducing()
is a terminal collector in Java’s Streams API, used to perform reduction operations—combining stream elements into a single result, like summing numbers, finding a maximum, or concatenating strings.
Java 8 Program to Find the Longest Word in the List
import java.util.*;
import java.util.stream.*;
public class ReducingExample {
public static void main(String[] args) {
List words = Arrays.asList("apple", "banana", "cherry", "kiwi");
String longestWord = words.stream()
.collect(Collectors.reducing((s1, s2) -> s1.length() > s2.length() ? s1 : s2))
.orElse("No words");
System.out.println("Longest word: " + longestWord); // banana
}
}
Java 8 Program to Find the Length of the String using reducing ()
List words = Arrays.asList("apple", "banana", "cherry", "kiwi");
int totalLength = words.stream()
.collect(Collectors.reducing(0, String::length, Integer::sum));
System.out.println("Total length: " + totalLength); // e.g. 22
Collectors.mapping() – Map While Collecting
Collectors.mapping()
is super handy when you want to transform (map) elements while collecting them—think of it as a map()
+ collect()
combo in one clean step.
Java 8 Program to group the string by first letter and collect length
List words = Arrays.asList("apple", "banana", "cherry", "kiwi");
Map> groupedLengths = words.stream()
.collect(Collectors.groupingBy(
word -> word.charAt(0), // key: first character
Collectors.mapping(String::length, Collectors.toList()) // map to word length
));
System.out.println(groupedLengths);
// {a=[5], b=[6], c=[6], k=[4]}
Java 8 Program to group the string by first letter and join all words
List words = Arrays.asList("apple", "banana", "cherry", "kiwi");
Map groupedJoined = words.stream()
.collect(Collectors.groupingBy(
word -> word.charAt(0),
Collectors.mapping(w -> w, Collectors.joining(", "))
));
System.out.println(groupedJoined);
// {a=apple, b=banana, c=cherry, k=kiwi}
Real world example of using collect() operations like reducing(), mapping(), and groupingBy().
Use Case: Products in a Store.
We’ll work with a Product class that has:
name (String), category (String), price (double)
Then we’ll:
- Find the most expensive product.
- Calculate total price.
- Group products by category and map to prices.
- Group products by category and join names.
- Get the max price per category
import java.util.*;
import java.util.stream.*;
class Product {
String name;
String category;
double price;
Product(String name, String category, double price) {
this.name = name;
this.category = category;
this.price = price;
}
@Override
public String toString() {
return name + " ($" + price + ")";
}
}
public class ProductStreamExample {
public static void main(String[] args) {
List products = Arrays.asList(
new Product("Laptop", "Electronics", 1200.00),
new Product("Phone", "Electronics", 800.00),
new Product("TV", "Electronics", 1500.00),
new Product("Sofa", "Furniture", 700.00),
new Product("Chair", "Furniture", 150.00),
new Product("Desk", "Furniture", 300.00),
new Product("Book", "Stationery", 20.00),
new Product("Pen", "Stationery", 5.00)
);
// 1. Reducing: Find the most expensive product
Product mostExpensive = products.stream()
.collect(Collectors.reducing((p1, p2) -> p1.price > p2.price ? p1 : p2))
.orElse(null);
System.out.println("1. Most Expensive Product: " + mostExpensive);
// 2. Reducing: Total price of all products
double totalPrice = products.stream()
.collect(Collectors.reducing(0.0, p -> p.price, Double::sum));
System.out.println("2. Total Price: $" + totalPrice);
// 3. Mapping: Group by category, collect prices
Map> pricesByCategory = products.stream()
.collect(Collectors.groupingBy(
p -> p.category,
Collectors.mapping(p -> p.price, Collectors.toList())
));
System.out.println("3. Prices by Category: " + pricesByCategory);
// 4. Mapping: Group by category, join product names
Map namesByCategory = products.stream()
.collect(Collectors.groupingBy(
p -> p.category,
Collectors.mapping(p -> p.name, Collectors.joining(", "))
));
System.out.println("4. Product Names by Category: " + namesByCategory);
// 5. Mapping + Reducing: Group by category, get max price
Map maxPriceByCategory = products.stream()
.collect(Collectors.groupingBy(
p -> p.category,
Collectors.mapping(p -> p.price, Collectors.reducing(0.0, Double::max))
));
System.out.println("5. Max Price by Category: " + maxPriceByCategory);
}
}
output :
1. Most Expensive Product: TV ($1500.0)
2. Total Price: $4675.0
3. Prices by Category: {Electronics=[1200.0, 800.0, 1500.0], Furniture=[700.0, 150.0, 300.0], Stationery=[20.0, 5.0]}
4. Product Names by Category: {Electronics=Laptop, Phone, TV, Furniture=Sofa, Chair, Desk, Stationery=Book, Pen}
5. Max Price by Category: {Electronics=1500.0, Furniture=700.0, Stationery=20.0}
forEach method
It acts aseach element in the stream. Usually used for printing, logging, or updating external systems.It’s a terminal operation
List names = Arrays.asList("Alice", "Bob", "Charlie");
names.stream()
.forEach(name -> System.out.println("Hello, " + name));
output :
Hello, Alice
Hello, Bob
Hello, Charlie
toArray() method in Java 8
It is used to convert a Stream into an array. Below is the example to convert and string stream into String array, we can use any specific type for arrays like integers, long etc.
List names = Arrays.asList("Alice", "Bob", "Charlie");
String[] nameArray = names.stream()
.toArray(String[]::new);
System.out.println(Arrays.toString(nameArray));
// Output: [Alice, Bob, Charlie]
reduce(BinaryOperator accumulator) method
It reduces the stream’s elements using an associative accumulation function and returns an Optional
//sum of integers from a list of integers
import java.util.Arrays;
import java.util.Optional;
public class ReduceExample {
public static void main(String[] args) {
Optional sum = Arrays.asList(1, 2, 3, 4, 5)
.stream()
.reduce((a, b) -> a + b);
sum.ifPresent(System.out::println); // Output: 15
}
}
count() method
Counts the number of elements in a Stream. It return a long value.
long count = list.stream().count();
anyMatch(), allMatch(), noneMatch() methods
- anyMatch(Predicate
predicate) – Returns true if any element matches the predicate - allMatch(Predicate
predicate) – Returns true if all elements match the predicate - noneMatch(Predicate
predicate) – Returns true if none of the elements match the predicate
//Example to show anyMatch,allMatch and noneMatch methods
import java.util.Arrays;
import java.util.List;
public class MatchExamples {
public static void main(String[] args) {
List numbers = Arrays.asList(2, 4, 6, 8, 10);
// anyMatch: checks if *any* element is odd
boolean anyOdd = numbers.stream().anyMatch(n -> n % 2 != 0);
System.out.println("Any odd numbers? " + anyOdd); // false
// allMatch: checks if *all* elements are even
boolean allEven = numbers.stream().allMatch(n -> n % 2 == 0);
System.out.println("All numbers even? " + allEven); // true
// noneMatch: checks if *no* element is negative
boolean noneNegative = numbers.stream().noneMatch(n -> n < 0);
System.out.println("No negative numbers? " + noneNegative); // true
}
}
findFirst() and findAny() methods
Both are terminal operations in Java’s Stream API and return an element wrapped in an Optional.
- fiindFirst() – Returns the first element of the stream, if present.
- findAny() – Returns any element, useful for performance in parallel streams.
//findFirst,findAny method example
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
public class FindExamples {
public static void main(String[] args) {
List fruits = Arrays.asList("Apple", "Banana", "Mango", "Orange");
// findFirst: gets the first element in the stream
Optional firstFruit = fruits.stream().findFirst();
firstFruit.ifPresent(fruit -> System.out.println("First fruit: " + fruit));
// findAny: may return any element (especially useful in parallel streams)
Optional anyFruit = fruits.stream().findAny();
anyFruit.ifPresent(fruit -> System.out.println("Any fruit: " + fruit));
}
}
FAQs about Java 8 Stream API Methods
Q1. Are streams reusable?
No, Java streams cannot be reused once consumed. You must create a new stream to reprocess data.
Q2. What’s the difference between map
and flatMap
?map()
transforms elements; flatMap()
flattens nested structures (e.g., list of lists into a single list).
Q3. Can I use streams with files or IO operations?
Yes, classes like Files.lines()
allow stream processing over file lines.
Q4. When should I use parallelStream()
?
A: Use it when processing large datasets where operations are independent and thread-safe.
Conclusion
The Java 8 Stream API methods bring powerful data processing capabilities to Java developers. By learning how to use both intermediate and terminal operations, you can write clean, efficient, and maintainable code. Whether you’re filtering data, mapping values, or collecting results, the Stream API allows you to work with data at a higher abstraction level.With this complete overview of Java 8 Stream API methods, you now have the knowledge to implement modern Java features effectively in your projects.
Pingback: Java 8 Features | Java 8 Features with Example - Java Cody