Unit4 - Subjective Questions
CSE310 • Practice Questions with Detailed Answers
Differentiate between a Static Nested Class and a Non-Static Nested Class (Inner Class) in Java.
Static Nested Class and Non-Static Nested Class differ primarily in how they relate to the outer class instance.
| Feature | Static Nested Class | Non-Static Nested Class (Inner Class) |
|---|---|---|
| Keyword | Declared with the static keyword. |
Declared without the static keyword. |
| Instance Requirement | Can be instantiated without an instance of the Outer class. | Requires an instance of the Outer class to be instantiated. |
| Access to Members | Can only access static members of the Outer class directly. It cannot access instance members (non-static) directly. | Can access both static and non-static (instance) members of the Outer class directly, including private members. |
| Instantiation Syntax | Outer.StaticNested nested = new Outer.StaticNested(); |
Outer.Inner inner = outerInstance.new Inner(); |
| Use Case | Used to group helper classes that do not require access to the outer class's instance state. | Used when the nested class needs to access the instance variables/methods of the outer class. |
Explain the concept of Anonymous Inner Classes in Java. How are they useful for event handling or interface implementation?
An Anonymous Inner Class is an inner class without a name and for which only a single object is created. An anonymous inner class can be useful when making an instance of an object with certain "extras" such as overloading methods of a class or interface, without having to actually subclass a class.
Key Characteristics:
- No Name: It has no canonical name.
- Instantiation: It is declared and instantiated in a single expression.
- Scope: It usually implements an interface or extends a class.
Usage in Interfaces:
They are frequently used for passing code as data, such as in event handling (listeners) before Lambda expressions were introduced.
Example:
java
interface Greeter {
void greet();
}
public class Main {
public static void main(String[] args) {
// Anonymous class implementing Greeter interface
Greeter g = new Greeter() {
@Override
public void greet() {
System.out.println("Hello world");
}
};
g.greet();
}
}
In this example, a class implementing Greeter is defined and instantiated immediately.
Define a Functional Interface in Java. How does the @FunctionalInterface annotation work, and what is its relationship with Lambda expressions?
Functional Interface
A Functional Interface is an interface that contains exactly one abstract method. It may contain any number of default methods, static methods, or methods overriding methods from java.lang.Object.
@FunctionalInterface Annotation
This annotation is used to ensure that the interface meets the requirements of a functional interface.
- It is optional but recommended.
- If an interface annotated with
@FunctionalInterfacecontains more than one abstract method, the compiler will generate an error.
Relationship with Lambda Expressions
Lambda expressions are essentially succinct implementations of Functional Interfaces. A Lambda expression provides the implementation for the single abstract method defined in the interface.
Example:
java
@FunctionalInterface
interface Calculator {
int calculate(int a, int b);
}
// Usage with Lambda
Calculator add = (a, b) -> a + b;
Describe the syntax of Lambda Expressions in Java. Provide examples for expressions with no parameters, single parameter, and multiple parameters.
A Lambda Expression in Java is a short block of code which takes in parameters and returns a value. It is similar to a method, but it does not need a name and can be implemented right in the body of a method.
Syntax
- Parameter List: Comma-separated list of formal parameters enclosed in parentheses.
- Arrow Token: The
->symbol. - Body: Contains expressions and statements.
Examples
1. No Parameters:
java
() -> System.out.println("Hello Lambda");
2. Single Parameter:
Parentheses are optional for a single parameter.
java
x -> x * x;
3. Multiple Parameters:
java
(int x, int y) -> {
return x + y;
};
Note: If the body has a single expression, braces {} and the return keyword can be omitted.
Discuss the Exception Hierarchy in Java. Explain the roles of Throwable, Error, Exception, and RuntimeException.
In Java, all exceptions and errors are subclasses of the java.lang.Throwable class. The hierarchy is divided into two main branches:
1. Throwable
The root class of the Java exception hierarchy.
2. Error
- Subclass of
Throwable. - Represents serious problems that a reasonable application should not try to catch (e.g.,
OutOfMemoryError,StackOverflowError,VirtualMachineError). - These are usually abnormal conditions that are external to the application.
3. Exception
- Subclass of
Throwable. - Represents conditions that a reasonable application might want to catch.
- Divided into two categories:
- Checked Exceptions: Classes that extend
Exceptionbut notRuntimeException(e.g.,IOException,SQLException). These must be handled at compile-time (try-catch or throws). - Unchecked Exceptions (RuntimeException): Classes that extend
RuntimeException. These typically indicate programming errors (e.g.,NullPointerException,ArithmeticException). They are not checked at compile-time.
- Checked Exceptions: Classes that extend
Explain the keywords try, catch, and finally with a code example demonstrating the flow of execution.
Java uses a combination of try, catch, and finally blocks to handle exceptions.
Keywords:
- try: The block of code to be tested for errors while it is being executed.
- catch: The block of code to be executed if an exception occurs in the try block.
- finally: The block of code to be executed regardless of whether an exception occurred or not. It is typically used for resource cleanup (closing files, database connections).
Code Example:
java
public class ExceptionTest {
public static void main(String[] args) {
try {
int data = 50 / 0; // This throws ArithmeticException
System.out.println("This line will not execute");
} catch (ArithmeticException e) {
System.out.println("Exception caught: " + e);
} finally {
System.out.println("Finally block is always executed");
}
System.out.println("Rest of the code...");
}
}
Flow of Execution:
- Control enters
try. Exception occurs at50/0. - Control jumps to
catchblock; "Exception caught..." is printed. - Control enters
finallyblock; "Finally block..." is printed. - Execution continues after the blocks; "Rest of the code..." is printed.
Distinguish between throw and throws keywords in Java.
Both keywords are used in exception handling but serve different purposes.
| Feature | throw | throws |
|---|---|---|
| Purpose | Used to explicitly throw an exception object. | Used to declare that a method might throw one or more exceptions. |
| Location | Used inside the method body. | Used in the method signature (definition). |
| Number of Exceptions | Can only throw one exception at a time. | Can declare multiple exceptions separated by commas. |
| Syntax | throw new ArithmeticException(" / by zero"); |
public void method() throws IOException, SQLException { ... } |
| Propagation | Acts as an action to create an exception state. | Acts as a warning/contract to the caller to handle the exception. |
| Instance vs Class | Followed by an instance (object) of Exception. | Followed by Class names of Exceptions. |
What is the Try-with-Resources statement in Java? How does it help in resource management compared to the traditional try-finally block?
Try-with-resources is a feature introduced in Java 7 that automatically closes resources used within the try block. A resource is an object that must be closed after the program is finished with it (e.g., Files, Sockets, Database connections).
Requirement:
The resource must implement the java.lang.AutoCloseable or java.io.Closeable interface.
Comparison:
Traditional Approach:
java
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader("file.txt"));
// read file
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (br != null) br.close(); // Explicit close required
} catch (IOException ex) {
ex.printStackTrace();
}
}
Try-with-Resources:
java
try (BufferedReader br = new BufferedReader(new FileReader("file.txt"))) {
// read file
} catch (IOException e) {
e.printStackTrace();
}
// br is automatically closed here
Benefits:
- Code Reduction: Eliminates the boilerplate code in the
finallyblock. - Safety: Ensures resources are closed even if exceptions occur.
- Readability: Code is cleaner and easier to read.
Explain the concept of Exception Propagation in Java.
Exception Propagation refers to the mechanism by which an exception is passed from the method where it occurred to the method that called it, moving up the call stack until it is caught or the program terminates.
Mechanism:
- If an exception occurs in a method and is not caught (using
try-catch), the exception drops down the call stack to the previous method. - If the previous method also does not catch it, it propagates further up.
- This continues until it reaches the
main()method. Ifmain()does not handle it, the JVM handles it by terminating the program and printing the stack trace.
Checked vs. Unchecked Propagation:
- Unchecked Exceptions: Automatically propagated by default. The compiler does not enforce handling.
- Checked Exceptions: Do strictly propagate automatically; the method must explicitly declare them using
throwsfor propagation to occur legitimately during compilation.
Example:
main() calls m1(), m1() calls m2(). If an exception occurs in m2(): m2 m1 main.
How can you handle multiple exceptions in a single catch block? Explain the Multi-catch feature introduced in Java 7.
Before Java 7, catching multiple distinct exceptions required separate catch blocks for each exception type, leading to duplicated code.
Multi-catch Feature
Java 7 introduced the ability to catch multiple exception types in a single catch block using the pipe operator (|).
Syntax:
java
try {
// code that may throw exceptions
} catch (ExceptionType1 | ExceptionType2 | ExceptionType3 e) {
// handling code
}
Rules:
- The exception variable
ein a multi-catch block is implicitlyfinaland cannot be reassigned. - Exceptions separated by
|cannot have a parent-child relationship (inheritance). For example,catch (Exception | ArithmeticException e)is illegal becauseArithmeticExceptionis a subclass ofException.
Example:
java
try {
int[] arr = new int[5];
arr[10] = 30 / 0;
} catch (ArithmeticException | ArrayIndexOutOfBoundsException e) {
System.out.println("Error occurred: " + e.getMessage());
}
Describe the process of creating a Custom Exception (User-defined Exception) in Java. Provide a code example.
Java provides a comprehensive set of built-in exceptions, but sometimes application-specific logic requires custom error handling.
Steps to Create a Custom Exception:
- Create a class that extends
Exception(for a checked exception) orRuntimeException(for an unchecked exception). - Define a constructor that calls the superclass constructor (
super(message)) to set the error message.
Code Example:
1. Defining the Exception:
java
// Extending Exception makes it a Checked Exception
class InvalidAgeException extends Exception {
public InvalidAgeException(String str) {
// Calling constructor of parent Exception
super(str);
}
}
2. Using the Exception:
java
public class TestCustomException {
static void validate(int age) throws InvalidAgeException {
if (age < 18) {
throw new InvalidAgeException("Age is not valid for voting");
} else {
System.out.println("Welcome to vote");
}
}
public static void main(String[] args) {
try {
validate(13);
} catch (InvalidAgeException e) {
System.out.println("Caught Exception: " + e.getMessage());
}
}
}
What are Assertions in Java? Explain their syntax and how to enable them.
Assertions are a development tool used to test invariants (conditions that should always be true) in the code. They allow developers to detect logical errors during testing and debugging.
Syntax
There are two forms of the assert statement:
- Simple:
assert expression1;- If
expression1is false, anAssertionErroris thrown.
- If
- Detailed:
assert expression1 : expression2;expression1: The boolean condition.expression2: A value passed to theAssertionErrorconstructor (converted to a string message).
Enabling Assertions
By default, assertions are disabled in the JVM. They must be enabled explicitly at runtime.
- Enable: Use the
-eaor-enableassertionsflag.
java -ea MyProgram - Disable: Use the
-daor-disableassertionsflag.
Example
java
int value = -1;
assert value >= 0 : "Value must be non-negative";
Discuss the Java 8 Date/Time API utility classes. How do LocalDate, LocalTime, and LocalDateTime differ from the old Date class?
Prior to Java 8, date handling (via java.util.Date and Calendar) was mutable, not thread-safe, and had poor API design. Java 8 introduced the java.time package.
Key Classes:
- LocalDate: Represents a date without a time-zone (Year-Month-Day). Immutable.
- Example:
LocalDate today = LocalDate.now();
- Example:
- LocalTime: Represents a time without a date or time-zone (Hour-Minute-Second-Nanosecond). Immutable.
- Example:
LocalTime now = LocalTime.now();
- Example:
- LocalDateTime: Combines date and time. Immutable.
- Example:
LocalDateTime dt = LocalDateTime.now();
- Example:
Differences from java.util.Date:
| Feature | java.util.Date | java.time (Java 8) |
|---|---|---|
| Mutability | Mutable (Object state can change). | Immutable (Thread-safe). |
| Clarity | offsets (Month starts at 0, Year starts at 1900). | Clear values (Month starts at 1). |
| Methods | Limited built-in manipulation. | Rich API (plusDays, minusHours, isBefore). |
| Formatting | Uses SimpleDateFormat (not thread-safe). |
Uses DateTimeFormatter (thread-safe). |
What is a Local Inner Class? What are the restrictions on accessing local variables within a local inner class?
A Local Inner Class is a class defined inside a block, typically within a method body. It is not a member of the enclosing class but is local to the block where it is defined.
Characteristics:
- Scope: It can only be instantiated within the block where it is defined.
- Access Modifiers: It cannot have access modifiers like
public,private, orprotected. It can befinalorabstract.
Accessing Local Variables:
A local inner class can access members of the enclosing class. However, when accessing local variables of the enclosing method, a specific restriction applies:
- Effectively Final: The local variable being accessed must be declared
finalor be "effectively final" (meaning its value is never changed after initialization).
Reason: The inner class instance might outlive the method execution stack. To handle this, Java captures the value of the local variable. If the variable were mutable, synchronization issues would arise between the inner class's copy and the stack variable.
Explain the difference between Checked and Unchecked exceptions with examples.
Java distinguishes between exceptions that must be handled and those that can be handled.
Checked Exceptions
- Definition: Exceptions checked by the compiler at compile-time.
- Requirement: The code must either catch the exception (
try-catch) or declare it in the method signature (throws). - Use Case: External failures usually beyond the program's control (File I/O, Network).
- Examples:
IOException,SQLException,ClassNotFoundException.
Unchecked Exceptions
- Definition: Exceptions that occur at runtime and are not checked by the compiler.
- Inheritance: Classes extending
RuntimeExceptionorError. - Requirement: Handling is optional (though good practice to fix the cause).
- Use Case: Logic errors or improper use of APIs.
- Examples:
NullPointerException,ArrayIndexOutOfBoundsException,ArithmeticException.
Analyze the rules for Exception Handling with Method Overriding. What happens when a subclass overrides a method that throws an exception?
When a subclass overrides a method from a superclass, specific rules apply regarding the throws clause to ensure type safety and contract adherence.
Rules:
-
No New Checked Exceptions: The overriding method (subclass) cannot declare any checked exception that is new or broader than the exceptions declared in the overridden method (superclass).
- Example: If Super declares
throws IOException, Sub cannot declarethrows Exception.
- Example: If Super declares
-
Fewer or Subclass Exceptions: The overriding method can declare:
- The same exception.
- A subclass of the declared exception.
- No exception at all.
-
Unchecked Exceptions: The overriding method can throw any
RuntimeException(Unchecked exception) regardless of what the superclass method declares.
Example:
java
class Parent {
void msg() throws IOException { ... }
}
class Child extends Parent {
// Valid: Same exception
void msg() throws IOException { ... }
// Valid: Subclass exception
void msg() throws FileNotFoundException { ... }
// Valid: No exception
void msg() { ... }
// Valid: Unchecked exception
void msg() throws ArithmeticException { ... }
// INVALID: Broader exception
// void msg() throws Exception { ... }
}
Explain the purpose of the Period and Duration classes in the Java Date/Time API.
In the Java 8 Date/Time API, Period and Duration are used to represent amounts of time.
Period
- Definition: Represents a quantity of time in terms of years, months, and days.
- Usage: Used with
LocalDate. - Example: Calculating the difference between two dates.
java
LocalDate start = LocalDate.of(2020, 1, 1);
LocalDate end = LocalDate.of(2021, 1, 1);
Period p = Period.between(start, end); // P1Y (1 Year)
Duration
- Definition: Represents a quantity of time in terms of seconds and nanoseconds.
- Usage: Used with
LocalTimeorLocalDateTime. - Example: Calculating the execution time of a block of code.
java
LocalTime start = LocalTime.now();
// ... code ...
LocalTime end = LocalTime.now();
Duration d = Duration.between(start, end);
Compare Lambda Expressions with Anonymous Inner Classes. When should you use one over the other?
While both features allow for dynamic implementations, they differ in syntax and scope.
| Feature | Anonymous Inner Class | Lambda Expression |
|---|---|---|
| Type | Can implement interfaces (multiple methods) or extend classes. | Can only implement Functional Interfaces (single abstract method). |
| Syntax | Verbose (requires new, method name, etc.). |
Concise (params -> body). |
this Keyword |
Refers to the instance of the anonymous class itself. | Refers to the enclosing instance (current class). |
| Compilation | Compiles into a separate .class file (e.g., Main$1.class). |
Treated as an invokedynamic instruction; usually no separate file. |
When to use:
- Use Lambda: When implementing a functional interface and you want concise code.
- Use Anonymous Class: When you need to override multiple methods, extend an abstract class, or need state (instance variables) within the implementation.
Write a Java program fragment to demonstrate how to handle a NullPointerException and an ArrayIndexOutOfBoundsException.
These are runtime exceptions that often occur due to logic errors.
java
public class RuntimeHandling {
public static void main(String[] args) {
String text = null;
int[] numbers = {1, 2, 3};
try {
// Scenario 1: Potential NullPointer
if (text != null) {
System.out.println(text.length());
} else {
// Simulating the crash for demonstration
throw new NullPointerException("String is null");
}
// Scenario 2: Array Index Out of Bounds
// This line would throw exception if reached
System.out.println(numbers[5]);
} catch (NullPointerException e) {
System.out.println("Error: Attempted to operate on a null object.");
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Error: Accessed index outside array limits.");
} catch (Exception e) {
System.out.println("General error: " + e.getMessage());
}
}
}
Note: While catching these is possible, the best practice for runtime exceptions is usually to fix the logic (e.g., check array length before accessing) rather than using try-catch blocks.
What are the advantages of using Nested Classes in Java?
Nested classes (Static nested and Inner classes) offer several architectural benefits:
- Logical Grouping of Classes: If a class is useful to only one other class, then it is logical to embed it in that class and keep the two together. This packages helper classes closer to where they are used.
- Increased Encapsulation: Consider two classes, A and B, where B needs access to members of A that would otherwise be declared private. By hiding class B within class A, A's members can be declared private and B can access them. In addition, B itself can be hidden from the outside world.
- More Readable and Maintainable Code: Nesting small classes within top-level classes places the code closer to where it is used.
- Code Optimization: Static nested classes can reduce memory overhead compared to inner classes if access to the enclosing instance is not needed.