Popular Searches
Popular Course Categories
Popular Courses

Preparing Exception Handling, Collections, and Generics Interview Questions

Preparing Exception Handling, Collections, and Generics Interview Questions

Core Java Projects, Interview Preparation, and Career Readiness

Preparing Exception Handling, Collections, and Generics Interview Questions

Course: Core Java Training

Topic: Exception Handling, Collections Framework, and Generics Interview Preparation

Course Link: Core Java Training at JustAcademy

Demo Link: Register for a Free Course Demo

JustAcademy Homepage: Visit JustAcademy


1. Introduction

Exception handling, the Collections Framework, and Generics are important areas of Core Java interviews. Interviewers use these topics to evaluate a candidate's understanding of error management, data storage, object-oriented programming, type safety, and writing maintainable Java applications.

Exception handling helps applications respond to unexpected situations without terminating unnecessarily. Collections provide reusable data structures for storing and processing groups of objects. Generics enable classes, interfaces, and methods to work with different data types while maintaining compile-time type safety.

This guide covers fundamental concepts, frequently asked interview questions, practical Java programs, common mistakes, scenario-based questions, and revision exercises.

2. Learning Objectives

  • Understand Java exceptions, their hierarchy, and the difference between checked and unchecked exceptions.
  • Explain try, catch, finally, throw, and throws.
  • Choose appropriate collection implementations for different requirements.
  • Compare List, Set, Queue, and Map.
  • Understand iteration, sorting, equality, hashing, and concurrent modification.
  • Explain generic classes, generic methods, bounded type parameters, wildcards, and type erasure.
  • Answer common conceptual, coding, and scenario-based interview questions.

3. Exception Handling in Java

3.1 What Is an Exception?

An exception is an event that interrupts the normal flow of a program. It can occur because of invalid input, an unavailable file, an illegal operation, or an attempt to access an array outside its valid range.

Java represents exceptions and errors using classes derived from Throwable.

class ExceptionDemo {
    public static void main(String[] args) {
        int a = 10;
        int b = 0;
        System.out.println(a / b);
    }
}

Expected result: The program throws an ArithmeticException because integer division by zero is invalid.

3.2 Java Exception Hierarchy

Object
  └── Throwable
       ├── Error
       └── Exception
            ├── RuntimeException
            └── Other checked exceptions
Type Description Examples
Error Serious JVM or environment-related problem that applications generally should not attempt to recover from routinely. OutOfMemoryError, StackOverflowError
Checked exception Compiler requires handling or declaration, except for unchecked exception types. IOException, SQLException
Unchecked exception Runtime exception that does not require a catch or declaration at compile time. NullPointerException, IllegalArgumentException

3.3 Checked vs. Unchecked Exceptions

Feature Checked Unchecked
Checked by compiler Yes, handling or declaration is required No
Typical cause Recoverable external operations, such as file access Programming errors or invalid runtime operations
Examples IOException, ClassNotFoundException NullPointerException, ArithmeticException
Handling approach Catch the exception or declare it using throws Fix the underlying cause; catch when recovery is meaningful

3.4 Using try and catch

The try block contains code that may throw an exception. A matching catch block handles a particular exception type.

public class TryCatchExample {
    public static void main(String[] args) {
        try {
            int result = 20 / 0;
            System.out.println(result);
        } catch (ArithmeticException e) {
            System.out.println("Cannot divide by zero.");
        }

        System.out.println("Program continues.");
    }
}

Output:

Cannot divide by zero.
Program continues.

Interview point: Catch specific exceptions where possible. Avoid catching broad types without a clear reason or silently ignoring failures.

3.5 Multiple catch Blocks

A single try block can have multiple catch blocks. Place more specific exception types before broader types because a broader catch placed first can make later catches unreachable.

try {
    String value = null;
    System.out.println(value.length());
} catch (NullPointerException e) {
    System.out.println("The value is null.");
} catch (RuntimeException e) {
    System.out.println("A runtime problem occurred.");
}

Java also supports multi-catch when different exception types need the same handling logic:

try {
    // Operation that may fail
} catch (IllegalArgumentException | IllegalStateException e) {
    System.out.println("Invalid operation: " + e.getMessage());
}

