Chapter 6: Functional Programming, Lambda Expressions & Stream API
Introduction
Java 8 introduced a major evolution in the Java programming language.
Before Java 8, developers primarily used:
- Classes
- Objects
- Loops
- Iterators
While these approaches remain important, modern enterprise applications increasingly leverage:
- Functional Programming
- Lambda Expressions
- Functional Interfaces
- Stream API
These features help developers write:
- Cleaner Code
- More Readable Code
- Less Boilerplate
- More Maintainable Applications
In this chapter, we will learn modern Java programming techniques and apply them to our Institute Placement Management System (IPMS).
What You Will Learn
By the end of this chapter, you will:
- Understand Functional Programming
- Learn Lambda Expressions
- Create Functional Interfaces
- Use Built-in Functional Interfaces
- Work with Method References
- Use Stream API
- Perform Filtering
- Perform Mapping
- Perform Sorting
- Perform Aggregations
- Process Collections Efficiently
- Build Modern IPMS Features
Understanding Functional Programming
Functional Programming focuses on:
- Functions
- Immutability
- Declarative Programming
Instead of:
for(int i=0;i<list.size();i++) {
}
we focus on:
students.stream()
Traditional Programming
List<String> names =
new ArrayList<>();
names.add("John Doe");
names.add("Sara Elise");
for(String name : names) {
System.out.println(name);
}
Functional Style
names.forEach(
name ->
System.out.println(name));
Benefits
- Less Code
- Better Readability
- Easier Maintenance
- Better Collection Processing
Functional Programming Overview

Lambda Expressions
A Lambda Expression is an anonymous function.
Traditional Approach
Runnable runnable =
new Runnable() {
@Override
public void run() {
System.out.println(
"Running");
}
};
Lambda Approach
Runnable runnable =
() ->
System.out.println(
"Running");
Lambda Syntax
(parameters) -> expression
Example
(name) ->
System.out.println(name);
No Parameter Lambda
() ->
System.out.println(
"Welcome");
Single Parameter Lambda
name ->
System.out.println(name);
Multiple Parameters
(a, b) ->
a + b
Lambda Returning Value
(a, b) ->
a + b
Example
Calculator calculator =
(a, b) -> a + b;
Functional Interfaces
A Functional Interface contains only one abstract method.
Example
@FunctionalInterface
public interface Calculator {
int add(
int a,
int b);
}
Lambda Implementation
Calculator calculator =
(a, b) -> a + b;
Calling
System.out.println(
calculator.add(10,20));
Output
30
Functional Interface Example
@FunctionalInterface
public interface Notification {
void send(
String message);
}
Implementation
Notification notification =
message ->
System.out.println(
message);
Using
notification.send(
"Placement Drive Created");
Built-in Functional Interfaces
Java provides several commonly used interfaces.
Package:
java.util.function
Common Interfaces
| Interface | Method |
|---|---|
| Predicate | test() |
| Function | apply() |
| Consumer | accept() |
| Supplier | get() |
Predicate
Used for filtering.
Predicate<Integer> eligible =
cgpa -> cgpa >= 7;
Example
System.out.println(
eligible.test(8));
Output
true
Function
Transforms data.
Function<String,Integer> length =
name -> name.length();
Example
System.out.println(
length.apply(
"John Doe"));
Consumer
Consumes data.
Consumer<String> display =
name ->
System.out.println(
name);
Example
display.accept(
"Sara Elise");
Supplier
Produces data.
Supplier<String> company =
() -> "Google";
Example
System.out.println(
company.get());
Method References
Method references provide cleaner syntax.
Lambda
names.forEach(
name ->
System.out.println(name));
Method Reference
names.forEach(
System.out::println);
Static Method Reference
ClassName::methodName
Instance Method Reference
object::methodName
Constructor Reference
Student::new
Introduction to Streams
Streams process collections efficiently.
Traditional Collection Processing
for(Student student
: students) {
if(student.getCgpa() >= 8) {
System.out.println(
student.getName());
}
}
Stream Approach
students.stream()
.filter(
student ->
student.getCgpa() >= 8)
.forEach(
student ->
System.out.println(
student.getName()));
Stream Architecture

