Master Java Streams API with 100+ Problems & Solutions
- Stream Basics (Warm-up)
- Mapping & Transformation
- Filtering & Matching
- Reduction & Aggregation
- Grouping & Partitioning
- Collectors Deep Practice
- Advanced Interview Level Problems
- Streams with Objects
- Parallel Streams
- Tricky Conceptual Questions
- 15 MUST-DO Interview Problems
stream()- Create a stream from collectionfilter()- Filter elements based on predicatemap()- Transform elementsdistinct()- Remove duplicatescount()- Count elementssorted()- Sort elementscollect()- Collect results
import java.util.*;
import java.util.stream.*;
public class StreamBasics {
// Filter even numbers from a list
public static List<Integer> filterEvenNumbers(List<Integer> numbers) {
return numbers.stream()
.filter(n -> n % 2 == 0)
.collect(Collectors.toList());
}
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
System.out.println("Even numbers: " + filterEvenNumbers(numbers));
// Output: [2, 4, 6, 8, 10]
}
}public static List<String> convertToUppercase(List<String> strings) {
return strings.stream()
.map(String::toUpperCase)
.collect(Collectors.toList());
}
// Example usage
List<String> words = Arrays.asList("java", "python", "javascript");
System.out.println(convertToUppercase(words));
// Output: [JAVA, PYTHON, JAVASCRIPT]public static List<Integer> findSquares(List<Integer> numbers) {
return numbers.stream()
.map(n -> n * n)
.collect(Collectors.toList());
}
// Example usage
List<Integer> nums = Arrays.asList(1, 2, 3, 4, 5);
System.out.println(findSquares(nums));
// Output: [1, 4, 9, 16, 25]public static List<Integer> removeDuplicates(List<Integer> numbers) {
return numbers.stream()
.distinct()
.collect(Collectors.toList());
}
// Example usage
List<Integer> nums = Arrays.asList(1, 2, 2, 3, 4, 4, 5);
System.out.println(removeDuplicates(nums));
// Output: [1, 2, 3, 4, 5]public static long countGreaterThan(List<Integer> numbers, int threshold) {
return numbers.stream()
.filter(n -> n > threshold)
.count();
}
// Example usage
List<Integer> nums = Arrays.asList(1, 5, 10, 15, 20, 25);
System.out.println("Count > 10: " + countGreaterThan(nums, 10));
// Output: 3// Ascending order
public static List<Integer> sortAscending(List<Integer> numbers) {
return numbers.stream()
.sorted()
.collect(Collectors.toList());
}
// Descending order
public static List<Integer> sortDescending(List<Integer> numbers) {
return numbers.stream()
.sorted(Comparator.reverseOrder())
.collect(Collectors.toList());
}
// Example usage
List<Integer> nums = Arrays.asList(5, 2, 8, 1, 9);
System.out.println("Ascending: " + sortAscending(nums));
System.out.println("Descending: " + sortDescending(nums));
// Output:
// Ascending: [1, 2, 5, 8, 9]
// Descending: [9, 8, 5, 2, 1]map()- One-to-one transformationflatMap()- One-to-many transformation (flattening)Collectors.joining()- Join stringsCollectors.toSet()- Collect to Set
public static List<Integer> getStringLengths(List<String> strings) {
return strings.stream()
.map(String::length)
.collect(Collectors.toList());
}
// Example usage
List<String> words = Arrays.asList("Java", "Streams", "API");
System.out.println(getStringLengths(words));
// Output: [4, 7, 3]class Person {
String name;
int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() { return name; }
public int getAge() { return age; }
}
public static List<String> extractNames(List<Person> persons) {
return persons.stream()
.map(Person::getName)
.collect(Collectors.toList());
}
// Example usage
List<Person> people = Arrays.asList(
new Person("Alice", 25),
new Person("Bob", 30),
new Person("Charlie", 35)
);
System.out.println(extractNames(people));
// Output: [Alice, Bob, Charlie]public static List<Integer> flattenList(List<List<Integer>> nestedList) {
return nestedList.stream()
.flatMap(List::stream)
.collect(Collectors.toList());
}
// Example usage
List<List<Integer>> nested = Arrays.asList(
Arrays.asList(1, 2, 3),
Arrays.asList(4, 5),
Arrays.asList(6, 7, 8, 9)
);
System.out.println(flattenList(nested));
// Output: [1, 2, 3, 4, 5, 6, 7, 8, 9]public static String toCommaSeparatedString(List<String> strings) {
return strings.stream()
.collect(Collectors.joining(", "));
}
// Example usage
List<String> fruits = Arrays.asList("Apple", "Banana", "Orange");
System.out.println(toCommaSeparatedString(fruits));
// Output: Apple, Banana, Orangepublic static Set<Integer> listToSet(List<Integer> numbers) {
return numbers.stream()
.collect(Collectors.toSet());
}
// Example usage
List<Integer> nums = Arrays.asList(1, 2, 2, 3, 4, 4, 5);
System.out.println(listToSet(nums));
// Output: [1, 2, 3, 4, 5] (order may vary)allMatch()- Check if all elements match predicateanyMatch()- Check if any element matchesnoneMatch()- Check if no element matchesfindFirst()- Get first elementfindAny()- Get any elementOptional- Handle potential absence of values
public static boolean areAllPositive(List<Integer> numbers) {
return numbers.stream()
.allMatch(n -> n > 0);
}
// Example usage
List<Integer> nums1 = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> nums2 = Arrays.asList(1, -2, 3, 4, 5);
System.out.println("All positive (nums1): " + areAllPositive(nums1)); // true
System.out.println("All positive (nums2): " + areAllPositive(nums2)); // falsepublic static boolean anyStartsWithA(List<String> strings) {
return strings.stream()
.anyMatch(s -> s.startsWith("A"));
}
// Example usage
List<String> words = Arrays.asList("Apple", "Banana", "Cherry");
System.out.println("Any starts with A: " + anyStartsWithA(words));
// Output: truepublic static Optional<Integer> findFirstGreaterThan50(List<Integer> numbers) {
return numbers.stream()
.filter(n -> n > 50)
.findFirst();
}
// Example usage
List<Integer> nums = Arrays.asList(10, 20, 60, 30, 70);
Optional<Integer> result = findFirstGreaterThan50(nums);
result.ifPresent(n -> System.out.println("First > 50: " + n));
// Output: First > 50: 60public static Optional<Integer> findAnyDivisibleBy3(List<Integer> numbers) {
return numbers.stream()
.filter(n -> n % 3 == 0)
.findAny();
}
// Example usage
List<Integer> nums = Arrays.asList(10, 15, 20, 30);
Optional<Integer> result = findAnyDivisibleBy3(nums);
result.ifPresent(n -> System.out.println("Divisible by 3: " + n));
// Output: Divisible by 3: 15 (or 30)class Employee {
String name;
double salary;
public Employee(String name, double salary) {
this.name = name;
this.salary = salary;
}
public String getName() { return name; }
public double getSalary() { return salary; }
}
public static List<Employee> filterHighEarners(List<Employee> employees) {
return employees.stream()
.filter(e -> e.getSalary() > 50000)
.collect(Collectors.toList());
}
// Example usage
List<Employee> employees = Arrays.asList(
new Employee("Alice", 60000),
new Employee("Bob", 45000),
new Employee("Charlie", 75000)
);
List<Employee> highEarners = filterHighEarners(employees);
highEarners.forEach(e -> System.out.println(e.getName() + ": $" + e.getSalary()));
// Output:
// Alice: $60000.0
// Charlie: $75000.0reduce()- Reduce stream to single valuemax()/min()- Find maximum/minimumCollectors.summarizingInt()- Get statisticsCollectors.groupingBy()- Group elementsCollectors.counting()- Count elements in groups
// Using reduce
public static int findSum(List<Integer> numbers) {
return numbers.stream()
.reduce(0, Integer::sum);
}
// Using sum() with mapToInt
public static int findSumAlternative(List<Integer> numbers) {
return numbers.stream()
.mapToInt(Integer::intValue)
.sum();
}
// Example usage
List<Integer> nums = Arrays.asList(1, 2, 3, 4, 5);
System.out.println("Sum: " + findSum(nums));
// Output: Sum: 15public static Optional<Integer> findMax(List<Integer> numbers) {
return numbers.stream()
.max(Integer::compareTo);
}
public static Optional<Integer> findMin(List<Integer> numbers) {
return numbers.stream()
.min(Integer::compareTo);
}
// Example usage
List<Integer> nums = Arrays.asList(5, 2, 8, 1, 9);
findMax(nums).ifPresent(max -> System.out.println("Max: " + max));
findMin(nums).ifPresent(min -> System.out.println("Min: " + min));
// Output:
// Max: 9
// Min: 1public static Optional<Integer> findSecondHighest(List<Integer> numbers) {
return numbers.stream()
.distinct()
.sorted(Comparator.reverseOrder())
.skip(1)
.findFirst();
}
// Example usage
List<Integer> nums = Arrays.asList(5, 2, 8, 1, 9, 8);
findSecondHighest(nums).ifPresent(n -> System.out.println("Second highest: " + n));
// Output: Second highest: 8public static OptionalDouble calculateAverage(List<Integer> numbers) {
return numbers.stream()
.mapToInt(Integer::intValue)
.average();
}
// Example usage
List<Integer> nums = Arrays.asList(10, 20, 30, 40, 50);
calculateAverage(nums).ifPresent(avg -> System.out.println("Average: " + avg));
// Output: Average: 30.0public static Map<Integer, Long> countFrequency(List<Integer> numbers) {
return numbers.stream()
.collect(Collectors.groupingBy(
n -> n,
Collectors.counting()
));
}
// Example usage
List<Integer> nums = Arrays.asList(1, 2, 2, 3, 3, 3, 4, 4, 4, 4);
System.out.println(countFrequency(nums));
// Output: {1=1, 2=2, 3=3, 4=4}public static IntSummaryStatistics getStatistics(List<Integer> numbers) {
return numbers.stream()
.collect(Collectors.summarizingInt(Integer::intValue));
}
// Example usage
List<Integer> nums = Arrays.asList(1, 2, 3, 4, 5);
IntSummaryStatistics stats = getStatistics(nums);
System.out.println("Count: " + stats.getCount());
System.out.println("Sum: " + stats.getSum());
System.out.println("Average: " + stats.getAverage());
System.out.println("Min: " + stats.getMin());
System.out.println("Max: " + stats.getMax());Collectors.groupingBy()- Group elements by classifierCollectors.partitioningBy()- Partition into two groups- Downstream collectors - Additional operations on grouped data
class Employee {
String name;
String department;
double salary;
public Employee(String name, String department, double salary) {
this.name = name;
this.department = department;
this.salary = salary;
}
public String getName() { return name; }
public String getDepartment() { return department; }
public double getSalary() { return salary; }
}
public static Map<String, List<Employee>> groupByDepartment(List<Employee> employees) {
return employees.stream()
.collect(Collectors.groupingBy(Employee::getDepartment));
}
// Example usage
List<Employee> employees = Arrays.asList(
new Employee("Alice", "IT", 60000),
new Employee("Bob", "HR", 50000),
new Employee("Charlie", "IT", 70000),
new Employee("David", "HR", 55000)
);
Map<String, List<Employee>> grouped = groupByDepartment(employees);
grouped.forEach((dept, empList) -> {
System.out.println(dept + ": " + empList.size() + " employees");
});
// Output:
// IT: 2 employees
// HR: 2 employeespublic static Map<Boolean, List<Integer>> groupByEvenOdd(List<Integer> numbers) {
return numbers.stream()
.collect(Collectors.partitioningBy(n -> n % 2 == 0));
}
// Example usage
List<Integer> nums = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Map<Boolean, List<Integer>> grouped = groupByEvenOdd(nums);
System.out.println("Even: " + grouped.get(true));
System.out.println("Odd: " + grouped.get(false));
// Output:
// Even: [2, 4, 6, 8, 10]
// Odd: [1, 3, 5, 7, 9]public static boolean isPrime(int n) {
if (n <= 1) return false;
for (int i = 2; i <= Math.sqrt(n); i++) {
if (n % i == 0) return false;
}
return true;
}
public static Map<Boolean, List<Integer>> partitionPrimes(List<Integer> numbers) {
return numbers.stream()
.collect(Collectors.partitioningBy(StreamProblems::isPrime));
}
// Example usage
List<Integer> nums = Arrays.asList(2, 3, 4, 5, 6, 7, 8, 9, 10, 11);
Map<Boolean, List<Integer>> partitioned = partitionPrimes(nums);
System.out.println("Primes: " + partitioned.get(true));
System.out.println("Non-primes: " + partitioned.get(false));
// Output:
// Primes: [2, 3, 5, 7, 11]
// Non-primes: [4, 6, 8, 9, 10]public static Map<String, Long> countEmployeesPerDepartment(List<Employee> employees) {
return employees.stream()
.collect(Collectors.groupingBy(
Employee::getDepartment,
Collectors.counting()
));
}
// Example usage
List<Employee> employees = Arrays.asList(
new Employee("Alice", "IT", 60000),
new Employee("Bob", "HR", 50000),
new Employee("Charlie", "IT", 70000),
new Employee("David", "Finance", 65000)
);
System.out.println(countEmployeesPerDepartment(employees));
// Output: {IT=2, HR=1, Finance=1}public static Map<String, Optional<Employee>> highestSalaryPerDept(List<Employee> employees) {
return employees.stream()
.collect(Collectors.groupingBy(
Employee::getDepartment,
Collectors.maxBy(Comparator.comparingDouble(Employee::getSalary))
));
}
// Alternative: Get just the salary value
public static Map<String, Double> maxSalaryPerDept(List<Employee> employees) {
return employees.stream()
.collect(Collectors.groupingBy(
Employee::getDepartment,
Collectors.collectingAndThen(
Collectors.maxBy(Comparator.comparingDouble(Employee::getSalary)),
emp -> emp.map(Employee::getSalary).orElse(0.0)
)
));
}
// Example usage
List<Employee> employees = Arrays.asList(
new Employee("Alice", "IT", 60000),
new Employee("Bob", "HR", 50000),
new Employee("Charlie", "IT", 70000),
new Employee("David", "HR", 55000)
);
System.out.println(maxSalaryPerDept(employees));
// Output: {IT=70000.0, HR=55000.0}class Employee {
String name;
String department;
String role;
double salary;
public Employee(String name, String department, String role, double salary) {
this.name = name;
this.department = department;
this.role = role;
this.salary = salary;
}
public String getName() { return name; }
public String getDepartment() { return department; }
public String getRole() { return role; }
public double getSalary() { return salary; }
}
public static Map<String, Map<String, List<Employee>>> multiLevelGrouping(List<Employee> employees) {
return employees.stream()
.collect(Collectors.groupingBy(
Employee::getDepartment,
Collectors.groupingBy(Employee::getRole)
));
}
// Example usage
List<Employee> employees = Arrays.asList(
new Employee("Alice", "IT", "Developer", 60000),
new Employee("Bob", "IT", "Manager", 80000),
new Employee("Charlie", "HR", "Recruiter", 50000),
new Employee("David", "IT", "Developer", 65000)
);
Map<String, Map<String, List<Employee>>> grouped = multiLevelGrouping(employees);
System.out.println("IT Developers: " + grouped.get("IT").get("Developer").size());
// Output: IT Developers: 2Collectors.toMap()- Collect to Map- Merge functions for duplicate keys
Collectors.toUnmodifiableList()- Create immutable collections- Custom collectors
class Product {
int id;
String name;
double price;
public Product(int id, String name, double price) {
this.id = id;
this.name = name;
this.price = price;
}
public int getId() { return id; }
public String getName() { return name; }
public double getPrice() { return price; }
}
public static Map<Integer, Product> listToMap(List<Product> products) {
return products.stream()
.collect(Collectors.toMap(
Product::getId,
product -> product
));
}
// Example usage
List<Product> products = Arrays.asList(
new Product(1, "Laptop", 999.99),
new Product(2, "Mouse", 29.99),
new Product(3, "Keyboard", 79.99)
);
Map<Integer, Product> productMap = listToMap(products);
System.out.println("Product 2: " + productMap.get(2).getName());
// Output: Product 2: Mousepublic static Map<String, Integer> listToMapWithDuplicates(List<String> words) {
return words.stream()
.collect(Collectors.toMap(
word -> word,
String::length,
(existing, replacement) -> existing // Keep existing value
));
}
// Example usage
List<String> words = Arrays.asList("apple", "banana", "apple", "cherry");
System.out.println(listToMapWithDuplicates(words));
// Output: {banana=6, apple=5, cherry=6}public static List<String> createUnmodifiableList(List<String> source) {
return source.stream()
.collect(Collectors.toUnmodifiableList());
}
// Example usage
List<String> words = Arrays.asList("Java", "Python", "JavaScript");
List<String> immutable = createUnmodifiableList(words);
// immutable.add("C++"); // This would throw UnsupportedOperationExceptionpublic static Map<String, Integer> createLinkedHashMap(List<String> words) {
return words.stream()
.collect(Collectors.toMap(
word -> word,
String::length,
(v1, v2) -> v1,
LinkedHashMap::new // Maintain insertion order
));
}
// Example usage
List<String> words = Arrays.asList("zebra", "apple", "mango");
System.out.println(createLinkedHashMap(words));
// Output: {zebra=5, apple=5, mango=5} (maintains order)// Using reduce - returns Optional
public static Optional<String> concatenateWithReduce(List<String> strings) {
return strings.stream()
.reduce((s1, s2) -> s1 + s2);
}
// Using collect - returns concrete result
public static String concatenateWithCollect(List<String> strings) {
return strings.stream()
.collect(Collectors.joining());
}
// Example usage
List<String> words = Arrays.asList("Hello", " ", "World");
System.out.println("Reduce: " + concatenateWithReduce(words).orElse(""));
System.out.println("Collect: " + concatenateWithCollect(words));
// Both output: Hello Worldpublic static Optional<String> findLongestString(List<String> strings) {
return strings.stream()
.max(Comparator.comparingInt(String::length));
}
// Example usage
List<String> words = Arrays.asList("Java", "JavaScript", "Python", "C");
findLongestString(words).ifPresent(s -> System.out.println("Longest: " + s));
// Output: Longest: JavaScriptpublic static Optional<Character> firstNonRepeatedChar(String str) {
return str.chars()
.mapToObj(c -> (char) c)
.collect(Collectors.groupingBy(c -> c, LinkedHashMap::new, Collectors.counting()))
.entrySet()
.stream()
.filter(entry -> entry.getValue() == 1)
.map(Map.Entry::getKey)
.findFirst();
}
// Example usage
String text = "programming";
firstNonRepeatedChar(text).ifPresent(c -> System.out.println("First non-repeated: " + c));
// Output: First non-repeated: ppublic static List<Integer> findDuplicates(List<Integer> numbers) {
return numbers.stream()
.collect(Collectors.groupingBy(n -> n, Collectors.counting()))
.entrySet()
.stream()
.filter(entry -> entry.getValue() > 1)
.map(Map.Entry::getKey)
.collect(Collectors.toList());
}
// Alternative using Set
public static Set<Integer> findDuplicatesWithSet(List<Integer> numbers) {
Set<Integer> seen = new HashSet<>();
return numbers.stream()
.filter(n -> !seen.add(n))
.collect(Collectors.toSet());
}
// Example usage
List<Integer> nums = Arrays.asList(1, 2, 3, 2, 4, 5, 3, 6);
System.out.println("Duplicates: " + findDuplicates(nums));
// Output: Duplicates: [2, 3]public static Optional<Integer> findKthLargest(List<Integer> numbers, int k) {
return numbers.stream()
.distinct()
.sorted(Comparator.reverseOrder())
.skip(k - 1)
.findFirst();
}
// Example usage
List<Integer> nums = Arrays.asList(5, 2, 8, 1, 9, 3);
findKthLargest(nums, 2).ifPresent(n -> System.out.println("2nd largest: " + n));
// Output: 2nd largest: 8public static List<Integer> mergeLists(List<Integer> list1, List<Integer> list2) {
return Stream.concat(list1.stream(), list2.stream())
.distinct()
.sorted()
.collect(Collectors.toList());
}
// Example usage
List<Integer> list1 = Arrays.asList(1, 2, 3, 4);
List<Integer> list2 = Arrays.asList(3, 4, 5, 6);
System.out.println(mergeLists(list1, list2));
// Output: [1, 2, 3, 4, 5, 6]public static Map<String, Long> wordFrequency(String paragraph) {
return Arrays.stream(paragraph.toLowerCase().split("\\s+"))
.collect(Collectors.groupingBy(
word -> word,
Collectors.counting()
));
}
// Example usage
String text = "Java streams are powerful Java streams are elegant";
System.out.println(wordFrequency(text));
// Output: {java=2, streams=2, are=2, powerful=1, elegant=1}public static boolean areAnagrams(String str1, String str2) {
String sorted1 = str1.chars()
.sorted()
.collect(StringBuilder::new,
StringBuilder::appendCodePoint,
StringBuilder::append)
.toString();
String sorted2 = str2.chars()
.sorted()
.collect(StringBuilder::new,
StringBuilder::appendCodePoint,
StringBuilder::append)
.toString();
return sorted1.equals(sorted2);
}
// Example usage
System.out.println(areAnagrams("listen", "silent")); // true
System.out.println(areAnagrams("hello", "world")); // falsepublic static List<Employee> findTop3HighestPaid(List<Employee> employees) {
return employees.stream()
.sorted(Comparator.comparingDouble(Employee::getSalary).reversed())
.limit(3)
.collect(Collectors.toList());
}
// Example usage
List<Employee> employees = Arrays.asList(
new Employee("Alice", "IT", 60000),
new Employee("Bob", "HR", 50000),
new Employee("Charlie", "IT", 70000),
new Employee("David", "Finance", 80000),
new Employee("Eve", "IT", 65000)
);
findTop3HighestPaid(employees).forEach(e ->
System.out.println(e.getName() + ": $" + e.getSalary())
);
// Output:
// David: $80000.0
// Charlie: $70000.0
// Eve: $65000.0class Employee {
private int id;
private String name;
private String department;
private double salary;
private int age;
public Employee(int id, String name, String department, double salary, int age) {
this.id = id;
this.name = name;
this.department = department;
this.salary = salary;
this.age = age;
}
// Getters and Setters
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getDepartment() { return department; }
public void setDepartment(String department) { this.department = department; }
public double getSalary() { return salary; }
public void setSalary(double salary) { this.salary = salary; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
@Override
public String toString() {
return "Employee{id=" + id + ", name='" + name + "', dept='" +
department + "', salary=" + salary + ", age=" + age + "}";
}
}public static List<Employee> sortBySalary(List<Employee> employees) {
return employees.stream()
.sorted(Comparator.comparingDouble(Employee::getSalary))
.collect(Collectors.toList());
}
// Descending order
public static List<Employee> sortBySalaryDescending(List<Employee> employees) {
return employees.stream()
.sorted(Comparator.comparingDouble(Employee::getSalary).reversed())
.collect(Collectors.toList());
}public static Optional<Employee> findYoungestEmployee(List<Employee> employees) {
return employees.stream()
.min(Comparator.comparingInt(Employee::getAge));
}
// Example usage
List<Employee> employees = Arrays.asList(
new Employee(1, "Alice", "IT", 60000, 30),
new Employee(2, "Bob", "HR", 50000, 25),
new Employee(3, "Charlie", "IT", 70000, 35)
);
findYoungestEmployee(employees).ifPresent(e ->
System.out.println("Youngest: " + e.getName() + " (" + e.getAge() + ")")
);
// Output: Youngest: Bob (25)public static Map<String, Double> averageSalaryByDept(List<Employee> employees) {
return employees.stream()
.collect(Collectors.groupingBy(
Employee::getDepartment,
Collectors.averagingDouble(Employee::getSalary)
));
}
// Example usage
List<Employee> employees = Arrays.asList(
new Employee(1, "Alice", "IT", 60000, 30),
new Employee(2, "Bob", "HR", 50000, 25),
new Employee(3, "Charlie", "IT", 70000, 35),
new Employee(4, "David", "HR", 55000, 28)
);
System.out.println(averageSalaryByDept(employees));
// Output: {IT=65000.0, HR=52500.0}public static List<String> getNamesSortedByAge(List<Employee> employees) {
return employees.stream()
.sorted(Comparator.comparingInt(Employee::getAge))
.map(Employee::getName)
.collect(Collectors.toList());
}
// Example usage
System.out.println(getNamesSortedByAge(employees));
// Output: [Bob, Alice, David, Charlie]public static Optional<Map.Entry<String, Double>> deptWithHighestTotalSalary(List<Employee> employees) {
return employees.stream()
.collect(Collectors.groupingBy(
Employee::getDepartment,
Collectors.summingDouble(Employee::getSalary)
))
.entrySet()
.stream()
.max(Map.Entry.comparingByValue());
}
// Example usage
deptWithHighestTotalSalary(employees).ifPresent(entry ->
System.out.println("Department: " + entry.getKey() + ", Total: $" + entry.getValue())
);
// Output: Department: IT, Total: $130000.0public static List<Employee> increaseSalaryBy10Percent(List<Employee> employees) {
return employees.stream()
.map(emp -> {
Employee newEmp = new Employee(
emp.getId(),
emp.getName(),
emp.getDepartment(),
emp.getSalary() * 1.10,
emp.getAge()
);
return newEmp;
})
.collect(Collectors.toList());
}
// Or modify in place (if mutable)
public static void increaseSalaryBy10PercentInPlace(List<Employee> employees) {
employees.forEach(emp -> emp.setSalary(emp.getSalary() * 1.10));
}parallelStream()- Create parallel stream- Performance considerations
- Thread safety concerns
public static long sumParallel(List<Integer> numbers) {
return numbers.parallelStream()
.mapToLong(Integer::longValue)
.sum();
}
// Example usage
List<Integer> largeList = IntStream.rangeClosed(1, 1000000)
.boxed()
.collect(Collectors.toList());
long start = System.currentTimeMillis();
long sum = sumParallel(largeList);
long end = System.currentTimeMillis();
System.out.println("Sum: " + sum + ", Time: " + (end - start) + "ms");public class ParallelStreamPerformance {
public static long sequentialProcessing(List<Integer> numbers) {
long start = System.currentTimeMillis();
long sum = numbers.stream()
.mapToLong(n -> {
// Simulate some work
return (long) Math.sqrt(n);
})
.sum();
long end = System.currentTimeMillis();
System.out.println("Sequential time: " + (end - start) + "ms");
return sum;
}
public static long parallelProcessing(List<Integer> numbers) {
long start = System.currentTimeMillis();
long sum = numbers.parallelStream()
.mapToLong(n -> {
// Simulate some work
return (long) Math.sqrt(n);
})
.sum();
long end = System.currentTimeMillis();
System.out.println("Parallel time: " + (end - start) + "ms");
return sum;
}
public static void main(String[] args) {
List<Integer> numbers = IntStream.rangeClosed(1, 1000000)
.boxed()
.collect(Collectors.toList());
sequentialProcessing(numbers);
parallelProcessing(numbers);
}
}// ❌ BAD: Small datasets
List<Integer> smallList = Arrays.asList(1, 2, 3, 4, 5);
smallList.parallelStream().forEach(System.out::println); // Overhead > benefit
// ❌ BAD: Operations that must be ordered
List<String> words = Arrays.asList("a", "b", "c");
words.parallelStream().forEachOrdered(System.out::println); // Defeats purpose
// ❌ BAD: Stateful operations with shared mutable state
List<Integer> results = new ArrayList<>(); // NOT thread-safe
numbers.parallelStream()
.forEach(n -> results.add(n * 2)); // Race condition!
// ✅ GOOD: Use thread-safe collection
List<Integer> results = new ConcurrentLinkedQueue<>();
numbers.parallelStream()
.forEach(n -> results.add(n * 2));
// ✅ BETTER: Use collect
List<Integer> results = numbers.parallelStream()
.map(n -> n * 2)
.collect(Collectors.toList());// map() - One-to-one transformation
List<String> words = Arrays.asList("Hello", "World");
List<Integer> lengths = words.stream()
.map(String::length)
.collect(Collectors.toList());
// Result: [5, 5]
// flatMap() - One-to-many transformation (flattening)
List<String> sentences = Arrays.asList("Hello World", "Java Streams");
List<String> allWords = sentences.stream()
.flatMap(sentence -> Arrays.stream(sentence.split(" ")))
.collect(Collectors.toList());
// Result: [Hello, World, Java, Streams]
// Another example: Nested lists
List<List<Integer>> nested = Arrays.asList(
Arrays.asList(1, 2),
Arrays.asList(3, 4),
Arrays.asList(5, 6)
);
// Using map - returns Stream<List<Integer>>
List<List<Integer>> withMap = nested.stream()
.map(list -> list)
.collect(Collectors.toList());
// Result: [[1, 2], [3, 4], [5, 6]]
// Using flatMap - returns Stream<Integer>
List<Integer> withFlatMap = nested.stream()
.flatMap(List::stream)
.collect(Collectors.toList());
// Result: [1, 2, 3, 4, 5, 6]// reduce() - Combines elements to produce single result (Optional or value)
// Immutability focused, returns Optional for empty streams
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> sum = numbers.stream()
.reduce((a, b) -> a + b);
// OR
int sum = numbers.stream()
.reduce(0, (a, b) -> a + b);
// collect() - Mutable reduction, accumulates into container
// More flexible, can create any collection type
List<Integer> evenNumbers = numbers.stream()
.filter(n -> n % 2 == 0)
.collect(Collectors.toList());
// Key differences:
// 1. reduce() creates new value each time (immutable)
// 2. collect() modifies existing container (mutable)
// 3. collect() is better for building collections
// 4. reduce() is better for combining values// ❌ This will throw IllegalStateException
Stream<String> stream = Arrays.asList("a", "b", "c").stream();
stream.forEach(System.out::println);
stream.forEach(System.out::println); // IllegalStateException: stream has already been operated upon
// ✅ Solution: Create new stream each time
List<String> list = Arrays.asList("a", "b", "c");
list.stream().forEach(System.out::println);
list.stream().forEach(System.out::println); // Works fine
// Reason: Streams are designed for one-time use to optimize performance// STATELESS operations - Don't depend on previous elements
// Examples: filter(), map(), flatMap()
numbers.stream()
.filter(n -> n > 5) // Each element processed independently
.map(n -> n * 2) // No dependency on other elements
.collect(Collectors.toList());
// STATEFUL operations - Depend on previous elements
// Examples: sorted(), distinct(), limit(), skip()
numbers.stream()
.distinct() // Needs to remember what was seen
.sorted() // Needs to see all elements
.limit(5) // Needs to count
.collect(Collectors.toList());
// Stateful operations are barriers to parallelization// INTERMEDIATE operations - Return a Stream, lazy evaluation
// filter(), map(), flatMap(), distinct(), sorted(), peek(), limit(), skip()
Stream<Integer> intermediate = numbers.stream()
.filter(n -> n > 5) // Intermediate
.map(n -> n * 2); // Intermediate
// Nothing happens yet!
// TERMINAL operations - Trigger execution, return non-Stream result
// forEach(), collect(), reduce(), count(), anyMatch(), allMatch(),
// noneMatch(), findFirst(), findAny(), min(), max()
long count = numbers.stream()
.filter(n -> n > 5)
.count(); // Terminal - execution happens now!
// Multiple intermediate operations can be chained, but only ONE terminal operationList<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// Intermediate operations are not executed until terminal operation is called
Stream<Integer> stream = numbers.stream()
.filter(n -> {
System.out.println("Filtering: " + n);
return n > 2;
})
.map(n -> {
System.out.println("Mapping: " + n);
return n * 2;
});
System.out.println("Stream created, but nothing printed yet!");
// Now terminal operation triggers execution
List<Integer> result = stream.collect(Collectors.toList());
// Output:
// Stream created, but nothing printed yet!
// Filtering: 1
// Filtering: 2
// Filtering: 3
// Mapping: 3
// Filtering: 4
// Mapping: 4
// Filtering: 5
// Mapping: 5
// Notice: Operations are fused - filter and map happen together for each element// Short-circuiting operations can terminate early
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
// limit() - stops after n elements
List<Integer> first5 = numbers.stream()
.limit(5)
.collect(Collectors.toList());
// anyMatch() - stops at first match
boolean hasEven = numbers.stream()
.peek(n -> System.out.println("Checking: " + n))
.anyMatch(n -> n % 2 == 0);
// Output: Only "Checking: 1" and "Checking: 2" are printed
// findFirst() - stops after finding first element
Optional<Integer> first = numbers.stream()
.filter(n -> n > 5)
.findFirst();public static Map<Integer, Long> elementFrequency(List<Integer> numbers) {
return numbers.stream()
.collect(Collectors.groupingBy(
Function.identity(),
Collectors.counting()
));
}
// Example
List<Integer> nums = Arrays.asList(1, 2, 2, 3, 3, 3, 4, 4, 4, 4);
System.out.println(elementFrequency(nums));
// Output: {1=1, 2=2, 3=3, 4=4}public static Optional<Integer> secondHighest(List<Integer> numbers) {
return numbers.stream()
.distinct()
.sorted(Comparator.reverseOrder())
.skip(1)
.findFirst();
}
// Example
List<Integer> nums = Arrays.asList(5, 2, 8, 8, 1, 9);
System.out.println("Second highest: " + secondHighest(nums).orElse(-1));
// Output: Second highest: 8public static Set<Integer> findDuplicates(List<Integer> numbers) {
Set<Integer> seen = new HashSet<>();
return numbers.stream()
.filter(n -> !seen.add(n))
.collect(Collectors.toSet());
}
// Example
List<Integer> nums = Arrays.asList(1, 2, 3, 2, 4, 5, 3, 6);
System.out.println("Duplicates: " + findDuplicates(nums));
// Output: Duplicates: [2, 3]public static Optional<Character> firstNonRepeating(String str) {
return str.chars()
.mapToObj(c -> (char) c)
.collect(Collectors.groupingBy(
Function.identity(),
LinkedHashMap::new,
Collectors.counting()
))
.entrySet()
.stream()
.filter(e -> e.getValue() == 1)
.map(Map.Entry::getKey)
.findFirst();
}
// Example
System.out.println("First non-repeating: " +
firstNonRepeating("programming").orElse('X'));
// Output: First non-repeating: ppublic static Map<String, List<Employee>> groupByDepartment(List<Employee> employees) {
return employees.stream()
.collect(Collectors.groupingBy(Employee::getDepartment));
}public static Map<String, Double> maxSalaryByDept(List<Employee> employees) {
return employees.stream()
.collect(Collectors.groupingBy(
Employee::getDepartment,
Collectors.collectingAndThen(
Collectors.maxBy(Comparator.comparingDouble(Employee::getSalary)),
opt -> opt.map(Employee::getSalary).orElse(0.0)
)
));
}public static Map<String, Integer> sortMapByValue(Map<String, Integer> map) {
return map.entrySet()
.stream()
.sorted(Map.Entry.comparingByValue())
.collect(Collectors.toMap(
Map.Entry::getKey,
Map.Entry::getValue,
(e1, e2) -> e1,
LinkedHashMap::new
));
}
// Example
Map<String, Integer> scores = new HashMap<>();
scores.put("Alice", 85);
scores.put("Bob", 92);
scores.put("Charlie", 78);
System.out.println(sortMapByValue(scores));
// Output: {Charlie=78, Alice=85, Bob=92}public static Map<String, Long> wordCount(String text) {
return Arrays.stream(text.toLowerCase().split("\\s+"))
.collect(Collectors.groupingBy(
Function.identity(),
Collectors.counting()
));
}
// Example
String text = "java is great java is powerful";
System.out.println(wordCount(text));
// Output: {java=2, is=2, great=1, powerful=1}public static Map<Boolean, List<Integer>> partitionEvenOdd(List<Integer> numbers) {
return numbers.stream()
.collect(Collectors.partitioningBy(n -> n % 2 == 0));
}
// Example
List<Integer> nums = Arrays.asList(1, 2, 3, 4, 5, 6);
Map<Boolean, List<Integer>> partitioned = partitionEvenOdd(nums);
System.out.println("Even: " + partitioned.get(true));
System.out.println("Odd: " + partitioned.get(false));public static Optional<String> longestString(List<String> strings) {
return strings.stream()
.max(Comparator.comparingInt(String::length));
}
// Example
List<String> words = Arrays.asList("Java", "JavaScript", "Python");
longestString(words).ifPresent(s -> System.out.println("Longest: " + s));
// Output: Longest: JavaScriptpublic static List<Integer> mergeLists(List<Integer> list1, List<Integer> list2) {
return Stream.concat(list1.stream(), list2.stream())
.distinct()
.sorted()
.collect(Collectors.toList());
}
// Example
List<Integer> l1 = Arrays.asList(1, 3, 5);
List<Integer> l2 = Arrays.asList(2, 3, 4);
System.out.println(mergeLists(l1, l2));
// Output: [1, 2, 3, 4, 5]public static Map<Integer, String> listToMap(List<Employee> employees) {
return employees.stream()
.collect(Collectors.toMap(
Employee::getId,
Employee::getName,
(existing, replacement) -> existing // Keep first occurrence
));
}public static Map<String, Double> avgSalaryByDept(List<Employee> employees) {
return employees.stream()
.collect(Collectors.groupingBy(
Employee::getDepartment,
Collectors.averagingDouble(Employee::getSalary)
));
}public static List<Integer> topNElements(List<Integer> numbers, int n) {
return numbers.stream()
.distinct()
.sorted(Comparator.reverseOrder())
.limit(n)
.collect(Collectors.toList());
}
// Example
List<Integer> nums = Arrays.asList(5, 2, 8, 1, 9, 3, 7);
System.out.println("Top 3: " + topNElements(nums, 3));
// Output: Top 3: [9, 8, 7]public static List<String> removeNulls(List<String> strings) {
return strings.stream()
.filter(Objects::nonNull)
.collect(Collectors.toList());
}
// Example
List<String> words = Arrays.asList("Java", null, "Python", null, "JavaScript");
System.out.println(removeNulls(words));
// Output: [Java, Python, JavaScript]| Operation | Description | Example |
|---|---|---|
filter() |
Filter elements | .filter(n -> n > 5) |
map() |
Transform elements | .map(String::toUpperCase) |
flatMap() |
Flatten nested streams | .flatMap(List::stream) |
distinct() |
Remove duplicates | .distinct() |
sorted() |
Sort elements | .sorted() |
peek() |
Debug/side-effects | .peek(System.out::println) |
limit() |
Take first n | .limit(10) |
skip() |
Skip first n | .skip(5) |
| Operation | Description | Example |
|---|---|---|
forEach() |
Iterate | .forEach(System.out::println) |
collect() |
Collect to collection | .collect(Collectors.toList()) |
reduce() |
Reduce to single value | .reduce(0, Integer::sum) |
count() |
Count elements | .count() |
anyMatch() |
Check if any match | .anyMatch(n -> n > 5) |
allMatch() |
Check if all match | .allMatch(n -> n > 0) |
noneMatch() |
Check if none match | .noneMatch(n -> n < 0) |
findFirst() |
Get first element | .findFirst() |
findAny() |
Get any element | .findAny() |
min() |
Find minimum | .min(Comparator.naturalOrder()) |
max() |
Find maximum | .max(Comparator.naturalOrder()) |
| Collector | Description | Example |
|---|---|---|
toList() |
Collect to List | Collectors.toList() |
toSet() |
Collect to Set | Collectors.toSet() |
toMap() |
Collect to Map | Collectors.toMap(k, v) |
joining() |
Join strings | Collectors.joining(", ") |
counting() |
Count elements | Collectors.counting() |
summingInt() |
Sum integers | Collectors.summingInt(T::field) |
averagingInt() |
Average integers | Collectors.averagingInt(T::field) |
groupingBy() |
Group elements | Collectors.groupingBy(T::field) |
partitioningBy() |
Partition by predicate | Collectors.partitioningBy(predicate) |
- Use primitive streams when possible:
IntStream,LongStream,DoubleStreamavoid boxing overhead - Short-circuit operations: Use
limit(),findFirst(),anyMatch()to stop early - Parallel streams carefully: Only for large datasets with CPU-intensive operations
- Avoid stateful operations in parallel:
sorted(),distinct()in parallel streams - Method references over lambdas:
String::lengthis cleaner thans -> s.length() - Collect once: Don't call
collect()multiple times on same stream
- ❌ Reusing streams
- ❌ Modifying source during stream operations
- ❌ Using parallel streams for small datasets
- ❌ Side effects in stream operations
- ❌ Not handling Optional properly
- ❌ Using streams when simple loop is clearer
Java Streams provide a powerful, functional approach to processing collections. Master these patterns and you'll be well-prepared for any Java interview! Practice these problems regularly to build muscle memory.
Remember: Streams are about declaring WHAT you want, not HOW to do it. Think declaratively!
Good luck with your Java interviews! 🚀