3.6 finally Block

The finally block is used for cleanup that should normally run whether the try block completes successfully or an exception is caught. It commonly appears in older code that manages resources manually.

try {
    System.out.println("Performing operation");
} catch (Exception e) {
    System.out.println("Handling exception");
} finally {
    System.out.println("Cleanup section");
}

The finally block usually executes, but it is not an absolute guarantee in situations such as abrupt JVM termination. For closing files and similar resources, prefer try-with-resources.

3.7 Difference Between throw and throws

throw throws
Actually throws a particular exception object. Declares exception types that a method may pass to its caller.
Used inside a method or block. Used in a method or constructor declaration.
Example: throw new IllegalArgumentException("Invalid age"); Example: void readFile() throws IOException
static void validateAge(int age) {
    if (age < 18) {
        throw new IllegalArgumentException("Age must be at least 18");
    }
}

3.8 Custom Exceptions

Create a custom exception when an application needs to represent a meaningful business-specific failure, such as an invalid account operation or unavailable inventory.

class InsufficientBalanceException extends Exception {
    public InsufficientBalanceException(String message) {
        super(message);
    }
}

class BankAccount {
    private double balance = 1000;

    public void withdraw(double amount)
            throws InsufficientBalanceException {
        if (amount <= 0) {
            throw new IllegalArgumentException(
                "Amount must be positive");
        }
        if (amount > balance) {
            throw new InsufficientBalanceException(
                "Insufficient account balance");
        }
        balance -= amount;
    }
}

Extending Exception creates a checked custom exception. Extending RuntimeException creates an unchecked custom exception. Choose based on the contract and recovery expectations of the application.

3.9 Try-with-resources

Try-with-resources automatically closes resources that implement AutoCloseable. It reduces cleanup code and helps prevent resource leaks.

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class ReadFileExample {
    public static void main(String[] args) {
        try (BufferedReader reader =
                 new BufferedReader(new FileReader("data.txt"))) {
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }
        } catch (IOException e) {
            System.out.println("Unable to read file: "
                               + e.getMessage());
        }
    }
}

The reader is closed automatically when execution leaves the try-with-resources statement. If both the main operation and resource closing fail, Java preserves the primary exception and records closing failures as suppressed exceptions.

3.10 Exception Handling Best Practices

  • Catch exceptions only when you can handle them, recover, add useful context, or translate them appropriately.
  • Do not use empty catch blocks that hide failures.
  • Prefer specific exception types over a generic Exception catch.
  • Do not use exceptions as a substitute for ordinary control flow.
  • Preserve the original cause when wrapping an exception.
  • Use try-with-resources for files, streams, and other closeable resources.
  • Provide clear error messages without exposing passwords, tokens, or sensitive data.

4. Exception Handling Interview Questions and Answers

Q1. What is the difference between an exception and an error?

Answer: Both extend Throwable. Exceptions represent conditions applications may often handle, while errors generally indicate serious JVM or environment problems that ordinary application code is not expected to recover from.

Q2. Can we have a try block without a catch block?

Answer: Yes. A try block can be followed by finally without a catch, or it can be a try-with-resources statement followed by a finally block or no catch at all. A plain try block cannot stand alone without a catch or finally.

Q3. Can a finally block be skipped?

Answer: It normally runs, but it may not run if the JVM terminates abruptly, for example through System.exit() or a process failure. Do not depend on finally for actions that must survive every possible termination.

Q4. Can we catch multiple exceptions in one catch block?

Answer: Yes, Java supports multi-catch using the pipe symbol, for example catch (IOException | SQLException e), provided the alternatives do not have a subclass relationship that makes the declaration invalid.

Q5. What happens if an exception is not handled?

Answer: It propagates up the call stack. If it remains uncaught, the thread's uncaught-exception handler is invoked and the thread typically terminates after the JVM prints diagnostic information.

Q6. Can we throw an exception from a constructor?

Answer: Yes. Constructors can throw checked or unchecked exceptions. A checked exception must be caught or declared in the constructor's signature.

Q7. What is exception propagation?

Answer: It is the process in which an exception moves from the method where it occurs to calling methods until a matching handler is found or the exception remains uncaught.

