Top 30 Java-8 Interview Questions & Answers to Ace Your Java Interview

Greetings, readers! In this article, I present a compilation of crucial Java 8 interview questions that can significantly contribute to your success in a Java development interview. These questions cover both standard and coding inquiries commonly encountered during interviews. By thoroughly reviewing and understanding these questions, you’ll be well-prepared to excel in your Java interview. Let’s delve into the details.

Ajay Rathod
23 min readJan 24, 2024

Are you preparing for a job interview as a Java developer?

Find my book Guide To Clear Java Developer Interview here Gumroad (PDF Format) and Amazon (Kindle eBook).

Guide To Clear Spring-Boot Microservice Interview here Gumroad (PDF Format) and Amazon (Kindle eBook).

Download the sample copy here: Guide To Clear Java Developer Interview[Free Sample Copy]

Guide To Clear Spring-Boot Microservice Interview[Free Sample Copy]

What are the features of Java 8 and Java 11?

Java 8 was a major release of the Java programming language and platform, and it introduced several new features and improvements. Some of the most notable features of Java 8 include:

Lambda expressions: A way to define and pass around blocks of code as if they were objects, which allows for more concise, functional-style code.

Functional interfaces: Interfaces that have exactly one abstract method, which allows for behavior parameterization and the ability to pass behavior as a method argument.

Streams: A new API for processing collections of data that allows for operations such as filtering, mapping, and reducing to be performed in a more functional and readable way.

Date and time API: A new API for working with date and time, which replaces the legacy java.util.Date and java.util.Calendar classes.

Concurrent Accumulators: A set of classes designed for use with parallel streams, which allow for the efficient accumulation of values.

Java 11, released in 2018, is a long-term support release and it brings several important changes and improvements over Java 8. Some of the most notable features of Java 11 include:

Local-variable type inference: A new syntax that allows you to infer the type of a variable from the value being assigned to it, which can make your code more readable and concise.

What are lambda expressions and their use in Java-8?

Lambda expressions are a new feature introduced in Java 8 that allow developers to write more concise, functional-style code. They are a way to define and pass around blocks of code as if they were objects.

A lambda expression is composed of three parts:

A list of parameters (or none) enclosed in parentheses.

The “arrow” token ->

The body of the lambda expression, which can be a single expression or a block of code.

Here is an example of a simple lambda expression that takes two integers and returns their sum:

(int a, int b) -> {return a + b; }

Lambda expressions can be used to define functional interfaces, which are interfaces that have a single abstract method. The java.util.function package in Java 8 includes several functional interfaces such as Consumer, Function, Predicate, and Supplier.

Lambda expressions can also be passed to methods or used as arguments for functional interfaces. For example, the forEach method of the java.util.stream.Stream class takes a Consumer functional interface as an argument, allowing you to pass in a lambda expression to perform a specific action on each element in the stream.

Lambda expressions can also be used with other features of Java 8 such as streams and the new date and time API to perform operations such as filtering, mapping, and reducing collections of data, in a more functional and readable way.

It’s worth noting that, although lambda expressions can help make your code more concise and readable, they can also make it more difficult to understand if they are not used correctly. It’s important to use them in a way that makes the code easy to understand and maintain.

What are the Java 8 Interface changes?

Java 8 introduced several changes to the way interfaces work, including the addition of default methods and static methods. These changes were made to allow interfaces to provide more functionality and to make it easier to add new methods to existing interfaces without breaking existing code.

Default methods: Java 8 introduced the concept of default methods, which are methods that have a default implementation in an interface. This allows interfaces to provide a default implementation for methods, without requiring the classes that implement the interface to provide one.

Static methods: Java 8 also introduced the ability for interfaces to have static methods, which are methods that can be called on the interface itself, rather than on an instance of the interface.

Functional interface: Java 8 also introduced a functional interface, an interface that has exactly one abstract method. This is used to create lambda expressions, which are used to implement the single abstract method of the functional interface.

Private methods: Java 9 introduced the ability to define private methods within interfaces. This feature allows the interfaces to have more encapsulation and organization and allows the interface to provide more functionality.

These changes to interfaces in Java 8 and later have made it possible to add new functionality to existing interfaces in a backward-compatible way, and have also made it easier to create more functional and modular code.

What is a Functional interface in Java-8?

In Java 8, a functional interface is an interface that has exactly one abstract method. The “functional” in the name refers to the fact that the interface can be used as the target of a lambda expression or method reference.

