avatarSoma

Summary

This web content provides a comprehensive list of advanced Java interview questions focused on Lambda expressions and the Stream API, offering insights into functional programming concepts and practical examples for Java developers preparing for interviews.

Abstract

The article titled "Top 21 Lambda and Stream Interview Questions for Experienced Java Programmers" is a resource aimed at Java developers looking to prepare for interviews that cover Java 8 features, particularly Lambda expressions and the Stream API. It includes a curated list of 21 interview questions along with answers and explanations, covering topics such as the differences between Lambda expressions and anonymous classes, functional interfaces, and various Stream operations like filter, map, and reduce. The author emphasizes the importance of understanding these concepts deeply, as they have become integral to modern Java programming. Additionally, the article offers guidance on debugging streams, performing parallel computations, and provides examples to illustrate the use of different functional interfaces like Supplier, Consumer, Predicate, and Function. The content also directs readers to additional resources for further learning, including recommended online courses and specialized books on Java interview preparation.

Opinions

  • The author believes in the importance of regular preparation for Java interviews and learns through the process of writing about and preparing for them.
  • Prior to Java 8, Java interviews were considered easier, focusing on Collections and Multi-threading, but the introduction of Lambda expressions and Stream API has significantly increased their complexity.
  • The author suggests that practical knowledge of Java, particularly in Lambda and Streams, is essential for experienced Java programmers to succeed in interviews.
  • The article implies that understanding the intricacies of functional interfaces, such as Supplier and Consumer, is crucial for effective use in functional programming with Java.
  • Debugging streams is presented as a challenging aspect of Java programming, with the peek() method highlighted as a valuable tool for this purpose.
  • The author encourages the use of the @FunctionalInterface annotation for compile-time checks, ensuring that interfaces are correctly implemented as functional interfaces.
  • The article promotes the use of parallel streams for performance improvements in certain scenarios, while also cautioning about the potential overhead that may outweigh the benefits in some cases.
  • The author endorses specific online courses and platforms for learning Java, suggesting that they can significantly enhance a developer's skill set.
  • The recommendation of the books "Grokking the Java Interview" and "Grokking the Spring Boot Interview" indicates the author's confidence in their value for interview preparation.

Top 21 Lambda and Stream Interview Questions for Experienced Java Programmers

My favorite Java interview questions from Lambda expression and Stream API for experienced Java developers

Hello friends, If you are preparing for Java developer interviews then you may have come across my earlier articles like 25 Advanced Java questions, 25 Spring Framework questions, 20 SQL queries from Interviews, 50 Microservices questions, 60 Tree Data Structure Questions, 15 System Design Questions, and 35 Core Java Questions.

More than 10K people have read those articles and I am really thankful to all of them. I like to write about Java interview questions because I believe in regular preparation and I learn a lot when I write about Java interviews or prepare for them.

Most of my Java knowledge is the result of my research for finding answers to Java questions asked to me on interviews and that’s the reason I am always in search of new and challenging Java questions.

Prior to Java 8, Java Interviews were used to be easy and mostly focused around Collections and Multi-threading but from Java 8 onward, it has become more and more tough with increased focus on Lambda and Stream API.

These 2 are tricky topics and if you have not worked or used them extensively you will most likely to struggle on interviews and that’s why I am sharing these frequently asked Java interview questions from Lambda Expression and Stream API which can help you to learn essential concepts and prepare better.

By the way, if you are new to Java programming language or want to improve Java skills then you can also checkout following best Java courses to get better:

  1. The Complete Java Masterclass (covers Java 17)
  2. Java Programming and Software Engineering Fundamentals Specialization Certificate on Coursera
  3. Java Programming Bootcamp: Zero to Mastery
  4. The Complete Java Programming Masterclass! [Karpado]
  5. CodeGym (learn Java by building Games)

These are my favorite online courses and platforms to learn Java from scratch and also build your Java skills. If you need more advanced courses to take your Java skill to next level you can also see following articles:

21 Java Lambda and Stream Interview Questions with Answers

So, what are we waiting for, here is the list of popular Java 8 questions related to Stream and Lambda Expression

  1. What is a lambda expression and how is it used in Java 8? (answer) hint — its a shortcut to pass code to a method, at the moment you can only pass code or lambda expression to a method which accept a functional interface.
  2. What is difference between Lambda expression and Anonymous class? Are they same? (answer) hint — anonymous class can implement non-functional interface as well. It’s also slower than lambda.
  3. What is functional interface in Java? Can you declare your own functional interface? (answer) hint — any method with just one abstract method like Runnable, Callable or Predicate, Consumer etc
  4. Is @Functional annotation mandatory for declaring functional interface in Java? (answer) hint — no, you can have functional interface without that annotation like Runnable, Comparator, and Callable.
  5. Can you use an interface with one abstract method from your old JAR as functional interface without recompiling them with Java 8 compiler? (answer) hint — yes, you can, no need to recompile code with Java8 compiler
  6. Can you explain the difference between map and flatMap in Java 8. (answer) you can use map to convert one object to another object while flatmap can also flatten apart from conversion. For example, you can use flatmap to convert a List of List of integer to List of String.
  7. Which method is used to filter objects in a stream of data? (answer) hint — you can use filter method to fitler data in stream, it accepts a Predicate which can be used to pass the filtering criterion.
  8. What is difference between Stream and IntStream class? (answer) hint — IntStream is a specialized class for int primitive, it will prevent auto-boxing and provide improved performance.
  9. How can you use the reduce method to perform a reduction operation on a stream of data? (answer) You can see this example to learn about how to use map and reduce.
  10. Can you name 5 different types of Functional interface in Java? (answer) hint — Supplier Predicate Consumer Runnable Function
  11. How can you use the collect method to collect the elements of a stream into a collection? (answer)
  12. What is difference between Predicate and Function interface in Java? (answer)

In Java, both Predicate and Function are functional interfaces that can be used with lambda expressions and method references. However, they have different purposes:

  • Predicate is an interface that takes an argument of a certain type and returns a boolean value. It is typically used to test whether an object satisfies a certain condition. The test(T t) method of the Predicate interface takes an argument of type T and returns a boolean.
  • Function is an interface that takes an argument of a certain type and returns a value of another type. It is typically used to transform an object of one type into an object of another type. The apply(T t) method of the Function interface takes an argument of type T and returns a value of type R.

In other words, a Predicate is a function that returns a boolean value, whereas a Function is a function that returns a non-boolean value.

Here’s an example that demonstrates the difference between the two:

List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David", "Eve");

// Example 1: Predicate
Predicate<String> startsWithA = name -> name.startsWith("A");

List<String> filteredNames = names.stream()
                                  .filter(startsWithA)
                                  .collect(Collectors.toList());
System.out.println(filteredNames); // Output: [Alice]

// Example 2: Function
Function<String, Integer> lengthFunction = name -> name.length();

List<Integer> nameLengths = names.stream()
                                 .map(lengthFunction)
                                 .collect(Collectors.toList());
System.out.println(nameLengths); // Output: [5, 3, 7, 5, 3]

In this example, we have a list of names. In the first example, we define a Predicate that tests whether a name starts with the letter "A". We then use this Predicate with the filter() method of the Stream API to obtain a new stream that contains only the names that start with "A".

In the second example, we define a Function that maps each name to its length. We then use this Function with the map() method of the Stream API to obtain a new stream that contains the lengths of the names.

Note that both Predicate and Function are functional interfaces, which means that they can be used with lambda expressions and method references. This makes it easy to write concise and expressive code that operates on collections of objects.

13. How to perform a parallel computation on a stream of data? (answer)

you can use the parallel() method of the Stream interface to perform a parallel computation on a stream of data. The parallel() method returns a parallel stream, which is a stream that can be processed in parallel by multiple threads.