Q8. Why should exceptions not be swallowed?

Answer: Ignoring an exception hides failures and makes debugging difficult. Log it appropriately, recover, rethrow it, or communicate a meaningful failure to the caller.

Q9. What are suppressed exceptions?

Answer: In try-with-resources, if the main operation throws an exception and closing a resource also fails, the closing exception can be attached to the primary exception as a suppressed exception. They can be inspected with getSuppressed().

Q10. How do you create a custom checked exception?

Answer: Extend Exception, define a constructor that calls super(message), and declare or catch it where necessary.

5. Java Collections Framework

5.1 What Is the Collections Framework?

The Java Collections Framework provides interfaces and implementations for storing, retrieving, searching, sorting, and processing groups of objects. It reduces the need to implement common data structures from scratch.

Common interfaces include Collection, List, Set, and Queue. The Map interface stores key-value pairs and is part of the framework, but it does not extend Collection.

5.2 Main Collection Interfaces

Interface Purpose Common implementations
List Ordered sequence; allows duplicate elements. ArrayList, LinkedList
Set Stores unique elements according to its equality or ordering rules. HashSet, LinkedHashSet, TreeSet
Queue Holds elements for processing, often in FIFO order. PriorityQueue, LinkedList
Deque Supports adding and removing at both ends. ArrayDeque, LinkedList
Map Associates unique keys with values. HashMap, LinkedHashMap, TreeMap

5.3 ArrayList vs. LinkedList

Feature ArrayList LinkedList
Underlying structure Resizable array Doubly linked list
Indexed access Usually O(1) O(n) in general
Append Amortized O(1) O(1) when inserting at the end through the list's tail reference
Insert/remove in the middle May shift elements, O(n) Finding the position is usually O(n); changing links is O(1) once positioned
Typical use Frequent reading and indexed access Specific queue/deque operations or list operations where node access is already available

Interview tip: Do not assume LinkedList is always faster for insertion and deletion. Finding an element's position can cost O(n), and linked nodes have additional memory overhead.

5.4 HashSet vs. TreeSet vs. LinkedHashSet

Feature HashSet LinkedHashSet TreeSet
Duplicates Not allowed Not allowed Not allowed according to its ordering comparison
Iteration order Not guaranteed Insertion order Sorted order
Typical performance Average O(1) for basic operations with good hashing Average O(1) for basic operations with good hashing O(log n) for basic operations
Best suited for Fast uniqueness checks Uniqueness while preserving insertion order Sorted unique elements and range operations

5.5 HashMap and Its Important Features

HashMap stores key-value pairs. It permits one null key and multiple null values. It does not guarantee iteration order and is not synchronized for concurrent mutation.

import java.util.HashMap;
import java.util.Map;

public class MapExample {
    public static void main(String[] args) {
        Map scores = new HashMap<>();
        scores.put("Asha", 85);
        scores.put("Ravi", 92);
        scores.put("Asha", 90);

        System.out.println(scores.get("Asha"));
        System.out.println(scores.containsKey("Ravi"));
    }
}

Output:

90
true

When a key already exists, put() replaces its associated value. Keys are considered equal according to equals() and hashCode().

5.6 How HashMap Works Conceptually

  1. Java calculates a hash from the key's hashCode().
  2. The hash helps determine the bucket where the entry belongs.
  3. If entries share a bucket, Java uses equality checks to distinguish keys.
  4. When an equal key is inserted again, its value is updated rather than creating a second mapping for that key.
  5. When the map grows beyond its resize threshold, its internal table may expand.

Modern Java implementations may use linked nodes or tree bins within heavily populated buckets. The exact implementation details depend on the Java version; the essential interview concepts are hashing, equality, collisions, and resizing.

5.7 Why Are equals() and hashCode() Important?

Hash-based collections use hashCode() to find a likely location and equals() to determine logical equality. If two objects are equal according to equals(), they must return the same hash code.

import java.util.Objects;

class Employee {
    private final int id;

    Employee(int id) {
        this.id = id;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (!(obj instanceof Employee)) return false;
        Employee other = (Employee) obj;
        return id == other.id;
    }

    @Override
    public int hashCode() {
        return Objects.hash(id);
    }
}

