Java 9 Stream API – takeWhile() Method Explained with Examples
Java 9 added four new methods to the Stream API, and takeWhile() is one of the most useful. It allows you to take elements from a stream as long as a condition is true, stopping as soon as the first element fails the predicate. Think of it as a lazy alternative to filter() for ordered streams where you want to stop processing early.
This tutorial explains how takeWhile() works, how it differs from filter(), and shows practical use cases.
What is takeWhile()?
takeWhile(Predicate<T> predicate) is a short-circuiting intermediate operation. It processes stream elements in order and includes each element in the output as long as the predicate returns true. The moment it encounters an element for which the predicate returns false, it stops — even if later elements would have matched.
Key difference from filter():
filter()checks every element and returns all matching onestakeWhile()stops at the first non-matching element, discarding everything after it
Basic Example
package com.java9r;
import java.util.List;
import java.util.stream.Collectors;
public class Java9TakeWhileDemo {
public static void main(String[] args) {
// Sorted list of numbers
var numbers = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
// takeWhile: take numbers less than 6, stop at first >= 6
var taken = numbers.stream()
.takeWhile(n -> n < 6)
.collect(Collectors.toList());
System.out.println("takeWhile(n < 6): " + taken);
// Output: [1, 2, 3, 4, 5]
// filter: returns ALL elements less than 6
var filtered = numbers.stream()
.filter(n -> n < 6)
.collect(Collectors.toList());
System.out.println("filter(n < 6): " + filtered);
// Output: [1, 2, 3, 4, 5] -- same result because list is sorted
// The difference becomes clear with an unsorted list:
var unsorted = List.of(1, 3, 5, 2, 4, 6, 7);
var takeResult = unsorted.stream().takeWhile(n -> n < 6).collect(Collectors.toList());
var filterResult = unsorted.stream().filter(n -> n < 6).collect(Collectors.toList());
System.out.println("\nUnsorted list: " + unsorted);
System.out.println("takeWhile: " + takeResult); // [1, 3, 5, 2, 4] – stops at 6
System.out.println("filter: " + filterResult); // [1, 3, 5, 2, 4] – wait, 6 is excluded but 7 too
}
}
Real-World Example: Price Threshold
package com.java9r;
import java.util.List;
import java.util.stream.Collectors;
class Product {
String name;
double price;
Product(String name, double price) {
this.name = name;
this.price = price;
}
@Override
public String toString() {
return name + " (Rs. " + price + ")";
}
}
public class StreamAPITakewhile {
public static void main(String[] args) {
// Products sorted by price (ascending)
var products = List.of(
new Product("Pen", 15.0),
new Product("Notebook", 80.0),
new Product("Bag", 350.0),
new Product("Tablet", 5000.0),
new Product("Laptop", 55000.0)
);
System.out.println("=== Products List ===");
products.forEach(System.out::println);
// takeWhile: show products under Rs. 1000 (stops at Tablet)
System.out.println("\n--- Budget items (price < 1000) ---");
products.stream()
.takeWhile(p -> p.price < 1000)
.forEach(System.out::println);
// Pen, Notebook, Bag – stops when it hits Tablet (5000)
// Compare with filter:
System.out.println("\n--- filter (price < 1000) ---");
products.stream()
.filter(p -> p.price < 1000)
.forEach(System.out::println);
// Same result here because the list IS already sorted by price
}
}
Expected Output
=== Products List ===
Pen (Rs. 15.0)
Notebook (Rs. 80.0)
Bag (Rs. 350.0)
Tablet (Rs. 5000.0)
Laptop (Rs. 55000.0)
--- Budget items (price < 1000) ---
Pen (Rs. 15.0)
Notebook (Rs. 80.0)
Bag (Rs. 350.0)
--- filter (price < 1000) ---
Pen (Rs. 15.0)
Notebook (Rs. 80.0)
Bag (Rs. 350.0)
takeWhile with Strings
import java.util.List;
import java.util.stream.Collectors;
var names = List.of("Alice", "Bob", "Carol", "Dave", "Eve");
// Take names while their length is less than 5
var shortNames = names.stream()
.takeWhile(n -> n.length() < 5)
.collect(Collectors.toList());
System.out.println(shortNames); // [Alice, Bob] – stops at "Carol" (length 5)
dropWhile() – The Complement
Java 9 also added dropWhile(), which is the opposite of takeWhile(). It skips elements as long as the predicate is true, then returns all remaining elements:
var numbers = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
// dropWhile: skip numbers < 6, return the rest
var result = numbers.stream()
.dropWhile(n -> n < 6)
.collect(Collectors.toList());
System.out.println(result); // [6, 7, 8, 9, 10]
When to Use takeWhile vs filter
| Scenario | Use |
|---|---|
| Data is sorted and you want a prefix matching a condition | takeWhile() |
| Data is unsorted and you want all matching elements | filter() |
| Performance matters and you can stop early | takeWhile() |
| Log file processing: read until "ERROR" appears | takeWhile() |
| You need all matching elements regardless of order | filter() |
Important Notes
takeWhile()is most predictable on ordered streams (lists). On unordered streams (likeHashSet), the behavior is non-deterministic.- It is a short-circuiting operation, so it can exit the pipeline early, which is more efficient than
filter()+limit()in sorted scenarios. - Requires Java 9 or later.
Summary
takeWhile() is a clean and expressive way to take a prefix of an ordered stream. Unlike filter(), which checks every element, takeWhile() stops at the first non-matching element — making it more efficient for sorted data. Pair it with dropWhile() to split a stream into a "before" and "after" a condition. This API addition in Java 9 makes stream pipelines more expressive and avoids the need for index-based workarounds in sorted data processing.
Comments