1. What is a functional interface in Java 8?
A functional interface defines exactly one abstract method and serves as a target for lambda expressions and method references. It may include default or static methods for reusable behavior and can be annotated with @FunctionalInterface
to communicate intent and enable compiler checks.
@FunctionalInterface
interface MyFunc {
void execute();
}
SEO tip: Use functional interfaces to design clean, testable APIs for callback-style or strategy patterns.
2. What is a lambda expression?
A lambda expression is a compact way to represent an anonymous function, replacing boilerplate anonymous classes. Lambdas improve readability and enable functional-style operations on collections via the Stream API.
(a, b) -> a + b
Best practice: Keep lambdas concise; extract complex logic into named methods for clarity and reusability.
3. What is the Stream API?
The Stream API provides a fluent, functional-style pipeline to process collections: filtering, mapping, reducing, and collecting results. Streams enable lazy evaluation and can be parallelized for performance gains when used correctly.
List<String> names = list.stream()
.filter(s -> s.startsWith("A"))
.collect(Collectors.toList());
Performance note: Use parallelStream()
only after measuring benefits and ensuring thread-safety of operations.
4. What is the difference between intermediate and terminal operations in streams?
Intermediate operations (e.g., filter()
, map()
) return a new stream and are lazily evaluated. Terminal operations (e.g., collect()
, forEach()
, count()
) produce a result or side-effect and trigger the pipeline execution.
Tip: Chain intermediate ops to build pipelines and keep side-effects confined to terminal operations for predictability.
5. How do you remove duplicates from a list using streams?
Use distinct()
to filter out duplicate elements based on equals()
, then collect results back into a list.
List<String> unique = list.stream()
.distinct()
.collect(Collectors.toList());
Alternative: For custom deduplication rules, use Collectors.toMap()
with a merge function.
6. What is the Optional class?
Optional is a container for an optional value that may be present or absent, reducing null checks and NullPointerExceptions. It encourages fluent handling of missing values via ifPresent
, orElse
, and map
.
Optional.ofNullable(name).ifPresent(System.out::println);
Guideline: Avoid overusing Optional in fields or collections; prefer it for return types of methods that might not produce a value.
7. What is a method reference in Java 8?
A method reference is a concise form of lambda that refers to an existing method by name, improving readability. Syntax forms include Class::staticMethod
, instance::method
, and Class::instanceMethod
.
list.forEach(System.out::println);
When to use: Replace simple lambdas with method references to clarify intent and reduce noise.
8. How do you sort a list using streams?
Use sorted()
for natural ordering or supply a custom comparator for bespoke orderings. Collect the results or process them directly in the stream pipeline.
list.stream()
.sorted()
.forEach(System.out::println);
// custom comparator
list.stream()
.sorted((a, b) -> b.compareTo(a))
.forEach(System.out::println);
Tip: For large datasets, consider collecting and sorting in-place if memory and mutability are acceptable.
9. What is the difference between map() and flatMap()?
map()
transforms each element into exactly one result element; flatMap()
maps each element to a stream (or collection) and flattens the resulting nested structure into a single stream, useful for processing nested collections.
list.stream()
.flatMap(Collection::stream)
.collect(Collectors.toList());
Use case: Use flatMap()
to flatten lists of lists or to expand elements into multiple items.
10. How do you filter null values from a list?
Filter nulls with Objects::nonNull
to produce a cleaned collection without null entries, improving safety before downstream processing.
list.stream()
.filter(Objects::nonNull)
.collect(Collectors.toList());
Best practice: Validate inputs early and prefer non-null collections downstream.
11. How do you group elements using streams?
Use Collectors.groupingBy()
to partition elements into a map keyed by a classifier function. This is efficient for reporting, aggregation, and preparing grouped data structures for UI or export.
Map<String, List<Person>> grouped =
people.stream()
.collect(Collectors.groupingBy(Person::getCity));
Pro tip: Combine groupingBy with downstream collectors (counting, mapping, summing) for one-pass aggregations.
12. What is the purpose of default methods in interfaces?
Default methods allow interfaces to provide concrete method implementations, enabling API evolution without breaking existing implementations. They help add behavior to interfaces while maintaining backward compatibility.
default void log(String msg) {
System.out.println(msg);
}
Design note: Use default methods sparingly to avoid confusing multiple-inheritance semantics.
13. How do you count elements in a stream?
Use the count()
terminal operation to return the number of elements after optional intermediate transformations like filter()
.
long count = list.stream()
.filter(s -> s.length() > 3)
.count();
Performance: Counting is efficient but avoid unnecessary traversals; combine filters into a single pipeline.
14. How do you convert a list to a map using streams?
Use Collectors.toMap()
to transform a stream into a map. Handle key collisions with a merge function and choose appropriate value mapping to avoid data loss.
Map<Integer, String> map = list.stream()
.collect(Collectors.toMap(
String::length,
Function.identity(),
(existing, replacement) => existing // resolve collisions
));
Advice: Ensure keys are deterministic and consider using composite keys for uniqueness.
15. How do you use reduce() in streams?
reduce()
folds elements into a single result using an associative accumulator. It’s useful for sums, concatenation, or combining objects when a simple collector isn’t available.
int sum = list.stream()
.reduce(0, Integer::sum);
Caution: For parallel streams, ensure the accumulator is associative and stateless for correct results.
Search
Categories
Recent Posts
Top Git interview Questions for Experienced Developer
Speed-up tips and tricks for Windows 11
Top 15 Linux Commands used by Experienced Developer
Top SQL Interview Examples for Experienced Developer
Internal Working of Java HashMap
Recent Tags