Tuesday, 21 October 2025

Java Interview Question : Comparable vs Comparator in Java Collection Framework– Key Difference Explained.

 When working with Java Collections Framework, sorting is one of the most common operations. Java provides two powerful interfaces — Comparable and Comparator — that help developers define custom sorting logic for objects.

In this article, we’ll understand both interfaces, their differences, and when to use which one — a very popular Core Java Interview Question.

1. Comparable Interface

The Comparable interface is used to define the default natural sorting order of objects.
A class implements this interface to specify how its objects should be compared to each other.

public interface Comparable<T> {

    public int compareTo(T obj);

}

Example:
class Student implements Comparable<Student> {
    int id;
    String name;

    public Student(int id, String name) {
        this.id = id;
        this.name = name;
    }

    // Defining natural sorting by id
    public int compareTo(Student s) {
        return this.id - s.id;
    }
}
Usage:
List<Student> list = new ArrayList<>();
list.add(new Student(3, "Amit"));
list.add(new Student(1, "Ravi"));
list.add(new Student(2, "Neha"));

Collections.sort(list); // uses compareTo()
Here, the sorting is based on the student id, which is the natural order.

2. Comparator Interface

The Comparator interface is used to define custom sorting logic outside the class.
This is useful when you want to sort objects in multiple different ways (e.g., by name, by id, etc.)

Syntax:

public interface Comparator<T> {

    public int compare(T obj1, T obj2);

}

Example:
class Student {
    int id;
    String name;

    public Student(int id, String name) {
        this.id = id;
        this.name = name;
    }
}

// Custom sorting by name
class NameComparator implements Comparator<Student> {
    public int compare(Student s1, Student s2) {
        return s1.name.compareTo(s2.name);
    }
}
Usage:
List<Student> list = new ArrayList<>();
list.add(new Student(3, "Amit"));
list.add(new Student(1, "Ravi"));
list.add(new Student(2, "Neha"));

Collections.sort(list, new NameComparator());

Java 8 Example using Lambda Expression

With Java 8, Comparator can be used in a more concise way:

Collections.sort(list, (s1, s2) -> s1.name.compareTo(s2.name));

Or simply:
list.sort(Comparator.comparing(Student::getName));

When to Use Which?

  • Use Comparable when you want natural sorting (e.g., sorting students by roll number).

  • Use Comparator when you want multiple sorting criteria (e.g., sort by name, then by marks, etc.).


Conclusion

Both Comparable and Comparator are essential for sorting custom objects in Java.

  • Comparable provides default natural order.

  • Comparator offers flexibility and customization for multiple sorting strategies.

By mastering these interfaces, you’ll be well-prepared for one of the most commonly asked Core Java interview questions.

Author:

Trilochan Tarai
Founder of java8s.com | Assistant Professor (CSE) at SoA University | Silan Software Pvt. Ltd.

Tuesday, 12 August 2025

Java String Handling Interview Question : What is the difference between String s1 = "Java"; and String s2 = new String("Java"); ?

 String s1 = "Java";

This creates a string literal. The JVM looks for "Java" in the String Constant Pool.

If it finds it, s1 will point to that existing string.

If not, it creates a new string "Java" in the pool and s1 will point to it.

String s2 = new String("Java");

This always creates a new String object in the heap memory, regardless of whether "Java" is in the pool or not.

Consider this code:

String s1 = "Java";

String s2 = "Java";

String s3 = new String("Java");

System.out.println(s1 == s2); // true (both point to the same object in the pool)

System.out.println(s1 == s3); // false (s3 is a new object in the heap)


Regards:

Trilochan Tarai

#Java #InterviewQuestions #StringHandling #CoreJava #SoftwareDevelopment #CodingInterview #TechJobs #JavaDeveloper #silansoftware #codeintervu


Monday, 16 June 2025

Most Commonly Java Interview Question in Java 8: What is Optional in Java 8?

 

Optional in Java 8:

In Java 8, Optional is a container object introduced in the java.util package. It is used to represent a value that can either be present (non-null) or absent (null). It provides a way to avoid NullPointerException (NPE) and improve code readability when dealing with nullable values.

Key Characteristics of Optional:

  1. Avoids Null Checks: Provides methods to handle nullable values without explicit null checks.
  2. Immutable: The Optional object is immutable, meaning its value cannot be changed once set.
  3. Improves Readability: It reduces boilerplate code and enhances readability when handling optional or nullable values.

