Hi! I'm Remsey, your Java instructor. Ready to flow through data with Streams!
Prefer to learn by listening? Hit play below and watch the audio come to life!
Welcome to Java Streams β the functional programming powerhouse that makes working with collections feel like magic! πβ¨
Imagine you have a huge pile of data β names, numbers, objects. Instead of writing messy loops and if-statements, Streams let you say: "Filter this, map that, and give me the result!" π―
Streams turn collections into data pipelines that are clean, readable, and incredibly powerful.
A Stream in Java is a sequence of elements from a source (like a List or Array) that supports aggregate operations. Think of it like a conveyor belt in a factory β data flows through, gets transformed, and comes out the other end! π
Let's start with a simple example β filtering numbers:
import java.util.Arrays;
import java.util.List;
public class StreamBasics {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
// Old way - with for loop π΄
System.out.println("Old way:");
for (Integer num : numbers) {
if (num % 2 == 0) {
System.out.print(num + " ");
}
}
// Stream way - clean and beautiful! π
System.out.println("\n\nStream way:");
numbers.stream()
.filter(n -> n % 2 == 0)
.forEach(n -> System.out.print(n + " "));
}
}
Streams have two types of operations:
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class MapExample {
public static void main(String[] args) {
List<String> names = Arrays.asList("alice", "bob", "charlie", "diana");
// Convert all names to uppercase
List<String> upperNames = names.stream()
.map(String::toUpperCase)
.collect(Collectors.toList());
System.out.println("Original: " + names);
System.out.println("Uppercase: " + upperNames);
// Get name lengths
List<Integer> nameLengths = names.stream()
.map(String::length)
.collect(Collectors.toList());
System.out.println("Lengths: " + nameLengths);
}
}
The real power comes from chaining operations together! Let's build a pipeline:
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class StreamChaining {
public static void main(String[] args) {
List<String> fruits = Arrays.asList(
"apple", "banana", "cherry", "avocado",
"apricot", "blueberry", "kiwi"
);
// Get fruits starting with 'a', make uppercase, sort, collect
List<String> result = fruits.stream()
.filter(f -> f.startsWith("a")) // Filter
.map(String::toUpperCase) // Transform
.sorted() // Sort
.collect(Collectors.toList()); // Collect
System.out.println("π Fruits starting with 'a':");
result.forEach(f -> System.out.println(" - " + f));
}
}
Streams really shine when working with objects! Let's create a Person class and filter/sort people:
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
class Person {
String name;
int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String toString() {
return name + " (" + age + ") ";
}
}
public class PersonStream {
public static void main(String[] args) {
List<Person> people = Arrays.asList(
new Person("Alice", 25),
new Person("Bob", 30),
new Person("Charlie", 22),
new Person("Diana", 28)
);
// Find people over 25, sort by age
System.out.println("π€ People over 25 (sorted by age):");
people.stream()
.filter(p -> p.age > 25)
.sorted((p1, p2) -> Integer.compare(p1.age, p2.age))
.forEach(System.out::println);
// Get list of names only
List<String> names = people.stream()
.map(p -> p.name)
.collect(Collectors.toList());
System.out.println("\nπ All names: " + names);
}
}
Terminal operations give you the final result. Here are some game-changers:
import java.util.Arrays;
import java.util.List;
import java.util.OptionalDouble;
public class TerminalOps {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(5, 10, 15, 20, 25, 30);
// Count
long count = numbers.stream().count();
System.out.println("Count: " + count);
// Sum
int sum = numbers.stream()
.mapToInt(Integer::intValue)
.sum();
System.out.println("Sum: " + sum);
// Average
OptionalDouble avg = numbers.stream()
.mapToInt(Integer::intValue)
.average();
System.out.println("Average: " + avg.orElse(0));
// Max
int max = numbers.stream()
.mapToInt(Integer::intValue)
.max()
.orElse(0);
System.out.println("Max: " + max);
// Min
int min = numbers.stream()
.mapToInt(Integer::intValue)
.min()
.orElse(0);
System.out.println("Min: " + min);
}
}
You have a list of products with prices. Filter products under $50, get their names in uppercase, and collect them into a list!
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
class Product {
String name;
double price;
public Product(String name, double price) {
this.name = name;
this.price = price;
}
}
public class ProductChallenge {
public static void main(String[] args) {
List<Product> products = Arrays.asList(
new Product("laptop", 899.99),
new Product("mouse", 25.50),
new Product("keyboard", 45.00),
new Product("monitor", 199.99),
new Product("usb cable", 9.99)
);
// TODO: Filter products under $50
// TODO: Map to uppercase names
// TODO: Collect to list
// TODO: Print the result
}
}
Master Streams with these hands-on exercises!
Task: Given a list of integers, use Streams to calculate the sum of squares of all even numbers.
filter() to get even numbersmap() to square each numberreduce() or sum() to add them upimport java.util.Arrays;
import java.util.List;
public class SumOfSquares {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
int sumOfSquares = numbers.stream()
.filter(n -> n % 2 == 0) // Even numbers only
.map(n -> n * n) // Square them
.mapToInt(Integer::intValue) // Convert to int stream
.sum(); // Sum them up
System.out.println("π Sum of squares of even numbers: " + sumOfSquares);
System.out.println("Calculation: 2Β² + 4Β² + 6Β² + 8Β² + 10Β² = 4 + 16 + 36 + 64 + 100 = " + sumOfSquares);
}
}
Task: Given a list of words, group them by their length
using Streams and Collectors.groupingBy().
Collectors.groupingBy()String::lengthMap<Integer, List<String>>import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class GroupByLength {
public static void main(String[] args) {
List<String> words = Arrays.asList(
"Java", "is", "awesome", "I", "love",
"coding", "in", "Java", "Streams"
);
Map<Integer, List<String>> grouped = words.stream()
.collect(Collectors.groupingBy(String::length));
System.out.println("π Words grouped by length:");
grouped.forEach((length, wordList) -> {
System.out.println(" Length " + length + ": " + wordList);
});
}
}
Task: Given a list of employees with salaries, find the top 3 highest-paid employees using Streams.
sorted() with a custom comparatorlimit(3) to get top 3Comparator.reverseOrder()import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
class Employee {
String name;
double salary;
public Employee(String name, double salary) {
this.name = name;
this.salary = salary;
}
public String toString() {
return name + ": $" + salary;
}
}
public class Top3Salaries {
public static void main(String[] args) {
List<Employee> employees = Arrays.asList(
new Employee("Alice", 75000),
new Employee("Bob", 95000),
new Employee("Charlie", 65000),
new Employee("Diana", 120000),
new Employee("Eve", 88000),
new Employee("Frank", 102000)
);
System.out.println("π Top 3 Highest Paid Employees:");
employees.stream()
.sorted(Comparator.comparingDouble((e -> e.salary)).reversed())
.limit(3)
.forEach(e -> System.out.println(" " + e));
}
}
π‘ Pro Tip: Streams make your code more readable and maintainable! Once you get the hang of them, you'll never want to write loops again. They're also optimized for parallel processing! π
PREVIOUS MODULE
Generics
NEXT MODULE
Coming Soon...