Creating Streams
From Collection
students.stream();
From Array
Arrays.stream(numbers);
From Values
Stream.of(
1,2,3,4);
Filtering Data
students.stream()
.filter(
student ->
student.getCgpa() >= 8)
.forEach(
System.out::println);
Mapping Data
students.stream()
.map(
Student::getName)
.forEach(
System.out::println);
Example Output
John Doe
Sara Elise
Sorting Data
students.stream()
.sorted(
Comparator.comparing(
Student::getName))
.forEach(
System.out::println);
Reverse Sorting
students.stream()
.sorted(
Comparator.comparing(
Student::getCgpa)
.reversed())
.forEach(
System.out::println);
Limiting Records
students.stream()
.limit(5)
.forEach(
System.out::println);
Skipping Records
students.stream()
.skip(5)
.forEach(
System.out::println);
Collecting Results
List<Student> toppers =
students.stream()
.filter(
student ->
student.getCgpa() >= 8)
.collect(
Collectors.toList());
Counting Records
long count =
students.stream()
.count();
Finding First Record
Optional<Student> student =
students.stream()
.findFirst();
Finding Any Record
Optional<Student> student =
students.stream()
.findAny();
Matching Records
boolean result =
students.stream()
.allMatch(
student ->
student.getCgpa() >= 7);
anyMatch
boolean result =
students.stream()
.anyMatch(
student ->
student.getCgpa() >= 9);
noneMatch
boolean result =
students.stream()
.noneMatch(
student ->
student.getCgpa() < 0);
Aggregation
Sum
double total =
students.stream()
.mapToDouble(
Student::getCgpa)
.sum();
Average
double average =
students.stream()
.mapToDouble(
Student::getCgpa)
.average()
.orElse(0);
Maximum
double highest =
students.stream()
.mapToDouble(
Student::getCgpa)
.max()
.orElse(0);
Minimum
double lowest =
students.stream()
.mapToDouble(
Student::getCgpa)
.min()
.orElse(0);
Grouping Data
Map<String,List<Student>>
studentsByBranch =
students.stream()
.collect(
Collectors.groupingBy(
Student::getBranch));
Example
Map<String,List<Student>>
studentsByBranch =
students.stream()
.collect(
Collectors.groupingBy(
Student::getBranch));
Partitioning Data
Map<Boolean,List<Student>>
result =
students.stream()
.collect(
Collectors.partitioningBy(
student ->
student.getCgpa() >= 8));
Stream Pipeline
students.stream()
.filter(
student ->
student.getCgpa() >= 8)
.sorted(
Comparator.comparing(
Student::getName))
.map(
Student::getName)
.forEach(
System.out::println);
Parallel Streams
Used for large datasets.
students.parallelStream()
.forEach(
System.out::println);
Sequential Stream
students.stream()
.forEach(
System.out::println);
IPMS Student Example
List<Student> students =
new ArrayList<>();
students.add(
new Student(
101L,
"John Doe",
8.75));
students.add(
new Student(
102L,
"Sara Elise",
9.20));
Eligible Students
students.stream()
.filter(
student ->
student.getCgpa() >= 8)
.forEach(
System.out::println);
Placement Report
students.stream()
.sorted(
Comparator.comparing(
Student::getCgpa)
.reversed())
.forEach(
System.out::println);
IPMS Stream Processing

Mini Project
Build Student Analytics Module.
Requirements:
- Store Students
- Filter Eligible Students
- Sort by CGPA
- Generate Placement Reports
- Group by Branch
- Calculate Average CGPA
- Find Top Students
Best Practices
- Prefer Streams for Collection Processing
- Use Method References
- Keep Lambdas Small
- Avoid Side Effects
- Use Parallel Streams Carefully
- Use Functional Interfaces
Common Beginner Mistakes
| Mistake | Correct Approach |
|---|---|
| Complex Lambdas | Keep Lambdas Simple |
| Overusing Parallel Streams | Use Only When Necessary |
| Ignoring Optional | Handle Properly |
| Long Stream Pipelines | Break Into Steps |
| Using Streams Everywhere | Use Appropriate Approach |
Practice Exercises
- Create Calculator Functional Interface.
- Create Notification Functional Interface.
- Use Predicate for Student Filtering.
- Use Function for Name Transformation.
- Use Consumer for Display.
- Use Supplier for Company Data.
- Filter Students by CGPA.
- Sort Students by Name.
- Calculate Average CGPA.
- Generate Placement Analytics.
Chapter Summary
In this chapter, you learned:
- Functional Programming
- Lambda Expressions
- Functional Interfaces
- Predicate
- Function
- Consumer
- Supplier
- Method References
- Stream API
- Filtering
- Mapping
- Sorting
- Aggregations
- Parallel Streams
In the next chapter, we will learn:
- Multithreading
- Concurrent Programming
- Executor Framework
- Synchronization
These concepts help build scalable and high-performance enterprise applications.