Without a consistent equals() and hashCode() implementation, a HashSet may treat logically identical objects as separate elements or a HashMap may not find a key as expected.

5.8 Comparable vs. Comparator

Comparable Comparator
Defines a class's natural ordering through compareTo(). Defines an external or alternative ordering through compare().
Implemented by the class being compared. Can be implemented separately or created using comparator utilities and lambdas.
Typically one natural order. Multiple sorting strategies can be supplied.
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

class Student {
    String name;
    int marks;

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

class SortStudents {
    public static void main(String[] args) {
        List students = new ArrayList<>();
        students.add(new Student("Asha", 88));
        students.add(new Student("Ravi", 75));
        students.add(new Student("Meera", 95));

        students.sort(Comparator.comparingInt(s -> s.marks));

        for (Student s : students) {
            System.out.println(s.name + ": " + s.marks);
        }
    }
}

5.9 Iterator and ListIterator

An Iterator traverses a collection and provides remove() for supported collections. A ListIterator is specific to lists and supports forward and backward traversal, as well as supported element replacement and insertion operations.

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

List<Integer> numbers =
    new ArrayList<>(List.of(10, 15, 20, 25));

Iterator<Integer> iterator = numbers.iterator();

while (iterator.hasNext()) {
    if (iterator.next() % 2 != 0) {
        iterator.remove();
    }
}

System.out.println(numbers);

Output: [10, 20]

Removing elements directly from a collection during enhanced-for iteration can trigger ConcurrentModificationException. Use the iterator's supported removal method or a suitable collection operation instead.

5.10 Fail-Fast Iterators

Many standard collection iterators are fail-fast: they may throw ConcurrentModificationException when they detect structural modification outside the iterator during iteration. This behavior is best-effort bug detection, not a thread-safety guarantee.

For concurrent access, consider suitable alternatives such as ConcurrentHashMap, CopyOnWriteArrayList, or explicit synchronization depending on the access pattern and performance requirements.

5.11 Queue and Deque

A queue commonly processes elements in first-in, first-out order. A priority queue instead orders elements by priority according to its comparator or natural ordering. A deque supports insertion and removal at both ends and can be used to implement a queue or stack.

import java.util.ArrayDeque;
import java.util.Deque;

Deque<String> tasks = new ArrayDeque<>();
tasks.addLast("Task A");
tasks.addLast("Task B");

System.out.println(tasks.removeFirst());
System.out.println(tasks.removeFirst());

Output:

Task A
Task B

ArrayDeque is often a good choice for stack or queue operations. It does not permit null elements.

5.12 Collections Utility Methods

The Collections utility class offers methods such as sort(), reverse(), shuffle(), min(), max(), and wrappers for synchronized or unmodifiable views.

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

List<Integer> values =
    new ArrayList<>(List.of(5, 2, 9, 1));

Collections.sort(values);
System.out.println(values);

Collections.reverse(values);
System.out.println(values);

Output:

[1, 2, 5, 9]
[9, 5, 2, 1]

Remember that an unmodifiable view is not necessarily an immutable copy: changes to the backing collection may still be visible through the view.

5.13 Common Collection Complexity Summary

Operation Typical complexity Important qualification
ArrayList.get(index) O(1) Direct indexed access
ArrayList search by value O(n) May inspect every element
HashMap.get(key) Average O(1) Depends on hashing and collisions
TreeMap.get(key) O(log n) Tree-based sorted map
HashSet.contains(value) Average O(1) Depends on hashing and equality behavior
TreeSet.contains(value) O(log n) Uses ordering comparisons

6. Collections Framework Interview Questions and Answers

Q1. What is the difference between Collection and Collections?

Answer: Collection is a root interface for many collection types. Collections is a utility class containing static methods for sorting, searching, reversing, wrapping, and other operations.

Q2. Is Map a subtype of Collection?

Answer: No. Map is a separate interface that stores key-value mappings. It provides views such as keySet(), values(), and entrySet().

Q3. Can a HashMap contain duplicate keys?

Answer: No. Keys are unique according to equality rules. Adding an equal key updates its value. Different keys may map to the same value.

Q4. Can a HashSet contain duplicate objects?

Answer: It does not allow duplicates according to its equality and hashing rules. Correctly overriding equals() and hashCode() is important for custom classes.

Q5. What is the difference between HashMap and Hashtable?

Answer: HashMap is not synchronized and allows one null key and null values. Hashtable is a legacy synchronized map and does not allow null keys or values. For concurrent applications, ConcurrentHashMap is often more suitable than Hashtable.

Q6. What is the difference between ArrayList and Vector?

Answer: Both are resizable-array implementations. Vector is a legacy class whose individual methods are synchronized, whereas ArrayList is generally preferred for non-concurrent use. Method-level synchronization alone does not automatically make a multi-step workflow thread-safe.

Q7. How does a TreeMap differ from a HashMap?

Answer: HashMap does not guarantee iteration order and offers average constant-time basic operations under suitable hashing. TreeMap keeps keys sorted and generally offers logarithmic-time basic operations.

Q8. What is ConcurrentModificationException?

Answer: It can occur when a fail-fast iterator detects structural modification outside the iterator while traversing a collection. Use the iterator's own removal method, an appropriate bulk operation, or a concurrent collection when suitable.

Q9. How do you sort a list of custom objects?

Answer: Implement Comparable for natural ordering or pass a Comparator to sorting methods. For example, students.sort(Comparator.comparingInt(s -> s.marks)).

Q10. What is the difference between Iterator and Enumeration?

Answer: Enumeration is a legacy traversal interface. Iterator is the modern general-purpose interface and supports removal when the collection permits it.

Q11. Why should mutable objects be used carefully as map keys?

Answer: If fields used by equals() or hashCode() change after insertion, the map may no longer find the entry using the modified key. Prefer immutable keys or avoid changing equality-related state while an object is stored in a hash-based collection.

Q12. What is the difference between unmodifiable and immutable collections?

Answer: An unmodifiable collection rejects mutation through that reference, but its backing data may still change elsewhere. An immutable collection has state that cannot be changed after creation. Be precise about whether a method returns a view or a defensive immutable copy.

7. Generics in Java

7.1 What Are Generics?

Generics allow types and methods to operate on parameterized types. They provide stronger compile-time type checking, reduce explicit casting, and make reusable code safer.

import java.util.ArrayList;
import java.util.List;

List<String> names = new ArrayList<>();
names.add("Asha");
names.add("Ravi");

// names.add(100); // Compile-time error

String first = names.get(0);
System.out.println(first);

Output: Asha

Without generics, a collection might accept unrelated object types and require casts when retrieving values. Parameterized types make the intended element type explicit.

7.2 Generic Class

A generic class declares one or more type parameters. The following example creates a reusable container for values of a chosen type.

class Box<T> {
    private T value;