Common Methods in Optional:

  1. Creating an Optional:
    • Optional.of(T value): Creates an Optional with a non-null value. Throws NullPointerException if the value is null.
    • Optional.ofNullable(T value): Creates an Optional that can hold a null or non-null value.
    • Optional.empty(): Returns an empty Optional.
  2. Checking for Value:
    • isPresent(): Returns true if a value is present, otherwise false.
    • isEmpty(): Returns true if no value is present, otherwise false.
  3. Retrieving the Value:
    • get(): Returns the value if present; otherwise, throws NoSuchElementException.
    • orElse(T other): Returns the value if present; otherwise, returns the provided default value.
    • orElseGet(Supplier<? extends T> supplier): Returns the value if present; otherwise, invokes the supplier and returns its result.
    • orElseThrow(Supplier<? extends X> exceptionSupplier): Returns the value if present; otherwise, throws an exception provided by the supplier.
  4. Processing the Value:
    • ifPresent(Consumer<? super T> action): Executes the given action if a value is present.
    • map(Function<? super T, ? extends U> mapper): Applies a mapping function if a value is present and returns a new Optional.
    • flatMap(Function<? super T, Optional<U>> mapper): Similar to map but avoids nested Optional.

Example Usage:

1.       Basic Usage

Optional<String> optional = Optional.ofNullable("Hello, World!");

 

if (optional.isPresent()) {

    System.out.println(optional.get()); // Output: Hello, World!

} else {

    System.out.println("No value present.");

}

2. Using orElse and ifPresent

Optional<String> optional = Optional.ofNullable(null);

 

// Using orElse

String result = optional.orElse("Default Value");

System.out.println(result); // Output: Default Value

 

// Using ifPresent

optional.ifPresent(value -> System.out.println("Value: " + value)); // Does nothing

 

3.      Using map and flatMap

Optional<String> optional = Optional.of("Hello");

 

Optional<Integer> lengthOptional = optional.map(String::length);

lengthOptional.ifPresent(System.out::println); // Output: 5

 

Benefits of Optional:

  1. Eliminates the risk of NullPointerException.
  2. Promotes functional programming by using methods like map, flatMap, and ifPresent.
  3. Makes the code more expressive and easier to understand.

 

Wednesday, 11 June 2025

Java Interview Question : JAVA Collection vs. Collections

 

java.util.Collection 

What it is: Collection is an interface that represents the root of the collection hierarchy in the Java Collections Framework. It defines the common behavior for a group of objects, known as its elements.

Purpose: It acts as a blueprint for all concrete collection types (like Lists, Sets, and Queues) that store individual elements. It specifies the basic operations that all collections should support.

import java.util.*;

public class CollectionExample {
    public static void main(String[] args) {
        Collection<String> names = new ArrayList<>(); // ArrayList implements List, which extends Collection
        names.add("Akshay");
        names.add("Ajay");
        names.add("Abhay");

        System.out.println("Collection elements: " + names); // Output: [Akshay, Ajay, Abhay]
       
        names.remove("Akshay");

        System.out.println("After removing Akshay: " + names); // Output: [Ajay, Abhay]

        System.out.println("Size: " + names.size()); // Output: 2
    }
}

java.util.Collections 

What it is: Collections is a utility class that provides static methods that operate on or return collections. It's like a helper class for the Collection interfaces and their implementations.

Purpose: It offers various polymorphic algorithms and utility methods that can be applied to Collection objects (or their sub-interfaces like List and Set). These methods include sorting, searching, shuffling, reversing, and creating thread-safe or unmodifiable versions of collections.

import java.util.*;

public class CollectionsExample {
    public static void main(String[] args) {

        List<Integer> numbers = new ArrayList<>();

        numbers.add(5);
        numbers.add(2);
        numbers.add(8);
        numbers.add(1);

        System.out.println("Original List: " + numbers); // Output: [5, 2, 8, 1]

        // Using Collections.sort()
        Collections.sort(numbers);
        System.out.println("Sorted List: " + numbers); // Output: [1, 2, 5, 8]

        // Using Collections.reverse()
        Collections.reverse(numbers);
        System.out.println("Reversed List: " + numbers); // Output: [8, 5, 2, 1]

        // Using Collections.max()
        System.out.println("Maximum element: " + Collections.max(numbers)); // Output: 8

        // Creating an unmodifiable list
        List<String> immutableList = Collections.unmodifiableList(List.of("apple", "banana"));

        // immutableList.add("orange"); // This would throw UnsupportedOperationException
        System.out.println("Immutable List: " + immutableList); // Output: [apple, banana]
    }
}

Monday, 10 March 2025

Java 8 Stream API MCQ for Interview

 Question: Which of the following operations is a terminal operation in Java 8 Stream API?

Options:

A. map()
B. filter()
C. collect()
D. flatMap()
Answer:
C. collect()
Explanation:
The collect() method is a terminal operation in the Stream API, used to transform the elements of a stream into a collection, list, or another data structure. Terminal operations produce a result or a side-effect and close the stream.