COFORGE Blog

Interview Experience At COFORGE

Based on the conversation, here are the questions the interviewer asked:

Suppose you have a string as a Neelabh. So you need to reverse the string using JDK 8 feature.

Suppose you have a string, say like same string. So you need to find out the count of each character. Like n is coming one time. 8 is coming two time. So you need to find out the count of each character using JDK 8 feature.

Suppose you have an employee table. Employee table has an employee id, employee name and employee salary. You need to find out the second highest salary from the employee table.

What is the diamond problem in Java? And how to overcome?

Can we make the constructor as a final, static, abstract and synchronized?

You have worked with JDK 8 version also. So what are the new features introduced in Java 8?

What is the difference between normal interface and functional interface?

Question : Can functional interface implement another functional interface?

A functional interface can extend another functional interface only if it does not declare any new abstract methods. This is because a functional interface is defined as an interface that has exactly one abstract method. If a functional interface were to declare a new abstract method, it would no longer be a functional interface.

Here’s an example:

Java
@FunctionalInterface
interface InterfaceA {
    void methodA();
}

@FunctionalInterface
interface InterfaceB extends InterfaceA {
    // No new abstract methods can be declared here
}

In this example, InterfaceB is a functional interface that extends another functional interface InterfaceA. It doesn’t declare any new abstract methods, so it’s still a functional interface. The method methodA() is the single abstract method for both InterfaceA and InterfaceB.

If InterfaceB were to declare a new abstract method, it would no longer be a functional interface, and you would get a compiler error.

Java
@FunctionalInterface
interface InterfaceA {
    void methodA();
}

@FunctionalInterface
interface InterfaceB extends InterfaceA {
    // It's okay to declare the same method from InterfaceA
    void methodA();
}

In this case, InterfaceB is simply redeclaring the method methodA() from InterfaceA. It doesn’t change the fact that InterfaceB is a functional interface, because there is still only one abstract method across InterfaceA and InterfaceB.

However, please note that redeclaring the method in InterfaceB is not necessary unless you want to provide a different Javadoc comment or annotation for that method in the context of InterfaceB. The method methodA() would be inherited from InterfaceA even if you didn’t redeclare it in InterfaceB.

What is the difference between comparator and comparable?

In Java, Comparable and Comparator are two interfaces used for comparing objects. Here’s how they differ:

Comparable: This interface is used to define the natural order of a class. If a class implements the Comparable interface, it means that objects of that class can be compared to each other. The Comparable interface has a single method, compareTo(), which takes another object of the same type and compares it to the current object. Here’s an example of a class implementing Comparable:

Java
public class Person implements Comparable<Person> {
    private String name;

    // constructor, getters and setters...

    @Override
    public int compareTo(Person other) {
        return this.name.compareTo(other.name);
    }
}

In this example, Person objects are compared based on their name property.

Comparator: This interface is used when you want to define multiple different ways to compare objects, or if you want to compare objects of a class that you do not have control over. The Comparator interface has a single method, compare(), which takes two objects and compares them. Here’s an example of a

Java
public class AgeComparator implements Comparator<Person> {
    @Override
    public int compare(Person p1, Person p2) {
        return Integer.compare(p1.getAge(), p2.getAge());
    }
}

In this example, the AgeComparator compares Person objects based on their age property.

In summary, use Comparable if you want to define a natural order for objects of a certain class, and use Comparator if you want to define other ways to compare objects or if you need to compare objects of a class that does not implement Comparable. Let me know if you have any other questions!

What is the difference between intermediate operation and terminal operation?

In Java’s Stream API, operations are categorized into two groups: intermediate operations and terminal operations. Here’s how they differ:

Intermediate Operations: These operations transform a stream into another stream. They are always lazy, meaning that they do not process the elements of the stream immediately. Instead, they record the operations to be performed and apply them only when a terminal operation is invoked on the stream. Examples of intermediate operations include filter(), map(), and sorted(). Here’s an example of intermediate operations:

List<String> names = Arrays.asList("John", "Jane", "Adam", "Eve"); Stream<String> stream = names.stream().filter(name -> name.startsWith("A")).map(String::toUpperCase);

In this example, filter() and map() are intermediate operations. They are not executed until a terminal operation is invoked on stream.

