Java 8 (Modern Java) Functional Streams API & examples
Consider following core classes (POJOs – Plain Old Java Object | Model | Entity) , from typical
Ecommerce application.
public class Category {
private int categoryId
private String name; //unique
private String description;
private List<Product> products=new ArrayList<>();
//constructor , getters setters
public class Product {
private int productId;
private String name;//unique
private double price;
private int quantity;
private LocalDate manufactureDate;
private Category category;
//constructor , getters setters
// Sample Data
Category electronics = new Category(1, "Electronics", "Electronic devices", new ArrayList<>());
Category groceries = new Category(2, "Groceries", "Daily essentials", new ArrayList<>());
Product p1 = new Product(101, "Laptop", 90000, 5, [Link](2024, 1, 10), electronics);
Product p2 = new Product(102, "Mobile", 50000, 10, [Link](2023, 11, 20), electronics);
Product p3 = new Product(103, "TV", 30000, 3, [Link](2024, 5, 15), electronics);
Product p4 = new Product(201, "Rice", 50, 100, [Link](2025, 1, 1), groceries);
Product p5 = new Product(202, "Milk", 30, 50, [Link](2025, 2, 1), groceries);
[Link]().addAll([Link](p1, p2, p3));
[Link]().addAll([Link](p4, p5));
List<Category> categories = [Link](electronics, groceries);
// STREAM EXAMPLES
1. filter → Get all products above 40,000
List<Product> expensive = [Link]() //Stream<Category>
.flatMap(c -> [Link]().stream()) //Stream<Product>
.filter(p -> [Link]() > 40000) //filtered Stream<Product>
.collect([Link]()); //List<Product>
[Link]("Expensive products (>40k): " + expensive);
2. map → Extract product names
List<String> names = [Link]()
.flatMap(c -> [Link]().stream())
.map(Product::getName)//Using Method reference, lambda – p-> [Link]() ,
Stream<String>
.collect([Link]());
[Link]("Product names: " + names);
3. flatMap → Get all products in one list
List<Product> allProducts = [Link]()
.flatMap(c -> [Link]().stream())
.collect([Link]());
[Link]("All products: " + allProducts);
4. reduce → Total value of all products (price * quantity)
double totalValue = [Link]()
.flatMap(c -> [Link]().stream())
.mapToDouble(p -> [Link]() * [Link]()) //DoubleStream containing total product
price
.reduce(0.0, Double::sum); //OR simply .sum()
[Link]("Total stock value = " + totalValue);
5. collect → Group by category name
Map<String, List<Product>> productsByCategory = [Link]()
.collect([Link](
Category::getName,//key mapper function
Category::getProducts//value mapper function
));
[Link]("Products by category: ");
[Link]((k,v) -> [Link](k+” “+v));
6. findAny → Get any product cheaper than 100
Product cheap = [Link]()
.flatMap(c -> [Link]().stream())
.filter(p -> [Link]() < 100)
.findAny()
.orElseThrow(() -> new ProductHandlingException(“Cheap product not found !!!!”));
[Link]("Any cheap product: " + cheap);
7. min & max
Product cheapest = [Link]()
.flatMap(c -> [Link]().stream())
.min([Link](Product::getPrice))//or use usual lambda here – based
on price
.orElse(null);
[Link]("Cheapest product = " + cheapest);
Product costliest = [Link]()
.flatMap(c -> [Link]().stream())
.max([Link](Product::getPrice))
.orElse(null);
[Link]("Costliest product = " + costliest);
8. Display products sorted (by price)
[Link]()
.flatMap(c -> [Link]().stream())
.sorted([Link](Product::getPrice))
.forEach([Link]::println);
9. distinct
List<String> distinctCategoryNames = [Link]()
.map(Category::getName)
.distinct()
.collect([Link]());
[Link]("Distinct category names: " + distinctCategoryNames);
10. anyMatch, allMatch, noneMatch
boolean hasExpensive = [Link]()
.flatMap(c -> [Link]().stream())
.anyMatch(p -> [Link]() > 80000);
[Link]("Any product >80k? " + hasExpensive);
boolean allAffordable = [Link]()
.flatMap(c -> [Link]().stream())
.allMatch(p -> [Link]() < 10000);
[Link]("All affordable (<10K)? " + allAffordable);
boolean noneFree = [Link]()
.flatMap(c -> [Link]().stream())
.noneMatch(p -> [Link]() == 0);
[Link]("No free products? " + noneFree);
11. forEach
[Link]("Print all products:");
[Link]()
.flatMap(c -> [Link]().stream())
.forEach([Link]::println);
12. Group products by category name
List<Product> allProducts = [Link]()
.flatMap(c -> [Link]().stream())
.collect([Link]());
[Link]("All products: " + allProducts);
Map<String, List<Product>> productsByCategory = [Link]()
.collect([Link](p -> [Link]().getName()));
[Link]((k,v) -> [Link](k+” “+v));
13. Count products per category
Map<String, Long> countByCategory = [Link]()
.collect([Link](p -> [Link]().getName(), [Link]()));
[Link]((k,v) -> [Link](k+” “+v));
14. Average price per category
Map<String, Double> avgPriceByCategory = [Link]()
.collect([Link](p -> [Link]().getName(),
[Link](Product::getPrice)));
[Link]((k,v) -> [Link](k+” “+v));
15. Total stock value per category (sum of price*qty)
Map<String, Double> totalStockValue = [Link]()
.collect([Link](p -> [Link]().getName(),
[Link](p -> [Link]() * [Link]())));
[Link]("Total stock value per category: " );
[Link]((k,v) -> [Link](k+” “+v));
16. Partition products into expensive vs cheap (threshold = 5000)
Map<Boolean, List<Product>> partitioned = [Link]()
.collect([Link](p -> [Link]() > 5000));
[Link]("Partitioned products (expensive vs cheap): ");
[Link]((k,v) -> [Link](k+” “+v));
17. Join product names into string
String productNames = [Link]()
.map(Product::getName)
.collect([Link](", ", "[", "]"));//delimiter , prefix,suffix
[Link]("All product names: "+productNames);
18. Max price per category
Map<String, Optional<Product>> maxPriceByCategory = [Link]()
.collect([Link](p -> [Link]().getName(),
[Link]([Link](Product::getPrice))));
[Link]("Max priced product per category: ");
[Link]((k,v)-> [Link](k+” “+v));
19. Mapping products to just names per category
Map<String, List<String>> productNamesByCategory = [Link]()
.collect([Link](p -> [Link]().getName(),
[Link](Product::getName, [Link]())));
[Link]("Product names per category: " );
[Link]((k,v)-> [Link](k+” “+v));
// Sample Data
Category electronics = new Category(1, "Electronics", "Electronic devices", new ArrayList<>());
Category groceries = new Category(2, "Groceries", "Daily essentials", new ArrayList<>());
Category clothing = new Category(3, "Clothing", "Fashion wear", new ArrayList<>());
Product p1 = new Product(101, "Laptop", 90000, 5, [Link](2024, 1, 10), electronics);
Product p2 = new Product(102, "Mobile", 50000, 10, [Link](2023, 11, 20), electronics);
Product p3 = new Product(103, "TV", 30000, 3, [Link](2024, 5, 15), electronics);
Product p4 = new Product(201, "Rice", 50, 100, [Link](2025, 1, 1), groceries);
Product p5 = new Product(202, "Milk", 30, 50, [Link](2025, 2, 1), groceries);
Product p6 = new Product(301, "Jeans", 2000, 20, [Link](2024, 9, 1), clothing);
Product p7 = new Product(302, "T-Shirt", 1000, 30, [Link](2024, 8, 15), clothing);
[Link]().addAll([Link](p1, p2, p3));
[Link]().addAll([Link](p4, p5));
[Link]().addAll([Link](p6, p7));
List<Category> categories = [Link](electronics, groceries, clothing);
20. Flatten products
List<Product> allProducts = [Link]()
.flatMap(c -> [Link]().stream())
.collect([Link]());
21. Top 3 most expensive products
List<Product> top3Expensive = [Link]()
.sorted([Link](Product::getPrice).reversed())//or can use
Comparator lambda also
.limit(3)
.collect([Link]());
[Link]("Top 3 expensive products: ");
[Link]([Link]::println);
22. Find newest product (latest manufacture date)
Product newest = [Link]()
.max([Link](Product::getManufactureDate))
.orElseThrow();
[Link]("Newest product: " + newest);
23. Find oldest product (earliest manufacture date)
Product oldest = [Link]()
.min([Link](Product::getManufactureDate))
.orElseThrow();
[Link]("Oldest product: " + oldest);
24. Total inventory value (all categories)
double totalInventory = [Link]()
.mapToDouble(p -> [Link]() * [Link]())
.sum();
[Link]("Total inventory value = " + totalInventory);
25. Products cheaper than 2000 grouped by category
Map<String, List<Product>> cheapProductsByCategory = [Link]()
.filter(p -> [Link]() < 2000)
.collect([Link](p -> [Link]().getName()));
[Link]("Cheap products per category (<2000): ");
[Link]((k,v)-> [Link](k+” “+v));
26. Average quantity per category
Map<String, Double> avgQtyByCategory = [Link]()
.collect([Link](p -> [Link]().getName(),
[Link](Product::getQuantity)));
[Link]("Average quantity per category: " + avgQtyByCategory);
[Link]<T> API
1. filter
Select elements that match a condition.
[Link](p -> [Link]() > 10000)
Input: Stream<Product>
Output: Stream<Product> (only expensive products)
2. map
Transform each element into something else.
[Link](Product::getName)// p -> [Link]()
Input: Stream<Product>
Output: Stream<String>
3. flatMap (map & faltten)
Flatten nested collections into a single stream(suitable for onemany mapping, One
CategoryMany Products)
[Link]().flatMap(c -> [Link]().stream())
Input: Stream<Category>
Output: Stream<Product>
4. sorted
Sort elements.
[Link]([Link](Product::getPrice)) //(p1,p2)->
((Double)[Link]()).compareTo([Link]());
Input: Stream<Product>
Output: Stream<Product> (sorted as per price asc)
5. distinct
Remove duplicates (based on equals/hashCode).
[Link]()
6. limit / skip
Get first N elements or skip N elements.
[Link](3) // top 3
[Link](5) // ignore first 5
7. findFirst / findAny
Short-circuit terminal operations to fetch one element.
[Link]() // deterministic (first element)
[Link]() // non-deterministic (any match, faster in parallel)
Output: Optional<T>
8. min / max
Find min or max based on comparator.
[Link]([Link](Product::getPrice))
[Link]([Link](Product::getManufactureDate))
Output: Optional<T>
9. reduce
Aggregate manually (sum, product, concatenation).
[Link](Product::getPrice).reduce(0.0, Double::sum) //equivalent to sum()
Output: one value (e.g. Double)
10. collect (collect stream elements into some collection | map)
Powerful aggregation into collections or maps.
[Link]([Link]()) // List<Product>
[Link]([Link]()) // Set<Product>
[Link]([Link](Product::getId, Product::getName)) // Map<id,name>
11. groupingBy
Group by a classifier (like SQL GROUP BY).
[Link]([Link](p -> [Link]().getName()))
Output: Map<String, List<Product>>
12. partitioningBy
Special case of grouping (boolean predicate).
[Link]([Link](p -> [Link]() > 1000))
Output: Map<Boolean, List<Product>>
13. counting / averaging / summing
Built-in collectors for statistics
[Link]() //count
[Link](Product::getPrice) //average
[Link](p -> [Link]() * [Link]())
14. joining
Concatenate strings.
[Link](Product::getName)
.collect([Link](", ", "[", "]")) //delimiter , prefix , suffix
Output: [Laptop, Mobile, TV, Rice, Milk]
15. mapping (inside grouping)
Transform values during grouping.
[Link](Product::getName, [Link]())
Output: Map<CategoryName, List<String>>
16. collectingAndThen
Post-process collector result.
[Link](
[Link]([Link](Product::getPrice)),
Optional::get
Example: directly get max element instead of Optional.
17. anyMatch / allMatch / noneMatch
Boolean checks on stream.
[Link](p -> [Link]() > 100000) // true/false
18. mapToInt / mapToDouble – mapper functions
Primitive specialization for performance.
[Link](p -> [Link]() * [Link]()).sum()
Output: primitive values (int, long, double)
19. forEach
Terminal operation.
[Link]([Link]::println);
Common Optional<T> Handling Methods
1. isPresent() / get() (old-school, not recommended for production)
Optional<Product> opt = [Link]()
.filter(p -> [Link]() > 5000)
.findFirst();
if ([Link]()) {
[Link]("Found: " + [Link]().getName());
get() without checking may throw the execption!
2. ifPresent()
Run logic only if value exists.
[Link](p -> [Link]("Found: " + [Link]()));
3. ifPresentOrElse() (Java 9+)
Handle both present & empty cases.
[Link](
p -> [Link]("Found: " + [Link]()),
() -> [Link]("No product found!")
);
4. orElse()
Provide a default if empty.
Product defaultProduct = [Link](new Product(0, "Default", 0.0, 0, null, null));
5. orElseGet()
Like orElse, but lazily computes default (supplier is called only if needed).
Product p = [Link](() -> createDummyProduct());
6. orElseThrow()
Throw supplied exception if empty.
Product p = [Link](() -> new RuntimeException("Product not found"));
7. map()
Transform the value inside the Optional (without unwrapping).
Optional<String> productName = [Link](Product::getName);
[Link]([Link]("Unknown"));
8. filter()
Keep only if condition matches.
[Link](p -> [Link]() > 10)
.ifPresent(p -> [Link]("Sufficient stock: " + [Link]()));
Examples
[Link] first expensive product > 70k
Optional<Product> expensiveOpt = [Link]()
.filter(p -> [Link]() > 70000)
.findFirst();
[Link](p -> [Link]("Expensive: " + p));
2. Use orElse
Product safeProduct = [Link](new Product(0, "Default", 0, 0, null, null));
[Link]("OrElse fallback: " + safeProduct);
3. Use orElseThrow
Product mustExist = [Link](() -> new RuntimeException("No product found
> 70k!"));
[Link]("OrElseThrow result: " + mustExist);
4. Extract just name with map
String productName = [Link](Product::getName).orElse("Unknown");
[Link]("Name: " + productName);
5. Apply filter on Optional
[Link](p -> [Link]() > 2)
.ifPresent(p -> [Link]("Has enough stock: " + p));
6. [Link](); // throws NoSuchElementException if empty
7. Custom Exception
// Custom exception for product not found
[Link](() -> new ProductNotFoundException(“No product found above 1
lakh!”)); // throws custom exception if empty