    public void set(T value) {
        this.value = value;
    }

    public T get() {
        return value;
    }
}

class BoxDemo {
    public static void main(String[] args) {
        Box<String> box = new Box<>();
        box.set("Core Java");
        System.out.println(box.get());

        Box<Integer> numberBox = new Box<>();
        numberBox.set(100);
        System.out.println(numberBox.get());
    }
}

Output:

Core Java
100

7.3 Generic Methods

A generic method declares its own type parameter before its return type. It can be declared inside a generic or non-generic class.

public class GenericMethodDemo {
    public static <T> void printArray(T[] values) {
        for (T value : values) {
            System.out.println(value);
        }
    }

    public static void main(String[] args) {
        String[] names = {"Asha", "Ravi"};
        Integer[] scores = {80, 95};

        printArray(names);
        printArray(scores);
    }
}

The compiler infers the method's type parameter from the supplied arguments in typical calls.

7.4 Bounded Type Parameters

A bound restricts the types that can be used for a type parameter. An upper bound such as T extends Number permits Number and its subclasses.

public class NumberUtil {
    public static <T extends Number> double square(T value) {
        double number = value.doubleValue();
        return number * number;
    }

    public static void main(String[] args) {
        System.out.println(square(5));
        System.out.println(square(2.5));
    }
}

Output:

25.0
6.25

For multiple bounds, use <T extends SomeClass & InterfaceA & InterfaceB>. If a class bound exists, it must appear first.

7.5 Wildcards in Generics

The wildcard ? represents an unknown type. It is useful when a method needs to accept collections whose exact type argument is not known.

Syntax Meaning Typical use
List<?> List of an unknown element type Read elements as Object; add only null in ordinary cases
List<? extends Number> List of some unknown subtype of Number Read numeric values as Number
List<? super Integer> List of Integer or one of its supertypes Add Integer values safely

7.6 Upper-Bounded Wildcards

import java.util.List;

public class SumNumbers {
    public static double sum(List<? extends Number> values) {
        double total = 0;
        for (Number value : values) {
            total += value.doubleValue();
        }
        return total;
    }
}

This method accepts, for example, List<Integer>, List<Double>, and List<Number>. The method can read each element as a Number, but generally cannot add an Integer or Double because the exact list element type is unknown.

7.7 Lower-Bounded Wildcards

import java.util.List;

public class AddIntegers {
    public static void addDefaults(List<? super Integer> values) {
        values.add(10);
        values.add(20);
    }
}

The parameter can accept List<Integer>, List<Number>, or List<Object>. When reading from such a list, the safely known type is generally Object.

7.8 PECS Rule

PECS stands for Producer Extends, Consumer Super.