Terminal Operations: These operations produce a result or a side-effect. Invoking a terminal operation on a stream triggers the processing of the data and consumes the stream. After a terminal operation is invoked, the stream can no longer be used. Examples of terminal operations include forEach(), reduce(), collect(), and sum(). Here’s an example of a terminal operation: List<String> names = Arrays.asList("John", "Jane", "Adam", "Eve"); long count = names.stream().filter(name -> name.startsWith("A")).count(); In this example, count() is a terminal operation. It triggers the processing of the filter() operation and consumes the stream.

In summary, intermediate operations are used to set up a pipeline of operations on a stream, but they don’t actually process any data until a terminal operation is invoked.

What is Return Type of Intermediate Operation and Terminal Operation?

Return Type of Intermediate

Intermediate operations in Java’s Stream API return another Stream. This allows the operations to be connected or chained together. Here are some examples:

map: Transforms the elements of the stream by applying a function to each element. Returns a Stream consisting of the results of applying the function to the elements of this stream.

Java
Stream<String> stream = Stream.of("a", "b", "c");
Stream<String> upperCaseStream = stream.map(String::toUpperCase);

filter: Filters elements of the stream based on a predicate (a boolean-valued function). Returns a Stream consisting of the elements of this stream that match the given predicate.

Java
Stream<String> stream = Stream.of("a", "b", "c");
Stream<String> aStream = stream.filter(s -> s.equals("a"));

sorted: Returns a Stream consisting of the elements of this stream, sorted according to natural order. If the elements of this stream are not Comparable, a java.lang.ClassCastException may be thrown when the terminal operation is executed.

Java
Stream<String> stream = Stream.of("c", "a", "b");
Stream<String> sortedStream = stream.sorted();

In each of these examples, the intermediate operation returns a new Stream that you can further process with other intermediate operations or with a terminal operation. This is what enables the fluent functional programming style that you can use with the Stream API.

Return Type of Terminal

Terminal operations in Java’s Stream API can return different types of results depending on the operation. Here are some examples:

  • Collection: The collect() operation is used to receive elements from a stream and store them in a collection. For example:
    List<String> list = stream.collect(Collectors.toList());
    In this example, collect() returns a List<String>.
  • Optional: The findAny(), findFirst(), max(), and min() operations return an Optional that may or may not contain a value. For example:
    Optional<String> optional = stream.findAny();
    In this example, findAny() returns an Optional<String>.
  • Primitive: The count(), sum(), average(), summaryStatistics() operations return a primitive value (long, int, double, IntSummaryStatistics, etc.). For example:
    long count = stream.count();
    In this example, count() returns a long.
  • Array: The toArray() operation returns an array containing the elements of the stream. For example:
    Object[] array = stream.toArray();
    In this example, toArray() returns an Object[].
  • Boolean: The anyMatch(), allMatch(), and noneMatch() operations return a boolean indicating whether some or all elements of the stream match a given predicate. For example: boolean anyMatch = stream.anyMatch(e -> e.startsWith("A"));
    In this example, anyMatch() returns a boolean.
  • Void: The forEach() operation returns void. It’s used for performing an action on each element of the stream. For example: stream.forEach(e -> System.out.println(e)); In this example, forEach() returns void.

Remember, once a terminal operation is invoked on a stream, the stream is consumed and can no longer be used.

You have worked with a Spring framework also? Can you give me some annotation which you have used?

What is the difference between controller and REST controller?

What is the use of actuator in Spring Boot?

You have worked with microservices also? How many hours of experience do you have in microservices?

What is the difference between primary key, foreign key and unique key?

Avatar

Neelabh

About Author

As Neelabh Singh, I am a Senior Software Engineer with 6.6 years of experience, specializing in Java technologies, Microservices, AWS, Algorithms, and Data Structures. I am also a technology blogger and an active participant in several online coding communities.

You may also like

Blog Design Pattern

Understanding the Builder Design Pattern in Java | Creational Design Patterns | CodeTechSummit

Overview The Builder design pattern is a creational pattern used to construct a complex object step by step. It separates
Blog Tech Toolkit

Base64 Decode

Base64 encoding is a technique used to encode binary data into ASCII characters, making it easier to transmit data over