Here’s an example that demonstrates how to use parallel streams to perform a time-consuming computation on a large list of integers:

List<Integer> numbers = IntStream.rangeClosed(1, 1000000).boxed().collect(Collectors.toList());

long startTime = System.currentTimeMillis();
int sum = numbers.stream().reduce(0, Integer::sum);
long endTime = System.currentTimeMillis();
System.out.println("Sequential sum: " + sum + " in " + (endTime - startTime) + " ms");

startTime = System.currentTimeMillis();
sum = numbers.parallelStream().reduce(0, Integer::sum);
endTime = System.currentTimeMillis();
System.out.println("Parallel sum: " + sum + " in " + (endTime - startTime) + " ms");

In this example, we first create a list of integers from 1 to 1,000,000 using the IntStream.rangeClosed() method. We then use the reduce() method of the stream to calculate the sum of the integers. We do this twice, once with a sequential stream and once with a parallel stream. The startTime and endTime variables are used to measure the time taken to perform the computation.

The output of the example is:

Sequential sum: 500000500000 in 9 ms
Parallel sum: 500000500000 in 2 ms

This shows that the parallel computation is much faster than the sequential computation, as it takes only 2 milliseconds compared to 9 milliseconds for the sequential computation.

However, note that parallel streams are not always faster than sequential streams, as the overhead of parallelization can sometimes outweigh the benefits. It is important to measure the performance of both approaches before deciding which one to use.

14. What is difference between Supplier and Consumer interface in Java? (answer)

In Java, the Supplier and Consumer interfaces are part of the functional interfaces introduced in Java 8 to support functional programming with lambda expressions.

The main difference between Supplier and Consumer is the direction of the data flow:

  • Supplier is a functional interface that represents a supplier of data. It has a single method get() that returns a value of a specified type. This means that the Supplier interface is used to provide data to a method or a function.
  • Consumer is a functional interface that represents a consumer of data. It has a single method accept(T t) that takes a value of a specified type as input and returns no output. This means that the Consumer interface is used to consume data from a method or a function.

In other words, a Supplier supplies data, while a Consumer consumes data. Here are some examples of how these interfaces can be used:

// Example using Supplier interface
Supplier<String> messageSupplier = () -> "Hello, world!";
String message = messageSupplier.get(); // message = "Hello, world!"

// Example using Consumer interface
Consumer<String> messageConsumer = (message) -> System.out.println(message);
messageConsumer.accept("Hello, world!"); // prints "Hello, world!" to the console

In the first example, a Supplier is used to supply a message, which is then stored in the message variable. In the second example, a Consumer is used to consume the message and print it to the console.

In summary, the Supplier and Consumer interfaces are both used to work with data in functional programming, but they differ in their direction of data flow.

15. How can you use the Stream API to perform a sorted operation on a stream of data? (answer)

In Java, the Stream API provides the sorted() method to perform a sorted operation on a stream of data. The sorted() method returns a new stream consisting of the elements of the original stream, sorted according to their natural order or a specified comparator.

Here’s an example of how to use the sorted() method to sort a stream of integers:

List<Integer> numbers = Arrays.asList(3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5);

List<Integer> sortedNumbers = numbers.stream()
                                      .sorted()
                                      .collect(Collectors.toList());

System.out.println(sortedNumbers);

This code creates a List of integers and then uses the stream() method to create a stream of the integers. The sorted() method is called on the stream to sort the elements in ascending order. Finally, the collect() method is used to collect the sorted elements into a new List.

The output of the code will be: [1, 1, 2, 3, 3, 4, 5, 5, 5, 6, 9].

If you want to sort the elements in descending order, you can pass a custom comparator to the sorted() method:

List<Integer> sortedNumbers = numbers.stream()
                                      .sorted(Comparator.reverseOrder())
                                      .collect(Collectors.toList());

