Basic Java 8 Interview Questions and Answers

1. What are the key features introduced in Java 8?

Java 8 introduced several major features, including :

  • Lambda Expressions for concise anonymous function expressions.
  • Functional Interfaces that define a single abstract method, like Runnable and Comparator.
  • Stream API for functional-style operations on collections.
  • Default and Static Methods in interfaces for backward compatibility.
  • Optional Class to avoid NullPointerException.
  • New Date and Time API (java.time) for better date handling.
  • Collectors for reducing and grouping data in streams.
  • Nashorn JavaScript Engine for executing JavaScript within Java.

2. What are Lambda Expressions in Java 8?

A Lambda Expression is a concise way to represent anonymous functions. It allows passing behavior as parameters, reducing boilerplate code. The syntax:

java
(parameters) -> expression (param1, param2) -> { statements; }
eg.

java
List<String> names = Arrays.asList("John", "Jane", "Jack"); names.forEach(name -> System.out.println(name));

3. What is a Functional Interface?

A Functional Interface in Java 8 has only one abstract method and can have multiple default/static methods.
Example:

@FunctionalInterface
java
interface MyInterface { void display();
Java provides several built-in functional interfaces like Predicate, Function, Consumer, and Supplier.

4. What is the difference between Collection and Stream API?

The Collection API (List, Set, etc.) is used to store and manage groups of objects. It supports operations like add, remove, and iterate. It’s eager, meaning operations are performed immediately.The Stream API is designed for processing data, not storing it. Streams are lazy, performing operations only when a terminal operation (like collect() or forEach()) is called.

Key differences:

  • Collection holds data; Stream processes data.
  • Collection modifies data; Stream doesn't alter the source.
  • Streams support functional-style operations like map, filter, reduce.Streams can be parallelized easily.

5. What are Default Methods in Java 8?

Default Methods in Java 8 allow interfaces to have method implementations using the default keyword. Before Java 8, interfaces could only have abstract methods, but default methods offer backward compatibility for adding new features without breaking existing implementations.
Example:
java
interface MyInterface { default void greet() { System.out.println("Hello!"); } }

6. What is the Optional Class in Java 8?

The Optional class in Java 8 is a container object that may or may not contain a non-null value. It’s used to avoid NullPointerException and represents the presence or absence of a value in a more expressive way.
Common methods include:

  • of(), ofNullable(), empty()
  • get(), isPresent(), orElse(), orElseGet(), orElseThrow()
Optional promotes cleaner code, especially when chaining method calls, and encourages better handling of missing values. It’s especially useful in APIs and return types where null might otherwise be returned.

7. What is the difference between map() and flatMap() in Streams?

Both map() and flatMap() are intermediate operations used in Java 8 Streams, but they behave differently when dealing with nested structures or transformations.
  • map() transforms each element and wraps the result back into a Stream.
  • flatMap() not only transforms but also flattens nested structures into a single stream.
List<List<String>> names = ...;
java
names.stream().map(List::stream); // Stream<Stream<String>> names.stream().flatMap(List::stream); // Stream<String>

8. What are Method References in Java 8?

Method References are a shorthand notation for calling methods via lambdas. They improve readability by replacing verbose lambda expressions. The syntax uses the :: operator.
  • Types of method references:
  1. Static methods – ClassName::staticMethod
  2. Instance methods – object::instanceMethod
  3. Instance methods of arbitrary objects – ClassName::instanceMethod
  4. Constructor reference – ClassName::new
java
list.forEach(System.out::println);

9. What is a Stream Terminal Operation?

A Terminal Operation in Java 8 Streams is an operation that produces a result or a side-effect and marks the end of the stream pipeline. Once a terminal operation is applied, the stream can’t be reused.
Common terminal operations include:
  • forEach() – performs an action on each element.
  • collect() – collects elements into a list, set, or map.
  • reduce() – reduces the stream to a single value.
  • count(), min(), max(), anyMatch(), allMatch()
java
List<Integer> nums = Arrays.asList(1, 2, 3); int sum = nums.stream().reduce(0, Integer::sum);

10. What is the purpose of the java.util.function package?

The java.util.function package introduced in Java 8 contains functional interfaces designed to support lambda expressions and functional programming. These interfaces are generic and cover most common use cases in data processing and transformation.
Common interfaces include:
  • Predicate<T> – takes a value and returns a boolean (test)
  • Function<T, R> – takes a value and returns another (apply)
  • Consumer<T> – takes a value and returns nothing (accept)
  • Supplier<T> – returns a value (get)
  • UnaryOperator<T>, BinaryOperator<T> – special forms of Function
These interfaces are widely used with the Stream API, Optional, and in method references. They help write cleaner, more reusable code and enable passing behavior (functions) as parameters, promoting functional style.


11. What is the difference between findFirst() and findAny() in Streams?

Both findFirst() and findAny() are terminal operations in Java 8 Streams that return an Optional<T> containing an element from the stream, but they differ in behavior:
  • findFirst() returns the first element in the stream (based on encounter order).
  • findAny() returns any element, often faster in parallel streams.
java
list.stream().findFirst(); // predictable, ordered list.parallelStream().findAny(); // faster, possibly unordered

12. What is Stream pipelining?

Stream pipelining refers to the chaining of multiple intermediate operations on a stream followed by a terminal operation. It creates a stream pipeline, which is lazily evaluated—meaning nothing happens until the terminal operation is invoked.

java
List<String> result = names.stream() .filter(name -> name.startsWith("A")) .map(String::toUpperCase) .collect(Collectors.toList());

In this example, filter and map are intermediate operations, and collect is the terminal operation that triggers processing.Stream pipelining is efficient because it processes elements one at a time through the chain, rather than applying each operation to the whole stream at once. This reduces overhead and improves performance, especially in large datasets.

13. What are Intermediate Operations in Streams?