  • Use ? extends T when a parameterized structure primarily produces values that the method reads as type T.
  • Use ? super T when a structure primarily consumes values of type T that the method adds.

PECS is a guideline for choosing wildcard bounds, not an absolute rule for every method. Consider what the method needs to read and write.

7.9 Type Erasure

Java implements generics mainly through type erasure. Generic type information is used for compile-time checks, while many type parameters are erased to their bounds or to Object in the resulting bytecode. The compiler inserts casts where required and may generate bridge methods.

Consequences include:

  • You generally cannot create new T() directly.
  • You cannot use a primitive type as a generic type argument; use wrapper types such as Integer instead of int.
  • You generally cannot create a parameterized type with new T[] or directly instantiate a generic array such as new List<String>[10].
  • You cannot overload methods solely by changing generic type arguments when their erased signatures become identical.
  • You cannot use instanceof List<String> as a runtime type check; a check such as instanceof List<?> is permitted.

7.10 Raw Types

A raw type omits a generic type argument, such as List instead of List<String>. Raw types are retained for backward compatibility but bypass important generic checks and may cause runtime ClassCastException failures.

import java.util.ArrayList;
import java.util.List;

List raw = new ArrayList();
raw.add("Hello");
raw.add(123);

List<String> names = raw; // Unchecked assignment
String name = names.get(1); // May throw ClassCastException

Prefer parameterized types and address compiler warnings rather than ignoring them.

7.11 Generic Invariance

Even though Integer extends Number, List<Integer> is not a subtype of List<Number>. If it were, code could insert a Double into a list that was expected to contain only Integers. Wildcards provide controlled flexibility where needed.

7.12 Generic Constructors and Interfaces

Constructors may declare type parameters, and interfaces can also be generic.

interface Repository<T, ID> {
    T findById(ID id);
    void save(T entity);
}

class ProductRepository implements Repository<String, Integer> {
    public String findById(Integer id) {
        return "Product-" + id;
    }