Functional interfaces are also known as Single Abstract Method Interfaces or SAM Interfaces. A functional interface can have any number of default and static methods.

Functional interfaces are annotated with @FunctionalInterface annotation.

The main use of functional interfaces is to create lambda expressions, which are used to implement the single abstract method of the functional interface.

For example,

@FunctionalInterface
interface MyFunctionalInterface {
public void myMethod();
}

This is a functional interface because it has only one abstract method, myMethod().

A functional interface can be implemented using a lambda expression, like this:

MyFunctionalInterface myObject = () -> {
// code here
};

Java 8 library has many functional interfaces such as:

java.util.function.Function<T,R>: Represents a function that takes an argument of type T and returns an argument of type R.

java.util.function.Consumer<T>: Represents an operation that takes a single input argument and returns no result.

java.util.function.Predicate<T>: Represents a predicate (boolean-valued function) of one argument.

java.util.function.Supplier<T>: Represents a supplier of results.

The above are examples of functional interfaces that are widely used in the Java 8 Stream API and other functional programming constructs in Java 8.

What are the types of Functional interfaces?

There are several types of functional interfaces in Java 8, each with a specific purpose. Some of the most commonly used functional interfaces include:

Consumer<T>: Represents an operation that takes a single input argument and returns no result. This interface is typically used to perform some operation on an object, such as printing it to the console.

Supplier<T>: Represents a supplier of results. This interface is typically used to create a new object or retrieve a value from a data source.

Predicate<T>: Represents a predicate (boolean-valued function) of one argument. This interface is typically used to test a condition and return a boolean value.

Function<T, R>: Represents a function that takes an argument of type T and returns an argument of type R. This interface is typically used to transform an object from one type to another.

UnaryOperator<T>: Represents an operation on a single operand that produces a result of the same type as its operand. It is a specialization of Function for the case where the operand and result are of the same type.

BinaryOperator<T>: Represents an operation upon two operands of the same type, producing a result of the same type as the operands.

BiConsumer<T, U>: Represents an operation that accepts two input arguments and returns no result.

BiFunction<T, U, R>: Represents a function that takes two arguments and produces a result.

BiPredicate<T, U>: Represents a predicate (boolean-valued function) of two arguments.

Runnable: Represents a command that can be executed.

These are some of the most common functional interfaces, but there are many others in the Java standard library, each with its own specific use case.

What is Method Reference in Java-8?

In Java 8, a method reference is a shorthand notation for a lambda expression that simply invokes an existing method. The basic syntax for a method reference is:

ClassName::methodName

For example, if you have a class called “MyClass” with a method called “myMethod”, you could use a method reference to invoke that method like this:

MyClass::myMethod

You can also use method references with constructors and array constructors. The basic syntax for a constructor reference is:

ClassName::new

For example, if you have a class called “MyClass”, you could use a constructor reference to create a new instance of that class like this:

MyClass::new

And the basic syntax for a array constructor reference is:

TypeName[]::new

For example, if you want to create an array of integers, you could use an array constructor reference like this:

int[]::new

Method references can be used in situations where a lambda expression would be used to invoke an existing method, such as when passing a method as an argument to a higher-order function.

What is Optional in Java-8?

In Java, the Optional class is a container object that may or may not contain a non-null value. It is introduced in Java 8 as a part of the java.util package. It is used to represent a value that may not be present and to prevent null pointer exceptions.

The main methods of the Optional class are:

of(T value): Creates an Optional instance with the given non-null value.

ofNullable(T value): Creates an Optional instance with the given value, which can be null.

empty(): Creates an empty Optional instance.

isPresent(): Returns true if the Optional contains a value, false otherwise.

get(): Returns the contained value, if present. If the Optional is empty, it throws a NoSuchElementException.

orElse(T other): Returns the contained value if present, otherwise returns the given default value.

orElseGet(Supplier<? extends T> supplier): Returns the contained value if present, otherwise returns the result of the given supplier function.

orElseThrow(Supplier<? extends X> exceptionSupplier): Returns the contained value if present, otherwise throws the exception provided by the given supplier function.

ifPresent(Consumer<? super T> consumer): If a value is present, invoke the specified consumer with the value, otherwise do nothing.

It is best practice to use Optional when the return type of a method can return null as it forces to handle the null case explicitly.

For example,

