The Java 8 Stream API is a powerful tool that lets developers process collections in a clean, functional way. This tutorial answers the most frequently asked Java 8 Stream API interview questions using real-world examples.
Before we proceed with the Java 8 stream API, let us first clarify the concept of a functional interface.
Table of Contents
✅ What is a Functional Interface?
A Functional Interface in Java is an interface with only one abstract method. It can have multiple default or static methods.
Example:
@FunctionalInterface
interface NameTransformer {
String transform(String name);
}
Using Functional Interface – 3 Ways
Using Concrete Class:
class MyNameTransformer implements NameTransformer {
@Override
public String transform(String string) {
return string.toUpperCase();
}
}
NameTransformer transformer = new MyNameTransformer();
System.out.println(transformer.transform("hello"));
// Output: HELLO
Using Anonymous Class:
NameTransformer transformer1 = new NameTransformer() {
@Override
public String transform(String name) {
return name.toUpperCase();
}
};
System.out.println(transformer1.transform("welcome to java anonymous class"));
// Output: WELCOME TO JAVA ANONYMOUS CLASS
Using Lambda Expression:
NameTransformer lambdaFunction = (str) -> {
return str.toUpperCase();
};
System.out.println(lambdaFunction.transform("using lambda"));
// Output: USING LAMBDA
NameTransformer lambdaFunction2 = (str) -> str.toUpperCase();
System.out.println(lambdaFunction2.transform("lambda single line code"));
// Output: LAMBDA SINGLE LINE CODE
📦 Java Predefined Functional Interfaces
Consumer<T> – takes an input, returns nothing
Consumer<String> consumer = string -> System.out.println(string);
consumer.accept("Hello");
// Output: Hello
Predicate<T> – takes input, returns boolean
Predicate<String> predicate = string -> string.length() > 5;
System.out.println(predicate.test("Hello")); // false
System.out.println(predicate.test("Hello Java")); // true
Function<T, R> – takes input, returns result
Function<String, Integer> function = string -> string.length();
System.out.println(function.apply("Hello")); // 5
System.out.println(function.apply("Hello World")); // 11
Supplier<T> – takes nothing, returns result
Supplier<Double> supplier = () -> Math.random() * 100;
System.out.println(supplier.get()); // random number
💼 Java 8 Stream API Real World Examples
Account class: Account.java
public class Account {
private String accountNumber;
private String accountHolderName;
private String branch;
private double balance;
public Account(String accountNumber, String accountHolderName, String branch, double balance) {
this.accountNumber = accountNumber;
this.accountHolderName = accountHolderName;
this.branch = branch;
this.balance = balance;
}
// Getters
public String getAccountNumber() { return accountNumber; }
public String getAccountHolderName() { return accountHolderName; }
public String getBranch() { return branch; }
public double getBalance() { return balance; }
@Override
public String toString() {
return "[" + accountNumber + ", " + accountHolderName + ", " + branch + ", " + balance + "]";
}
}
Sample data:
List<Account> accounts = List.of(
new Account("A101", "Alice", "Delhi", 2500),
new Account("A102", "Bob", "Delhi", 1800),
new Account("A103", "Charlie", "Mumbai", 3200),
new Account("A104", "David", "Chennai", 2100),
new Account("A105", "Eve", "Mumbai", 1500)
);
Now that we have a real-world Account object, let’s learn how to use Java 8 Stream API to solve common interview and production use-cases.
How to extract first 3 account numbers?
List<String> accountNumbers = accounts.stream()
.limit(3)
.map(account -> account.getAccountNumber())
.toList();
System.out.println(accountNumbers);
[A101, A102, A103]
How to extract account holder names in uppercase?
List<String> names = accounts.stream()
.map(Account::getAccountHolderName)
.map(String::toUpperCase)
.toList();
System.out.println(names);
[ALICE, BOB, CHARLIE, DAVID, EVE]
How to filter accounts with balance > 2000?
List<Account> highBalance = accounts.stream()
.filter(account -> account.getBalance() > 2000)
.toList();
System.out.println(highBalance);
[[A101, Alice, Delhi, 2500.0], [A103, Charlie, Mumbai, 3200.0], [A104, David, Chennai, 2100.0]]
Get account numbers where balance > 2000?
List<String> highBalAccountNums = highBalance.stream()
.map(Account::getAccountNumber)
.toList();
System.out.println(highBalAccountNums);
[A101, A103, A104]
Get balances in ascending order
List<Double> sortedAsc = accounts.stream()
.map(Account::getBalance)
.sorted()
.toList();
System.out.println(sortedAsc);
[1500.0, 1800.0, 2100.0, 2500.0, 3200.0]
Get balances in descending order
List<Double> sortedDesc = accounts.stream()
.map(Account::getBalance)
.sorted((a, b) -> Double.compare(b, a))
.toList();
System.out.println(sortedDesc);
[3200.0, 2500.0, 2100.0, 1800.0, 1500.0]
[A101, A103, A104]
Convert list to map with account number as key
Map<String, Account> accountMap = accounts.stream()
.collect(Collectors.toMap(Account::getAccountNumber, acc -> acc));
System.out.println(accountMap);
{A101=[A101, Alice, Delhi, 2500.0], A102=[A102, Bob, Delhi, 1800.0], A103=[A103, Charlie, Mumbai, 3200.0], A104=[A104, David, Chennai, 2100.0], A105=[A105, Eve, Mumbai, 1500.0]}
Convert list to map with account number and balance
Map<String, Double> balanceMap = accounts.stream()
.collect(Collectors.toMap(Account::getAccountNumber, Account::getBalance));
System.out.println(balanceMap);
{A101=2500.0, A102=1800.0, A103=3200.0, A104=2100.0, A105=1500.0}
Calculate sum of all balances
double total = accounts.stream()
.mapToDouble(Account::getBalance)
.sum();
System.out.println(total);
11100.0
Calculate average of all balances
double avg = accounts.stream()
.mapToDouble(Account::getBalance)
.average().orElse(0.0);
System.out.println(avg);
2220.0
Group accounts by branch and get total balance
Map<String, Double> branchWiseTotal = accounts.stream()
.collect(Collectors.groupingBy(Account::getBranch, Collectors.summingDouble(Account::getBalance)));
System.out.println(branchWiseTotal);
{Delhi=4300.0, Mumbai=4700.0, Chennai=2100.0}
Group accounts by branch and count
Map<String, Long> branchCount = accounts.stream()
.collect(Collectors.groupingBy(Account::getBranch, Collectors.counting()));
System.out.println(branchCount);
{Delhi=2, Mumbai=2, Chennai=1}
Group accounts by branch and calculate average balance
Map<String, Double> branchAverage = accounts.stream()
.collect(Collectors.groupingBy(Account::getBranch, Collectors.averagingDouble(Account::getBalance)));
System.out.println(branchAverage);
{Delhi=2150.0, Mumbai=2350.0, Chennai=2100.0}
🔚 Summary
The Java 8 Stream API enables developers to work with collections more efficiently using a functional approach. In this article, we covered essential Java 8 Stream API concepts and provided real examples frequently asked in interviews. Learn how to use methods like map(), filter(), and groupingBy() with the Java 8 Stream API and become interview-ready.
This guide covered everything from functional interfaces to real-world Stream API examples that appear in interviews.
For deeper understanding, you can also explore:
💬 If you have any questions or need help with a specific example, feel free to ask in the comments below!
Leave a Reply