🌊 Java 8 Streams API – Simple Revision Notes
🔴 Why Streams were introduced?
Problem before Java 8:
Collection processing used for / while loops
Code was long and messy
Hard to read & maintain
Parallel processing was difficult
Solution in Java 8:
Streams API was introduced to process collections in a clean, functional, and
readable way.
Feature Description Example
Sequence of elements
Stream supporting functional-style List<Integer> list = ...; [Link]()
operations
Intermediate Return a new stream; lazy filter(), map(), sorted(), distinct()
Operations
Terminal Produce a result or side- forEach(), collect(), count(),
Operations effect; triggers execution reduce()
Parallel Stream Allows parallel processing [Link]()
Utilities to accumulate collect([Link]()), toSet(),
Collectors results joining()
Lazy evaluation, functional stream operations do not modify
Key Points style, no storage original collection
🟢 What is a Stream?
A Stream is a sequence of elements used to process data from a collection
using functional style.
📌 Remember:
Stream does not store data
Stream works on collections
Stream does not change original data
🟢 Programming Style Used
Streams follow:
✅ Functional style
✅ Declarative style
❌ Not imperative (loop-based)
Focus on WHAT to do, not HOW to do.
🔗 Streams depend on these Java 8 features
1. Lambda Expressions
2. Functional Interfaces
3. Method References
4. Collections Framework
🔁 Stream Pipeline (MOST IMPORTANT)
A Stream works in 3 steps:
1⃣ Source
Collection or array
[Link]();
2⃣ Intermediate Operations
Process data
Return another Stream
Lazy execution
Examples:
filter()
map()
sorted()
.filter(n -> n % 2 == 0)
3⃣ Terminal Operation
Produces result
Triggers execution
Examples:
forEach()
collect()
count()
.forEach([Link]::println);
🔹 Simple Example (Must Remember)
[Link]()
.filter(n -> n % 2 == 0)
.forEach([Link]::println);
📌 Important Stream Rules (Non-Negotiable)
✅ Rule 1: Stream does NOT store data
Works on existing collection
✅ Rule 2: Stream is ONE-TIME use
Cannot reuse a stream
✅ Rule 3: Stream does NOT modify original data
Original collection remains unchanged
✅ Rule 4: Without terminal operation → NO execution
🟢 Common Stream Methods (Interview Must-Know)
Intermediate Operations
filter()
map()
sorted()
distinct()
limit()
Terminal Operations
forEach()
collect()
count()
reduce()
findFirst()
📦 Collectors (Very Common)
[Link]()
[Link]()
[Link]()
[Link]()
⚙️ Parallel Streams
[Link]();
Use when:
Large data
CPU-intensive tasks
⚠️ Stream vs Collection (Quick Difference)
Stream Collection
Process data Store data
One-time use Reusable
Lazy Eager
Functional style OOP style
🎯 5 One-Line Interview Answers (Memorize)
1⃣ Streams process collections in functional style
2⃣ Streams do not store data
3⃣ Streams are lazy
4⃣ Streams support parallel processing
5⃣ Streams use lambdas and functional interfaces
🟢 Final Memory Formula (Very Easy)
Collection → Stream → filter/map → Result
💡 Final Confidence Note
You now understand:
WHY Streams exist
WHAT problem they solved
HOW they work (basics)
RULES you must not break
LAMBDA EXPRESSIONS – OVERVIEW
✅ What is a Lambda Expression?
A lambda expression is an anonymous function used to provide an
implementation for a functional interface.
Key points:
No method name
No access modifier
Return type is inferred
Short & readable
Introduced in Java 8
🟢 Lambda Syntax
(parameters) -> expression
Examples:
() -> [Link]("Hello");
(a, b) -> a + b;
n -> n % 2 == 0;
⚠️ Lambda Rules (Non-Negotiable)
1️⃣ Works only with functional interfaces
2⃣ Cannot be used with normal interfaces
3️⃣ Return type is inferred by compiler
4️⃣ Body can be single or multiple lines
🔴 Anonymous Class vs Lambda (Quick)
Anonymous Class Lambda
Java 7 Java 8
Too much code Short syntax
Multiple methods One abstract method
Class based Function based
🎯 Lambda One-Line Interview Answer
“A lambda expression is an anonymous function introduced in Java 8 to
simplify anonymous classes.”
🔹 FUNCTIONAL INTERFACES – OVERVIEW
✅ What is a Functional Interface?
An interface that has exactly ONE abstract method.
🟢 Why Functional Interface?
Lambda needs a target type
Functional interface provides that contract
👉 Lambda = implementation
👉 Functional Interface = rule
⚠️ Functional Interface Rules (Non-Negotiable)
1️⃣ Only ONE abstract method
2⃣ Can have default methods
3️⃣ Can have static methods
4️⃣ @FunctionalInterface is optional but recommended
🟢 Example
Functional Interface
@FunctionalInterface
interface Greeting {
void sayHello();
}
Lambda Implementation
Greeting g = () -> [Link]("Hello");
[Link]();
📦 Built-in Functional Interfaces (Very Important)
Interface Input Output Used in
Predicate 1️ boolean filter()
Function<T,R> 1️ result map()
Consumer 1️ void forEach()
Supplier 0 result get()
🟢 Easy Memory Trick
Predicate → condition
Function → convert
Consumer → use
Supplier → give
🔗 How Lambda & Functional Interface Work Together
[Link]()
.filter(n -> n > 1️0) // Predicate
.forEach([Link]::println); // Consumer
🎯 Functional Interface Interview One-Line
“A functional interface contains exactly one abstract method and is used as the
target type for lambda expressions.”
🟢 FINAL CLARITY (VERY IMPORTANT)
❌ Lambda is NOT independent
❌ Functional interface is NOT optional
✔ Lambda + Functional Interface always come together
📌 FINAL REVISION FORMULA
Anonymous Class → Problem
Lambda → Short Syntax
Functional Interface → Contract
Streams → Uses Lambda + FI
🌟 Anonymous Class vs Lambda – Complete Overview
Feature Anonymous Class Lambda Expression
A class with no name used for An anonymous function used to
Definition
one-time implementation implement a functional interface
Must have functional interface
Optional. Can be used without
Reference reference to be executed or
reference but cannot reuse
reused
Keyword new keyword required No new keyword
Syntax Verbose Short & concise
✅ Can be reused multiple times
Reuse Only if reference is stored
via reference
Target
Any interface or abstract class Functional interface only
Type
Java
Java 7+ Java 8+
Version
One-time object, quick Cleaner syntax, functional
Use Case
implementation programming, streams
🔹 Key Rules You Must Remember
1️. Anonymous class without reference → can call method once.
2. Lambda → must be assigned to functional interface reference to call
multiple times.
3️. Lambda cannot implement abstract class.
4️. Anonymous class can implement abstract class or interface.
5. Streams always use lambdas internally (functional style).
🔹 Simple Examples Side by Side
Anonymous Class (without reference)
new Runnable() {
@Override
public void run() {
[Link]("Hello from anonymous class");
}
}.run(); // ✅ Works once
Lambda Expression (with reference)
Runnable r = () -> [Link]("Hello from lambda");
[Link](); // ✅ Can reuse
[Link]();
🔹 Interview-Safe One-Liners
1️. “Anonymous class can work without a reference but cannot be reused.”
2. “Lambda expressions must be assigned to a functional interface and can
be reused multiple times.”
3️. “Anonymous class uses new keyword; lambda does not.”
4️. “Lambda can only implement functional interfaces; anonymous class can
implement abstract class or interface.”
🟢 Mental Model
Think of it like this:
Anonymous Class → old style → verbose, one-time use possible
Lambda → new style → functional, short, reusable with reference
Streams → use lambdas to process collections
🔁 Anonymous vs Lambda
✅ What is SAME (70%)
Both:
Implement one abstract method
Used for one-time logic
Mostly used with:
o Runnable
o Comparator
o ActionListener
Do not create reusable business logic
🟢 Anonymous Class (Java 7)
[Link](list, new Comparator<Employee>() {
@Override
public int compare(Employee e1️, Employee e2) {
return e1️.salary - [Link];
}
});
✂️ Lambda (Java 8)
[Link](list, (e1️, e2) -> e1️.salary - [Link]);
👉 Same logic, fewer lines
👉 That’s it. No magic.
❓ Then WHY did Java introduce Lambda?
Because anonymous classes caused problems:
❌ Problems with Anonymous
Too much boilerplate
Hard to read
Focus on HOW, not WHAT
Nested code becomes ugly
🆕 What Lambda Gave
Cleaner code
Functional style
Easier to read
Enables Streams API
🔑 Streams cannot exist without lambda
🟢 Best Interview Line (USE THIS)
“Lambda expressions are a compact replacement for anonymous classes used
with functional interfaces. They reduce boilerplate code but internally work the
same way.
🚀 Real-Time Usage.
Used mainly in:
Sorting
Filtering
Stream pipelines
Small utility logic
❌ Not for:
Core business logic
Large methods
Complex flows
You are NOT confused now
You just needed clear WHY comparison
🔹 1⃣ Predicate<T>
👉 Used for CONDITIONS (true / false)
Logic
Takes one input
Returns boolean
Used in filtering
Method
boolean test(T t);
Usage
filter()
Validation
Conditions
🟢 Memory: Predicate → Question? ✔ / ❌
🔹 2⃣ Function<T, R>
👉 Used for TRANSFORMATION
Logic
Takes one input
Returns one output
Method
R apply(T t);
Usage
map()
Conversions
Data transformation
🟢 Memory: Function → Input ➜ Output
🔹 3⃣ Consumer<T>
👉 Used for DOING ACTION (no return)
Logic
Takes one input
Returns nothing
Method
void accept(T t);
Usage
forEach()
Printing
Logging
🟢 Memory: Consumer → Consumes & finishes
🔹 4⃣ Supplier<T>
👉 Used for PROVIDING data
Logic
Takes no input
Returns output
Method
T get();
Usage
Object creation
Lazy values
Default values
🟢 Memory: Supplier → Gives data
Streams Method Functional Interface
filter() Predicate
map() Function
forEach() Consumer
generate() Supplier
🎯 Lines:
Predicate → Condition checking
Function → Data transformation
Consumer → Action without return
Supplier → Provides data
🔹 1⃣ BiPredicate<T, U>
👉 Condition with TWO inputs
Logic
Takes two inputs
Returns boolean
Used for checking conditions
Method
boolean test(T t, U u);
Real-Time Usage
Validation with two fields
Comparing two values
🟢 Memory: BiPredicate → 2 inputs → true/false
🔹 2⃣ BiFunction<T, U, R>
👉 Combine two inputs → produce result
Logic
Takes two inputs
Returns one result
Method
R apply(T t, U u);
Real-Time Usage
Calculations
Combining values
Mapping two fields to one
🟢 Memory: BiFunction → 2 inputs → 1 output
🔹 3⃣ BiConsumer<T, U>
👉 Perform action on two inputs (no return)
Logic
Takes two inputs
Returns nothing
Method
void accept(T t, U u);
Real-Time Usage
Printing
Logging
Map iteration
🟢 Memory: BiConsumer → 2 inputs → action
✅ Java Streams – Answers & Examples
🔹 Basic Level (1–15)
1. Create a stream from a list
List<Integer> list = [Link](1️,2,3️);
Stream<Integer> stream = [Link]();
2. Convert a stream back to a list
List<Integer> result = [Link]([Link]());
3. Count elements in a stream
long count = [Link]().count();
4. Filter even numbers
[Link]()
.filter(n -> n % 2 == 0)
.toList();
5. Convert strings to uppercase
[Link]()
.map(String::toUpperCase)
.toList();
6. Sort a list
[Link]().sorted().toList();
7. Limit first 5 elements
[Link]().limit(5).toList();
8. Skip first 3 elements
[Link]().skip(3️).toList();
9. Find first element
Optional<Integer> first = [Link]().findFirst();
10. Check if all match condition
boolean allEven = [Link]().allMatch(n -> n % 2 == 0);
11. Check if any match condition
boolean anyEven = [Link]().anyMatch(n -> n % 2 == 0);
12. Remove duplicates
[Link]().distinct().toList();
13. Collect into Set
Set<Integer> set = [Link]().collect([Link]());
14. Infinite stream of random numbers
[Link](Math::random).limit(5).toList();
15. Create stream from array
[Link](arr);
🔹 Intermediate Level
16. Sum of integers
int sum = [Link]().mapToInt(Integer::intValue).sum();
17. Max & Min
int max = [Link]().max(Integer::compare).get();
int min = [Link]().min(Integer::compare).get();
18. Average
double avg = [Link]().mapToInt(i -> i).average().getAsDouble();
19. Concatenate multiple lists
[Link](list1️.stream(), [Link]()).toList();
20. Group even & odd
Map<Boolean, List<Integer>> map =
[Link]().collect([Link](n -> n % 2 == 0));
21. Group employees by department
[Link]()
.collect([Link](Employee::getDept));
22. Second highest number
[Link]()
.distinct()
.sorted([Link]())
.skip(1️)
.findFirst();
23. Partition >10 and ≤10
[Link](n -> n > 1️0);
24. Word frequency
[Link]()
.collect([Link](w -> w, [Link]()));
25. Remove null values
[Link]().filter(Objects::nonNull).toList();
26. Concatenate strings
[Link]().collect([Link]());
27. Flatten list of lists
[Link]()
.flatMap(List::stream)
.toList();
28. Find duplicate elements
Set<Integer> seen = new HashSet<>();
[Link]().filter(n -> ).toList();
29. Top 3 highest numbers
[Link]()
.sorted([Link]())
.limit(3️)
.toList();
30. String → length map
[Link]()
.collect([Link](s -> s, String::length));
31. Longest word
[Link]()
.max([Link](String::length));
32. Distinct characters
[Link]()
.flatMap(s -> [Link]().mapToObj(c -> (char) c))
.distinct()
.toList();
33. Merge two maps
[Link]((k,v) -> map1️.merge(k, v, Integer::sum));
34. Parallel stream
[Link]().forEach([Link]::println);
35. Summary report
IntSummaryStatistics stats =
[Link]().mapToInt(i -> i).summaryStatistics();
🎯 Important
Streams are lazy
Intermediate ops → filter, map, sorted
Terminal ops → collect, forEach, reduce
Prefer method references when possible
Avoid modifying external variables in streams
🔹 Method Reference
A method reference is a shortcut for a lambda expression that calls an existing
method.
Syntax
ClassName::methodName
objectName::methodName
Example
[Link]([Link]::println);
✔️ Shorter
✔️ More readable
🔹 Types of Method Reference
1️⃣ Static Method Reference
Math::max
2⃣ Instance Method Reference
obj::methodName
3️⃣ Instance Method of Arbitrary Object
String::toUpperCase
🔹 Constructor Reference
A constructor reference is used to create objects using a constructor.
It is a special form of method reference.
Syntax
ClassName::new
Example
Supplier<List<String>> s = ArrayList::new;
List<String> list = [Link]();
Parameterized Constructor Example
Function<String, StringBuilder> f = StringBuilder::new;
StringBuilder sb = [Link]("Hello");
🔑 Difference (Easy Table)
Feature Method Reference Constructor Reference
Purpose Call existing method Create object
Symbol ::methodName ::new
Replaces Lambda calling method Lambda using new
🎯 Interview One-Line Answer
Method reference is a shorthand of lambda expression to call an existing
method, while constructor reference is used to create objects.
1️ abstract method → Lambda / Method Reference
2+ abstract methods → NOT allowed