Optional<String> optional = Optional.ofNullable(null);
if(optional.isPresent()) {
System.out.println(optional.get());
} else {
System.out.println("No value");
}

In this example, the value of the optional is null, so the output would be “No value”.

What are the Intermediate and terminal operations in Java-8?

In Java 8, the Stream API is used to process collections of data in a functional manner. The Stream API provides two types of operations: intermediate and terminal.

Intermediate operations are operations that are performed on a stream, but do not produce a final result. They are used to transform the elements of a stream in some way, and return a new stream that contains the transformed elements. Examples of intermediate operations include filter, map, and flatMap.

Terminal operations are operations that produce a final result or a side-effect. They are used to consume the elements of a stream and produce a final result, such as a count, a sum, or a list. Examples of terminal operations include forEach, reduce, and collect.

Intermediate operations are lazy, meaning that they are not executed until a terminal operation is called. This allows multiple intermediate operations to be chained together, with the result of one operation being passed as the input to the next.

For example,

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
int sum = numbers.stream()
.filter(n -> n % 2 == 0)
.map(n -> n * 2)
.reduce(0, Integer::sum);

In this example, the filter is an intermediate operation that filters the stream of numbers to keep only even numbers. map is an intermediate operation that transforms each number in the stream by doubling it. reduce is a terminal operation that sums the numbers in the stream and returns the result.

It is important to note that once a terminal operation is called, the stream is considered consumed and it can’t be reused.

What is parallel processing in Java-8, and what are its uses?

Parallel processing in Java 8 refers to the ability to perform operations on a stream in parallel, using multiple threads. The Java 8 Stream API provides the parallel() method, which can be used to create a parallel stream from an existing sequential stream.

A parallel stream automatically splits the data into smaller chunks and assigns each chunk to a separate thread for processing. The results from each thread are then combined to produce the final result.

Parallel processing can be useful for improving the performance of certain types of operations, such as filtering and mapping, on large data sets. It can also be used to perform complex computations in parallel, such as reducing a large data set to a single value.

For example,

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
int sum = numbers.parallelStream().mapToInt(Integer::intValue).sum();

In this example, the parallelStream() method is used to create a parallel stream of the numbers, and the mapToInt() and sum() methods are used to calculate the sum of the numbers in parallel.

It’s important to note that parallel processing may not always be beneficial and it is dependent on the size of data and nature of operation. It’s always good to check the performance of the operation in both parallel and sequential mode and compare the results.

Difference between Flat and flat-map methods in Java-8?

flatMap is a method in Java Streams that is used to convert a stream of collections or arrays into a single flattened stream. In contrast, the flat method is not a standard method in Java Streams.

Here is an example of using flatMap to flatten a stream of collections:

List<List<Integer>> nestedList = Arrays.asList(
Arrays.asList(1, 2),
Arrays.asList(3, 4),
Arrays.asList(5, 6)
);
List<Integer> flattenedList = nestedList.stream()
.flatMap(Collection::stream)
.collect(Collectors.toList());
System.out.println(flattenedList); // Output: [1, 2, 3, 4, 5, 6]

In this example, we start with a List of List objects. We use the flatMap method to convert each inner List into a stream of integers, and then concatenate all the streams into a single stream of integers. Finally, we collect the resulting stream into a new List object.

The flat method, on the other hand, is not a standard method in Java Streams. It may be implemented as a custom method or library method, but its behavior would depend on the implementation.

What is the default method and its uses?

A default method is a method defined in an interface that has a default implementation. Default methods were introduced in Java 8 to allow interfaces to be extended without breaking existing implementations.

Before Java 8, interfaces could only contain method signatures, which meant that any class that implemented an interface was required to provide an implementation for all of its methods. This could be problematic when you want to add new methods to an existing interface because it would break all of the existing implementations.

With default methods, you can provide a default implementation for a method in an interface, which means that classes that implement the interface are not required to provide their own implementation. If a class does not provide its own implementation for a default method, it will use the default implementation defined in the interface.

Default methods are useful for extending existing interfaces without breaking existing implementations. They can also be used to provide a common implementation for a method that is applicable to all classes that implement the interface.

For example, consider an interface for a collection of items:

public interface Collection<T> {
void add(T item);
boolean contains(T item);
int size();
default boolean isEmpty() {
return size() == 0;
}
}

This interface defines three methods for adding items to the collection, checking if an item is contained in the collection, and getting the size of the collection. It also defines a default method, isEmpty(), that returns true if the size of the collection is 0.

