Master the Java 8 Stream API – Interview Booster with Real Examples & Expert Tips

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.

✅ What is a Functional Interface?

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!