This code sorts the elements in descending order using the reverseOrder() method of the Comparator interface.

In summary, the sorted() method of the Stream API can be used to sort the elements of a stream in natural or custom order.

16. How do you debug Stream in Java? Which method of Stream API can be helpful? (answer) hint — you can use peek() method to debug stream and see data during different stage of stream pipeline.

Debugging streams in Java can be a bit tricky, but the Stream API provides a few methods that can be helpful for this purpose.

One of the most useful methods for debugging a stream is the peek() method. The peek() method allows you to perform an action on each element of the stream without modifying the stream itself. You can use the peek() method to print out the elements of the stream, for example, to see what values the stream is processing at each step:

List<String> words = Arrays.asList("apple", "banana", "cherry");

List<String> result = words.stream()
                            .peek(System.out::println)
                            .filter(s -> s.startsWith("a"))
                            .peek(System.out::println)
                            .collect(Collectors.toList());

In this code, the peek() method is used twice to print out the elements of the stream before and after the filter() operation. The output of the code will be:

apple
apple
banana

This shows that the filter() operation removed the element "cherry" from the stream.

Another helpful method for debugging streams is the limit() method. The limit() method allows you to restrict the size of the stream to a certain number of elements. You can use the limit() method to limit the size of the stream to a small number of elements, for example, to see if the stream is processing the correct data:

List<String> words = Arrays.asList("apple", "banana", "cherry");

List<String> result = words.stream()
                            .limit(2)
                            .map(String::toUpperCase)
                            .collect(Collectors.toList());

In this code, the limit() method is used to limit the stream to the first two elements. The map() operation is then applied to transform the remaining elements to uppercase. The output of the code will be:

[APPLE, BANANA]

This shows that the map() operation was applied only to the first two elements of the stream.

In summary, the peek() and limit() methods of the Stream API can be helpful for debugging streams in Java. The peek() method allows you to perform actions on each element of the stream, while the limit() method allows you to restrict the size of the stream.

17. How to perform a distinct operation on a stream of data? (answer)

You can use the distinct() method of the Stream API to perform a distinct operation on a stream of data in Java.

The distinct() method returns a new stream that contains only the distinct elements of the original stream. It does this by comparing the elements using their equals() method.

Here’s an example that demonstrates how to use the distinct() method:

List<Integer> numbers = Arrays.asList(1, 2, 2, 3, 3, 3, 4, 5, 5);

List<Integer> distinctNumbers = numbers.stream()
                                        .distinct()
                                        .collect(Collectors.toList());

In this example, we have a list of numbers that contains duplicates. We use the stream() method to create a stream of the numbers, and then call the distinct() method to obtain a new stream that contains only the distinct elements. Finally, we use the collect() method to collect the distinct elements into a list.

The output of the code will be:

[1, 2, 3, 4, 5]

This shows that the distinct() method has removed the duplicate elements from the stream.

Note that the distinct() method uses the equals() method to compare the elements. If you want to perform distinct operations based on a specific property of an object, you can use the distinct() method in combination with map() and equals() methods.

18. How to perform a grouping and aggregation operation on a stream of data? (answer)

You can use the Collectors.groupingBy() method to perform a grouping and aggregation operation on a stream of data along with other Collectors methods such as counting(), summingInt(), and averagingInt().

Here’s an example that demonstrates how to group a stream of Person objects by their age, and then calculate the number of people and their average salary in each age group:

List<Person> people = Arrays.asList(
    new Person("Alice", 25, 50000),
    new Person("Bob", 30, 60000),
    new Person("Charlie", 25, 55000),
    new Person("Dave", 35, 70000),
    new Person("Eve", 30, 65000)
);

Map<Integer, Long> countByAge = people.stream()
    .collect(Collectors.groupingBy(Person::getAge, Collectors.counting()));

Map<Integer, Double> avgSalaryByAge = people.stream()
    .collect(Collectors.groupingBy(Person::getAge, Collectors.averagingInt(Person::getSalary)));