Classes that implement this interface are not required to provide their own implementation for isEmpty(), because a default implementation is already provided in the interface. However, they can override the default implementation if they need to provide a different behavior.

What are default and static methods in Java-8?

Default and static methods are two new features that were introduced in Java 8.

Default methods allow you to add new methods to interfaces without breaking existing code. This is done by providing a default implementation of the method in the interface. Classes that implement the interface can override the default implementation, or they can simply use the default implementation.

example of a default method:

public interface Animal {
default void eat() {
System.out.println("I am eating.");
}
}

Any class that implements the Animal interface will have access to the eat() method, even if the class does not explicitly implement the eat() method.

Static methods are methods that can be declared in interfaces. Static methods belong to the interface itself, not to any specific instance of the interface. Static methods can be called without creating an instance of the interface.

public interface Animal {
static void makeSound() {
System.out.println("I am making a sound.");
}
}

The makeSound() method can be called without creating an instance of the Animal interface:

Animal.makeSound(); // prints “I am making a sound.”

Default and static methods can be used to improve the design of Java applications in a number of ways. For example, default methods can be used to add new functionality to existing interfaces, and static methods can be used to provide utility methods that are available to all classes that implement a particular interface.

What are the memory changes that happened in Java-8?

The following are some of the memory changes that happened in Java 8:

Metaspace: Java 8 introduced Metaspace to replace PermGen. Metaspace is a region of memory that is used to store class metadata, such as class names, field and method names, and method bytecode. Metaspace is part of the native memory heap, which means that it is not limited by the maximum heap size.

G1 garbage collector: Java 8 introduced the G1 garbage collector as the default garbage collector. The G1 garbage collector is a concurrent garbage collector, which means that it can collect garbage while the application is still running. This can improve the performance of applications that have large heaps.

CompressedOops: Java 8 introduced CompressedOops, which is a technique that can reduce the memory footprint of Java objects. CompressedOops works by compressing object pointers from 64 bits to 32 bits on 64-bit platforms. This can reduce the memory footprint of Java objects by up to 50%.

String deduplication: Java 8 introduced String deduplication, which is a technique that can reduce the memory footprint of String objects. String deduplication works by storing a single copy of each unique String object in memory. This can reduce the memory footprint of String objects by up to 50%.

Overall, the memory changes in Java 8 have made Java applications more memory-efficient. This is important for applications that run on devices with limited memory, such as mobile devices and embedded systems.

What are the new Java-8 changes in HashMap?

Java 8 made the following changes to HashMap:

The new hash function for Strings: Java 8 introduced a new hash function for Strings that is more resistant to hash collisions. This can improve the performance of HashMap when it is used to store Strings.

Treeification: Java 8 added a new feature called “treeification” to HashMap. Treeification automatically converts a linked list of entries in a bucket to a red-black tree when the number of entries in the bucket exceeds a certain threshold. This can improve the performance of HashMap when there are a large number of hash collisions.

ConcurrentHashMap: Java 8 introduced a new concurrent implementation of HashMap called ConcurrentHashMap. ConcurrentHashMap is designed to be safe for concurrent access by multiple threads.

Why variable inside the lambda function is final in Java-8?

Variables inside lambda functions are final in Java because it help to prevent concurrency problems. Lambda functions are often used to capture variables from the surrounding scope. If these variables were not final, then it would be possible for multiple threads to modify the variables at the same time, which could lead to unexpected results.

int x = 0;
Runnable runnable = () -> {
x++; // This would cause a concurrency problem if multiple threads were executing this lambda function at the same time.
};
Thread thread1 = new Thread(runnable);
Thread thread2 = new Thread(runnable);
thread1.start();
thread2.start();

If the x variable were not final, then it is possible that both threads would increment the x variable at the same time, and the final value of x would be unpredictable.

By making variables inside lambda functions final, Java can ensure that these variables cannot be modified by multiple threads at the same time. This helps to prevent concurrency problems and makes Java code more robust.

Here is an example of how to use a lambda function without causing a concurrency problem:

int x = 0;
Runnable runnable = () -> {
// This is safe because the variable x is final.
int y = x + 1;
System.out.println(y);
};
Thread thread1 = new Thread(runnable);
Thread thread2 = new Thread(runnable);
thread1.start();
thread2.start();