    public void save(String entity) {
        System.out.println("Saved: " + entity);
    }
}

Here, T represents the entity type and ID represents its identifier type. Generics help make the contract clear at compile time.


8. Generics Interview Questions and Answers

Q1. Why are generics used in Java?

Answer: They provide compile-time type safety, reduce explicit casting, and allow reusable classes and methods to work with different reference types.

Q2. What is the difference between a generic class and a generic method?

Answer: A generic class declares type parameters at class level, while a generic method declares type parameters for that method. A non-generic class can still contain generic methods.

Q3. Can we use primitive types with generics?

Answer: No. Generic type arguments must be reference types. Use wrapper classes such as Integer, Double, and Boolean; autoboxing and unboxing can convert between wrappers and primitives where applicable.

Q4. What is type erasure?

Answer: It is the process by which generic type parameters are largely removed from the runtime representation after compile-time checks. This helps preserve compatibility with older Java code.

Q5. What is the difference between List<Object> and List<?>?

Answer: List<Object> is specifically a list of Object elements and can accept objects of different reference types. List<?> represents a list of an unknown element type and can refer to lists such as List<String> or List<Integer>.

Q6. What is a bounded type parameter?

Answer: It restricts the allowed type arguments, for example <T extends Number>, allowing the method to use operations available on Number.

Q7. Explain the PECS rule.

Answer: Producer Extends, Consumer Super. Use ? extends T for values read as T and ? super T for structures to which T values are added.

Q8. Why can't we create an instance of T directly?

Answer: Because the runtime generally does not retain enough concrete type information after erasure to instantiate the type parameter directly. A common alternative is to pass a Class<T> token or a factory function.

Q9. What is a raw type and why should it be avoided?

Answer: A raw type uses a generic class or interface without type arguments. It weakens compile-time checking and can introduce unchecked warnings and runtime type errors.

Q10. Can we overload generic methods?

Answer: Yes, if their signatures are distinct after type erasure. Methods cannot be overloaded solely by parameterized type arguments when the resulting erased signatures conflict.

Q11. Why is List<Integer> not a subtype of List<Number>?

Answer: Generic types are invariant. This prevents inserting a different Number subtype, such as Double, into a list that should contain only Integers.

Q12. What is the difference between extends and implements in a type parameter declaration?

Answer: In generic bounds, the keyword extends is used for both class and interface bounds. A class bound, if present, comes first, followed by interface bounds joined with &. The keyword implements is not used in the type parameter bound syntax.

9. Scenario-Based Interview Questions

Scenario 1: Reading a File That May Not Exist

Question: How would you handle an application trying to read a missing file?

Suggested answer: Use try-with-resources to manage the reader, catch IOException at a layer that can respond meaningfully, and display or log an appropriate message. If the file is optional, consider checking the application's file policy and providing a default or fallback.

Scenario 2: Removing Duplicates from a List

Question: How can you remove duplicate integers while preserving insertion order?

import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;

List<Integer> values =
    new ArrayList<>(List.of(4, 2, 4, 3, 2));

List<Integer> unique =
    new ArrayList<>(new LinkedHashSet<>(values));

System.out.println(unique);

Output: [4, 2, 3]

Explanation: LinkedHashSet maintains insertion order and rejects duplicates according to equality rules.

Scenario 3: Counting Word Frequencies

Question: How would you count how many times each word appears?

import java.util.HashMap;
import java.util.Map;

String[] words = {"java", "sql", "java", "python", "sql", "java"};
Map<String, Integer> frequency = new HashMap<>();

for (String word : words) {
    frequency.merge(word, 1, Integer::sum);
}

System.out.println(frequency);

Expected counts: java=3, sql=2, and python=1. The order printed by a HashMap is not guaranteed.

Scenario 4: Designing a Reusable Repository

Question: How would you create a repository that can store different entity types?

Suggested answer: Define a generic interface such as Repository<T, ID> with methods to save and retrieve entities. This provides a reusable contract while preserving the entity and identifier types at compile time.

Scenario 5: Choosing a Thread-Safe Map

Question: Multiple threads need to read and update a shared map. What would you consider?

Suggested answer: Consider ConcurrentHashMap for concurrent access. For compound operations, use atomic methods such as computeIfAbsent() where appropriate. Ensure that any larger multi-step business operation is also designed to be thread-safe.

Scenario 6: Validating User Input

Question: Should an application use exceptions to validate every ordinary input field?

Suggested answer: Use normal conditional checks for expected validation outcomes. Throw an exception when an operation violates a contract or cannot proceed in a meaningful way. Exceptions should not replace routine branching logic.

10. Combined Coding Practice

Exercise 1: Validate and Store Unique Student Marks

Write a program that checks whether marks are within the range 0 to 100, stores valid marks without duplicates, and reports invalid input using a meaningful exception.

import java.util.LinkedHashSet;
import java.util.Set;

public class MarksManager {
    static void addMark(Set<Integer> marks, int mark) {
        if (mark < 0 || mark > 100) {
            throw new IllegalArgumentException(
                "Marks must be between 0 and 100");
        }
        marks.add(mark);
    }