System.out.println("Count by age: " + countByAge);
System.out.println("Average salary by age: " + avgSalaryByAge);

In this example, we first create a list of Person objects. We then use the groupingBy() method to group the list by the Person objects' age field. The counting() collector is used to count the number of Person objects in each age group, and the averagingInt() collector is used to calculate the average salary of the Person objects in each age group.

The output of the example is:

Count by age: {25=2, 30=2, 35=1}
Average salary by age: {25=52500.0, 30=62500.0, 35=70000.0}

This shows that there are 2 people aged 25, 2 people aged 30, and 1 person aged 35 in the list, and that the average salary of people aged 25 is $52,500, the average salary of people aged 30 is $62,500, and the average salary of people aged 35 is $70,000.

19. How can you use the Stream API to perform a matching operation on a stream of data? (answer)

You can use the Stream API’s anyMatch(), allMatch(), and noneMatch() methods to perform a matching operation on a stream of data.

  • anyMatch(Predicate<T> predicate) returns true if at least one element of the stream matches the given predicate.
  • allMatch(Predicate<T> predicate) returns true if all elements of the stream match the given predicate.
  • noneMatch(Predicate<T> predicate) returns true if no element of the stream matches the given predicate.

Here’s an example that uses anyMatch() to check if a stream of integers contains any odd numbers:

List<Integer> numbers = Arrays.asList(2, 4, 6, 7, 8);
boolean hasOdd = numbers.stream().anyMatch(n -> n % 2 != 0);
System.out.println(hasOdd); // prints true

In this example, the anyMatch() method is called on the stream of integers returned by numbers.stream(), with the predicate n -> n % 2 != 0. This predicate checks if the given integer is odd by checking if its remainder when divided by 2 is not equal to 0. The method returns true because the stream contains the odd number 7.

22. Can you declare more than one method in a functional interface in Java? (answer) hint — Yes, you can add as many static and default methods as you want as interface can have those but only one abstract method.

21. If @Functional annotation is not mandatory then why do you use with functional interface? what benefit it provides? (answer) hint — it helps during compile time by throwing error if your interface is not really a functional interface for example it contains two abstract method. This is similar to @Override annotation.

Java and Spring Interview Preparation Material

Before any Java and Spring Developer interview, I always use to read the below resources

Grokking the Java Interview

Grokking the Java Interview: click here

I have personally bought these books to speed up my preparation.

You can get your sample copy here, check the content of it and go for it

Grokking the Java Interview [Free Sample Copy]: click here

If you want to prepare for the Spring Boot interview you follow this consolidated ebook, it also contains microservice questions from spring boot interviews.

Grokking the Spring Boot Interview

You can get your copy here — Grokking the Spring Boot Interview

That’s all about the 21 Stream and Lambda Expression interview questions. It’s important to have a good understanding of the Stream API and how to use it to perform operations on a stream of data. You should also be familiar with the different intermediate and terminal operations that are available in the Stream API and how to use them effectively.

Additionally, you should be familiar with lambda expressions, which are used to pass behavior as a method argument. And, If you need more Java 8 questions you can also see this 50 Java 8 questions and 15 Java Stream questions for more preparation.

By the way, if you are new to Java programming language or want to improve Java skills then you can also checkout following best Java courses to get better:

  1. The Complete Java Masterclass (covers Java 17)
  2. Java Programming and Software Engineering Fundamentals Specialization Certificate on Coursera
  3. Java Programming Bootcamp: Zero to Mastery
  4. The Complete Java Programming Masterclass! [Karpado]
  5. CodeGym (learn Java by building Games)

These are my favorite online courses and platforms to learn Java from scratch and also build your Java skills. If you need more advanced courses to take your Java skill to next level you can also see following articles:

Java
Programming
Functional Programming
Tech
Software Development
Recommended from ReadMedium