In this example, the x variable is final, so it cannot be modified by multiple threads at the same time. This ensures that both threads will read the same value for the x variable, and the output of the program will be predictable.

Overall, making variables inside lambda functions final is a good practice that can help to prevent concurrency problems and make Java code more robust.

Coding

Write a Program to find the duplicates in an array using stream API.

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class DuplicateFinder {
public static void main(String[] args) {
int[] arr = {1, 2, 3, 1, 2, 4, 5};
List<Integer> list = Arrays.stream(arr)
.boxed()
.collect(Collectors.toList());
list.stream()
.filter(i -> Collections.frequency(list, i) > 1)
.distinct()
.forEach(System.out::println);
}
}

How to sort the employee list in ascending and descending order using Java-8 streams API?

You can use the sorted method of the Stream API in Java 8 to sort a list of employees in ascending or descending order. By default, the sorted method sorts the elements in the stream in natural order, which means that it uses the elements’ compareTo method if the elements are Comparable, or it throws a ClassCastException if they are not.

Here’s an example of how you can sort a list of employees in ascending order based on their salary:

List<Employee> employees = getEmployeeList(); // get the list of employees
employees.stream()
.sorted(Comparator.comparing(Employee::getSalary))
.forEach(System.out::println);

Here’s an example of how you can sort the same list in descending order based on the employee’s name:

employees.stream()
.sorted(Comparator.comparing(Employee::getName).reversed())
.forEach(System.out::println);

Note that the reversed method on the comparator returns a comparator that gives the opposite ordering of the original comparator.

Find the highest salary of an employee from the HR department using Java stream API.

You have been given an employee list with EMP<Id, Name, Salary, Deptt>, and

You can use the filter and max methods of the Stream API in Java 8 to find the highest salary of an employee from the HR department. Here’s an example:

List<Employee> employees = getEmployeeList(); // get the list of employees
Optional<Employee> highestPaidHrEmployee = employees.stream()
.filter(e -> "HR".equals(e.getDeptt()))
.max(Comparator.comparing(Employee::getSalary));
if (highestPaidHrEmployee.isPresent()) {
System.out.println("The highest paid HR employee is: " + highestPaidHrEmployee.get().getName());
} else {
System.out.println("No HR employees found in the list.");
}

In this example, the filter method is used to select only the employees from the HR department, and the max method is used to find the employee with the highest salary. The max method returns an Optional object that may or may not contain the maximum value, depending on whether the stream is empty or not. So we use the isPresent method to check if a value was found before accessing it.

Find all employees who live in ‘Pune’ city, sort them by their name, and print the names of employees using Stream API.

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
public class Employee {
private String name;
private String city;
public Employee(String name, String city) {
this.name = name;
this.city = city;
}
public String getName() {
return name;
}
public String getCity() {
return city;
}
public static void main(String[] args) {
// Creating a list of employees
List<Employee> employees = new ArrayList<>();
employees.add(new Employee("John Smith", "New York"));
employees.add(new Employee("Jane Doe", "Chicago"));
employees.add(new Employee("Bob Johnson", "Pune"));
employees.add(new Employee("Sarah Lee", "Pune"));
// Filtering and sorting employees who live in Pune
List<Employee> puneEmployees = employees.stream()
.filter(e -> e.getCity().equals("Pune"))
.sorted(Comparator.comparing(Employee::getName))
.toList();
// Printing the names of employees who live in Pune
System.out.println("Employees who live in Pune:");
puneEmployees.stream()
.map(Employee::getName)
.forEach(System.out::println);
}
}

The code uses the filter method to filter out employees who live in Pune, then the sorted method to sort them by name, and finally, the map method to extract the names of the employees. The toList method is used to convert the filtered and sorted stream of employees to a list.

The output of the code would be:

Employees who live in Pune:

Bob Johnson

Sarah Lee

Find an average of even numbers using Java using Java 8 stream API.

import java.util.Arrays;
public class AverageOfEvenNumbersExample {
public static void main(String[] args) {
int[] numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
double average = Arrays.stream(numbers)
.filter(n -> n % 2 == 0)
.mapToDouble(n -> n)
.average()
.orElse(0.0);
System.out.println("The average of even numbers is " + average);
}
}