    public static void main(String[] args) {
        Set<Integer> marks = new LinkedHashSet<>();

        try {
            addMark(marks, 80);
            addMark(marks, 95);
            addMark(marks, 80);
            addMark(marks, 120);
        } catch (IllegalArgumentException e) {
            System.out.println(e.getMessage());
        }

        System.out.println(marks);
    }
}

Expected output:

Marks must be between 0 and 100
[80, 95]

Exercise 2: Create a Generic Pair

Create a class called Pair<K, V> that stores a key and value of potentially different types. Add a constructor and getter methods, then create a pair containing a String and an Integer.

class Pair<K, V> {
    private final K key;
    private final V value;

    Pair(K key, V value) {
        this.key = key;
        this.value = value;
    }

    public K getKey() {
        return key;
    }

    public V getValue() {
        return value;
    }
}

class PairDemo {
    public static void main(String[] args) {
        Pair<String, Integer> pair =
            new Pair<>("Age", 25);

        System.out.println(pair.getKey());
        System.out.println(pair.getValue());
    }
}

Exercise 3: Filter Invalid Records

Build a program that accepts a list of records, catches invalid record data at the appropriate boundary, and stores valid records in a Map keyed by record ID. Consider what should happen if an ID appears more than once and how the program should report invalid records.

Exercise 4: Write a Generic Maximum Method

Create a generic method that returns the larger of two values implementing Comparable. Use a bound such as <T extends Comparable<? super T>> and test it with Strings and Integers.

public class MaxUtil {
    public static <T extends Comparable<? super T>>
            T maximum(T first, T second) {
        return first.compareTo(second) >= 0
            ? first : second;
    }

    public static void main(String[] args) {
        System.out.println(maximum(10, 25));
        System.out.println(maximum("Java", "Python"));
    }
}

Output:

25
Python

11. Common Interview Mistakes to Avoid

  • Claiming that every exception is checked or that every error can be handled safely.
  • Confusing throw with throws.
  • Assuming finally is guaranteed to run under every possible termination condition.
  • Claiming that Map extends Collection.
  • Assuming every collection preserves insertion order.
  • Forgetting that hash-based collections depend on consistent equals() and hashCode().
  • Assuming LinkedList always outperforms ArrayList for insertions and deletions.
  • Modifying a collection during iteration without using a supported approach.
  • Confusing List<Object> with List<?>.
  • Assuming generic type arguments are fully available for runtime checks after type erasure.
  • Using raw types when parameterized types are available.
  • Giving only definitions without explaining a real use case or writing a short example.

12. Quick Revision Checklist

  • Explain checked and unchecked exceptions with examples.
  • Demonstrate try-catch-finally, throw, throws, custom exceptions, and try-with-resources.
  • Compare ArrayList, LinkedList, HashSet, TreeSet, HashMap, and TreeMap.
  • Explain the contract between equals() and hashCode().
  • Use Comparator to sort custom objects.
  • Explain iterator removal and fail-fast behavior.
  • Create a generic class and a generic method.
  • Explain upper bounds, lower bounds, wildcards, PECS, raw types, and type erasure.
  • Practice explaining why a chosen implementation fits a specific problem.

13. Interview Preparation Strategy

  1. Learn the concept: Start with a concise definition and the problem the feature solves.
  2. Compare alternatives: Be ready to explain why you would choose one exception type or collection implementation over another.
  3. Write code: Practice short programs that compile, produce predictable output, and handle edge cases.
  4. Explain trade-offs: Discuss ordering, duplicates, complexity, type safety, resource cleanup, and concurrency where relevant.
  5. Practice follow-up questions: Interviewers may change a requirement—for example, preserve insertion order, allow concurrent updates, or accept a wider range of generic types.
  6. Review your mistakes: Compile your practice programs and understand both compiler errors and runtime exceptions.

14. Conclusion

Exception handling, collections, and generics form a practical foundation for Core Java interviews. Exception handling makes failure behavior more deliberate, collections help select suitable data structures, and generics improve type safety and code reuse.

To prepare effectively, learn the definitions, understand the underlying behavior, practice the examples, and explain the reasoning behind your choices. Focus on clear, correct code and real-world scenarios rather than memorizing answers alone.

Continue learning: Explore the Core Java Training Course | Register for a Course Demo | JustAcademy Homepage

Previous Next
whatsapp