  • Intermediate Operations are operations in the Stream API that return another stream, allowing further operations to be chained (pipelining). They are lazy, meaning they don’t process data until a terminal operation is invoked.
  • filter(Predicate) – filters elements.
  • map(Function) – transforms elements
    • sorted() – sorts the stream
    • distinct() – removes duplicates
    • limit(n), skip(n) – restrict data
java
stream.filter(s -> s.length() > 3).map(String::toUpperCase)

14. What is the Predicate functional interface in Java 8?

In Java 8, the Predicate<T> functional interface is used to evaluate a boolean condition on an input of type T. It contains a single abstract method test(T t) that returns true or false. Predicates are commonly used in scenarios where conditional logic is applied, such as filtering elements in a Stream. For example, you can filter all strings that start with the letter "A" using a Predicate.

You can also chain predicates using default methods like and(), or(), and negate() to build complex conditions. The use of Predicate helps to write clean and expressive code while working with functional operations. It is part of the java.util.function package, which was introduced to support functional programming constructs in Java 8.

15. How does forEach() work in Java 8 Streams?

The forEach() method in Java 8 is a terminal operation used to perform an action for each element in the stream. It takes a Consumer<T> as a parameter and is often used to print, log, or process items. For example, you can print each element in a list using list.stream().forEach(System.out::println);. While forEach() is useful for side-effects, it does not modify the stream or return any value.

It is important to note that when using parallel streams, the order of execution may not be consistent. Therefore, forEachOrdered() is recommended when preserving order is necessary. forEach() helps eliminate traditional for loops, making the code cleaner and more expressive in a functional programming style.

16. What is the map() function used for in Java Streams?

The map() function in Java 8 Streams is an intermediate operation used to transform each element of the stream. It takes a Function<T, R> as input and returns a stream consisting of the results of applying the function. For example, to convert all strings in a list to uppercase, you can use map(String::toUpperCase).

It does not change the original collection; instead, it creates a new stream with modified values. map() is widely used when you want to convert data types, extract fields from objects, or apply any transformation logic. It enables functional-style transformations that make the code cleaner, more readable, and easier to maintain. It is a core part of stream processing pipelines in Java 8.

17. How is filter() different from map() in Streams?

Both filter() and map() are intermediate operations in Java 8 Streams, but they serve different purposes. The filter() method is used to exclude elements that do not match a given condition, returning a stream with fewer (or equal) elements. It takes a Predicate<T> as input. On the other hand, map() is used to transform each element into another form using a Function<T, R>.

For example, filter(x -> x > 5) will return only numbers greater than 5, while map(x -> x * 2) will return each number multiplied by 2. They are often used together in stream pipelines to first filter unwanted elements and then transform the remaining ones into the desired format.

18. What is the purpose of reduce() in Java Streams?

The reduce() method in Java 8 Streams is a terminal operation that performs a reduction on the elements of the stream using an associative accumulation function. It combines all elements into a single result. The most common use case is summing numbers, finding the maximum/minimum, or concatenating strings.

The method takes two parameters: an identity value and a BinaryOperator, such as (a, b) -> a + b. For instance, to sum integers: list.stream().reduce(0, Integer::sum). If an identity isn’t provided, it returns an Optional<T>. reduce() is powerful in functional programming as it simplifies aggregation logic, removing the need for explicit iteration and conditional statements.

19. What is the use of the Stream API in Java 8?

The Stream API introduced in Java 8 is a powerful feature that enables functional-style operations on sequences of elements, like collections. It allows data to be processed in a declarative way, making the code more concise, readable, and efficient. Streams support operations like filtering, mapping, sorting, and reducing, which can be chained together in a pipeline.

Streams can be either sequential or parallel, making it easy to take advantage of multicore processors. For example, you can transform a list of strings to uppercase and filter those starting with "A" in just a few lines of code using streams. The Stream API helps reduce boilerplate code and encourages the use of functional programming principles in Java, promoting better abstraction and cleaner data processing.

20. How does Java 8 support functional programming?

Java 8 supports functional programming primarily through the introduction of lambda expressions, the Stream API, and the java.util.function package. Functional programming is a paradigm where functions are treated as first-class citizens, enabling behavior to be passed around as parameters.

Lambda expressions allow methods to be passed as arguments, simplifying callbacks and event handling. The Stream API encourages a declarative approach to data manipulation by chaining operations like filter, map, and reduce. Additionally, Java 8 introduced functional interfaces like Function, Predicate, Consumer, and Supplier that are used in many stream operations. This shift enables more concise, readable, and testable code, aligning Java with modern programming trends seen in languages like Scala, Kotlin, and JavaScript.

21. What are primitive type streams in Java 8?

Java 8 provides specialized stream types for handling primitive data types more efficiently—namely, IntStream, LongStream, and DoubleStream. These streams avoid the overhead of boxing and unboxing primitive values into their wrapper classes (Integer, Long, Double) during stream operations. For instance, instead of using Stream<Integer>, IntStream can be used to work directly with int values. They come with specific methods like sum(), average(), and range() that are not available in generic streams.


java
IntStream.range(1, 5).sum(); // returns 10

22. What is a functional interface in Java 8?

A functional interface in Java 8 is an interface that has exactly one abstract method. It can contain multiple default or static methods, but only one abstract method is allowed. Functional interfaces are used to define types for lambda expressions and method references.

Java 8 introduced the @FunctionalInterface annotation to indicate that an interface is intended to be functional. Common examples include Runnable, Callable, Comparator, and interfaces from the java.util.function package like Function, Predicate, and Consumer. For instance, Function<T, R> has a single method apply(T t) and is used with map() operations in streams. Functional interfaces are the backbone of functional programming in Java and make the language more expressive and flexible.

23. What are the key differences between Java 7 and Java 8?

Java 8 introduced several major enhancements over Java 7, the most notable being lambda expressions, which enable a functional programming style by passing behavior as parameters. Java 8 also introduced the Stream API for efficient and readable data processing, and the java.time package, which offers a much-improved date/time API compared to Date and Calendar. Additionally, default and static methods in interfaces allow interface evolution without breaking existing code.

Java 8 also brought in Optional, which helps prevent NullPointerException, and the Nashorn JavaScript engine for embedding JavaScript in Java applications. In contrast, Java 7 focused more on language-level improvements like try-with-resources, multicatch, and switch statements with strings. Java 8 is a significant shift toward functional and declarative programming.

24. What is the Optional class in Java 8 and why is it useful?

Java 8 introduced the Optional<T> class as a container object to represent the presence or absence of a value. It helps avoid null pointer exceptions by providing a safe way to handle potentially null values. Instead of returning null, a method can return an Optional, and the caller can explicitly handle cases where the value is absent. Optional provides methods like isPresent(), ifPresent(), orElse(), orElseGet(), and map() to work with values.

java
Optional<String> name = Optional.ofNullable(getName()); name.ifPresent(System.out::println);

This encourages better null-check handling and makes the code more expressive and less error-prone. While Optional is not meant for every case, it's extremely useful in method return types where null might be expected.

25. What are default and static methods in interfaces in Java 8?

Before Java 8, interfaces in Java could only have abstract methods, meaning any method added would require all implementing classes to override it. Java 8 introduced default methods and static methods in interfaces, allowing developers to add new functionality without breaking existing implementations. A default method is declared with the default keyword and has a method body.

java
default void log(String msg) { System.out.println("Log: " + msg); }
java

Static methods in interfaces can be called using the interface name and are useful for utility or helper functionality. These changes support interface evolution, allowing you to add methods in large codebases safely. It’s especially beneficial for maintaining backward compatibility while still enabling new features and cleaner code design.

line

Copyrights © 2024 letsupdateskills All rights reserved