In this example, we define an array of numbers with some integers. We then use the Arrays.stream method to create a stream of integers from the array. We filter out the even numbers using the filter method, which takes a predicate that returns true for even numbers. We then use the mapToDouble method to convert the Stream<Integer> to an DoubleStream. We use the average method to get the average of the even numbers. If there are no even numbers in the array, we use the orElse method to return a default value of 0.0.

The output of this program for the array {1, 2, 3, 4, 5, 6, 7, 8, 9, 10} would be:

The average of even numbers is 5.0

How to use sorting in Java-8?

In Java 8, you can use the sorted method of the Stream API to sort elements in a collection. By default, the sorted method sorts elements in their natural order, but you can also provide a Comparator to specify the sort order.

Here’s an example of how you can sort a list of integers in ascending order using the sorted method:

List<Integer> numbers = Arrays.asList(3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5);
numbers.stream()
.sorted()
.forEach(System.out::println);

Here’s an example of how you can sort a list of strings in descending order based on their length:

List<String> words = Arrays.asList("apple", "banana", "cherry", "date", "elderberry");
words.stream()
.sorted(Comparator.comparingInt(String::length).reversed())
.forEach(System.out::println);

In this example, we use the Comparator.comparingInt method to create a comparator that compares strings based on their length, and then we use the reversed method to reverse the sort order.

Note that the sorted method returns a new stream with the elements sorted in the specified order, and it does not modify the original stream or collection.

Find the employee count in each department in the employee list using Java 8 Stream API.

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class Employee {
private String name;
private String department;
public Employee(String name, String department) {
this.name = name;
this.department = department;
}
public String getName() {
return name;
}
public String getDepartment() {
return department;
}
}
public class FindEmployeeCountByDepartment {
public static void main(String[] args) {
List<Employee> employees = Arrays.asList(
new Employee("Alice", "Engineering"),
new Employee("Bob", "Sales"),
new Employee("Carol", "Engineering"),
new Employee("Dave", "Marketing"),
new Employee("Eve", "Sales")
);
// Create a stream of the employee list.
Stream<Employee> employeeStream = employees.stream();
// Group the employees by department.
Map<String, Long> employeeCountByDepartment = employeeStream
.collect(Collectors.groupingBy(Employee::getDepartment, Collectors.counting()));
// Print the results.
System.out.println(employeeCountByDepartment);
}
}

Output : {Engineering=2, Sales=2, Marketing=1}

Find employees based on location or city and sort in an alphabetical manner using stream API.

(like a-z and each city employee’s salary should be sorted from max to min salary)

import java.util.*;
import java.util.stream.Collectors;
public class EmployeeFilter {
public static void main(String[] args) {
List<Employee> employees = Arrays.asList(
new Employee("John", "New York", 5000),
new Employee("Jane", "New York", 6000),
new Employee("Bob", "Chicago", 4500),
new Employee("Alice", "Chicago", 5500),
new Employee("Sam", "San Francisco", 7000),
new Employee("Emily", "San Francisco", 6500)
);
String location = "Chicago";
List<Employee> filteredEmployees = employees.stream()
.filter(e -> e.getLocation().equals(location))
.sorted(Comparator.comparing(Employee::getName).thenComparing(Employee::getSalary, Comparator.reverseOrder()))
.collect(Collectors.toList());
System.out.println("Filtered employees: " + filteredEmployees);
}
static class Employee {
private final String name;
private final String location;
private final int salary;
public Employee(String name, String location, int salary) {
this.name = name;
this.location = location;
this.salary = salary;
}
public String getName() {
return name;
}
public String getLocation() {
return location;
}
public int getSalary() {
return salary;
}
@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", location='" + location + '\'' +
", salary=" + salary +
'}';
}
}
}

In this program, we first define a List of Employee objects with some elements, where each employee has a name, a location (city), and a salary.

We then define a location variable to filter the employees based on the given location.

We use a stream to filter the employees based on the given location using the filter() method, and then sort them in alphabetical order by name using the sorted() method with Comparator.comparing(Employee::getName). Finally, we sort each city employee’s salary from highest to lowest using the sorted() method with Comparator.comparing(Employee::getSalary).reversed().

We collect the filtered and sorted employees into a list using the collect() method with Collectors.toList(), and print the result using the System.out.println() statement.

Filtered employees: [Employee{name=’Alice’, location=’Chicago’, salary=5500}, Employee{name=’Bob’, location=’Chicago’, salary=4500}]

Find the occurrence of names of employees from the List<Employee>, and find the frequency of each name.

import java.util.*;
public class EmployeeNameFrequency {
public static void main(String[] args) {
List<Employee> employees = Arrays.asList(
new Employee("John", "New York", 5000),
new Employee("Jane", "New York", 6000),
new Employee("Bob", "Chicago", 4500),
new Employee("Alice", "Chicago", 5500),
new Employee("Sam", "San Francisco", 7000),
new Employee("Emily", "San Francisco", 6500),
new Employee("John", "Chicago", 5500),
new Employee("Jane", "San Francisco", 6500),
new Employee("Bob", "San Francisco", 7000)
);
Map<String, Integer> nameFrequencyMap = new HashMap<>();
for (Employee employee : employees) {
String name = employee.getName();
nameFrequencyMap.put(name, nameFrequencyMap.getOrDefault(name, 0) + 1);
}
System.out.println("Name frequency: " + nameFrequencyMap);
}
static class Employee {
private final String name;
private final String location;
private final int salary;
public Employee(String name, String location, int salary) {
this.name = name;
this.location = location;
this.salary = salary;
}
public String getName() {
return name;
}
public String getLocation() {
return location;
}
public int getSalary() {
return salary;
}
@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", location='" + location + '\'' +
", salary=" + salary +
'}';
}
}
}

We then define a nameFrequencyMap map to store the frequency of each name.

We iterate over the employees using a for-each loop, and for each employee, we extract the name using the getName() method. We then put the name in the nameFrequencyMap map and increment its frequency using nameFrequencyMap.getOrDefault(name, 0) + 1.

Finally, we print the nameFrequencyMap map using the System.out.println() statement.

The output of the above program would be:

Name frequency: {Bob=2, Emily=1, Alice=1, Sam=1, Jane=2, John=2}

Write a Program to print only numbers from an alphanumeric char array using stream API in java-8.

import java.util.Arrays;
public class AlphanumericFilterExample {
public static void main(String[] args) {
String str = "a1b2c3d4e5f6g7h8i9j0";
char[] arr = str.toCharArray();
System.out.println("Original array: " + Arrays.toString(arr));
int[] nums = new String(arr)
.chars()
.filter(Character::isDigit)
.map(Character::getNumericValue)
.toArray();
System.out.println("Numbers only: " + Arrays.toString(nums));
}
}

character array. Then we create a stream from the characters of the string, filter only the numeric characters using the isDigit method of the Character class, convert the character to a numeric value using the getNumericValue method, and finally convert the result to an int array using the toArray method.

Original array: [a, 1, b, 2, c, 3, d, 4, e, 5, f, 6, g, 7, h, 8, i, 9, j, 0]

Numbers only: [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]

Write a program to find the sum of the entire array result using Java 8 streams.

import java.util.Arrays;
public class ArraySum {
public static void main(String[] args) {
int[] arr = {1, 2, 3, 4, 5};
int sum = Arrays.stream(arr).sum();
System.out.println("Sum of array elements: " + sum);
}
}

In this program, we first define an integer array arr with some elements. Then we use the Arrays.stream() method to create a stream of integers from the array, and then we call the sum() method on the stream to find the sum of all the elements in the array.

Finally, we print the sum using the System.out.println() statement.

Write a program to find even numbers from a list of integers and multiply with 2 using stream java 8.

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class EvenNumbers {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
List<Integer> evenNumbersDoubled = numbers.stream()
.filter(n -> n % 2 == 0)
.map(n -> n * 2)
.collect(Collectors.toList());
System.out.println("Even numbers doubled: " + evenNumbersDoubled);
}
}

In this program, we first define a list of integer numbers with some elements. Then we create a stream of integers from the list using the stream() method on the list.

We then use the filter() method on the stream to filter out all the odd numbers, and then use the map() method to multiply each even number by 2.

Finally, we collect the result of the stream into a list using the collect() method with Collectors.toList() and print the result using the System.out.println() statement.

The output of the above program would be:

Even numbers doubled: [4, 8, 12, 16, 20]

Above all Questions came straight from interview, by preparing them we can easily clear Java-8 topic interview.

Thanks for reading

  • 👏 Please clap for the story and follow me 👉
  • 📰 Read more content on my Medium (50 stories on Java Developer interview)

Find my books here:

--

--

Ajay Rathod

Software Engineer @Cisco | Java Programmer | AWS Certified | Writer | Find My Books on Java Interview here - https://rathodajay10.gumroad.com/