Unit-02 Java
Unit-02 Java
✅ Q1. What is an Exception in Java? What is the fundamental idea behind exception
handling in Java?
Answer:
An exception in Java is an unexpected problem or abnormal event that arises during the
execution of a program and disrupts its normal flow. These are typically caused by situations
like dividing a number by zero, accessing an invalid index in an array, trying to open a non-
existing file, or receiving invalid user input. Exceptions are objects in Java that describe the
error condition and are instances of the class Throwable or its subclasses.
Java provides a robust exception handling mechanism that allows the program to detect
such problems and respond in a proper and controlled way, instead of crashing suddenly.
The main purpose of exception handling is to ensure the normal execution of the program
continues, even when something goes wrong.
The fundamental idea behind exception handling is to separate error-handling code from
regular code, making the program cleaner, more readable, and fault-tolerant. Java provides
built-in support for this using five key keywords:
try: block that contains risky code
catch: block that handles exceptions
finally: block that always executes (cleanup)
throw: used to explicitly throw an exception
throws: used to declare an exception in method signature
By using these constructs, Java allows programs to detect and recover from problems,
provide user-friendly messages, and maintain program stability.
Checked by
Checked and unchecked both exist. Not checked by compiler.
compiler
OutOfMemoryError,
NullPointerException, IOException,
Examples StackOverflowError,
ArithmeticException
VirtualMachineError
✅ Q4. What are the different types of exceptions in Java? Provide examples for each type.
Answer:
In Java, exceptions are categorized into two major types:
1. Checked Exceptions
2. Unchecked Exceptions
1. Checked Exceptions:
These are exceptions that are checked at compile time.
The programmer is required to handle them using try-catch or declare them using
throws keyword.
If not handled, the program will not compile.
These usually occur due to external factors (like file handling, database access).
Examples:
IOException: when a file cannot be read or opened.
SQLException: when a database operation fails.
ClassNotFoundException: when a class is not found during runtime.
2. Unchecked Exceptions:
These are exceptions that occur at runtime.
The compiler does not check them.
Usually occur due to logic errors or programming mistakes.
Examples:
NullPointerException: accessing a method on a null object.
ArithmeticException: dividing a number by zero.
ArrayIndexOutOfBoundsException: invalid index access in arrays.
This classification helps developers know which exceptions must be handled explicitly and
which may be left unhandled (but should still be managed properly for clean and user-
friendly applications).
✅ Q6. Describe the context behind exception handling when an exception occurs.
Answer:
When an exception occurs in Java, it means that something has gone wrong during the
runtime of a program. This could be a small issue (like an incorrect input from the user) or a
serious one (like a missing file). In the normal flow of execution, if no exception occurs, the
program runs sequentially. But when an exception arises, the normal flow breaks, and Java
immediately begins to search for a handler to manage the exception.
Java uses a structured model of exception handling. The context behind this mechanism is
to make the program more reliable and less prone to sudden termination. Instead of
crashing the program, Java lets us define how to respond when an error occurs. This
response is written in a special block called the catch block, which is used alongside a try
block.
When Java detects an exception:
It jumps out of the normal execution.
It checks if a proper catch block exists to handle that specific type of exception.
If the exception is caught, the handler executes the corrective code.
If it’s not caught, the program terminates abnormally, and the JVM prints a stack
trace showing where the error occurred.
This context of handling exceptions allows developers to:
Avoid program crashes.
Log or inform users about the issue.
Perform recovery actions (like retrying, defaulting, or exiting gracefully).
Improve program reliability and maintainability.
Thus, Java’s exception handling mechanism allows programs to anticipate and manage
errors, making them more secure and robust.
✅ Q7. How does Java manage the code flow when an exception occurs?
Answer:
When an exception occurs in Java, the normal sequence of code execution is interrupted.
Java then diverts the control flow to the nearest catch block that is capable of handling the
exception. This flow of control is essential for managing abnormal conditions in a predictable
manner.
Here is how Java handles code flow:
1. Normal Flow Before Exception:
o Code executes line by line in sequence.
o If no error occurs, try-catch blocks are ignored or completed normally.
2. When Exception Occurs:
o The program jumps out of the try block as soon as the error is detected.
o Java then starts searching for a matching catch block.
o The catch block must match the type of exception that was thrown.
3. After Catching:
o Once the matching catch block is found, the corresponding code is executed.
o After handling the exception, Java may execute a finally block if present.
4. If No Catch Block Found:
o If the exception is not handled, Java passes it up the method call stack.
o If no method in the call stack handles it, the JVM handles it, and the program
terminates abnormally.
In summary, Java’s exception mechanism ensures that the program doesn’t continue
executing invalid or dangerous code after an error has occurred, and gives developers a
chance to take appropriate action.
✅ Q8. How does Java react to exceptions when a program is performed?
Answer:
When a Java program is executed and an exception occurs, Java’s runtime system
immediately reacts to handle the situation. It does so through a process called exception
handling, which aims to prevent the program from crashing and gives the programmer a
way to respond properly to the problem.
Here’s how Java reacts:
As soon as an exception is thrown, the normal flow of the program stops at that
point.
The JVM starts searching for a matching catch block in the current method.
If a catch block is present and matches the exception type, control is passed to it,
and the exception is handled.
If no catch block is present, the exception is passed to the calling method.
This continues up the call stack until the exception is either caught or it reaches the
top (main method).
If it reaches the top and still no handler is found, the JVM handles the exception,
prints the stack trace, and terminates the program.
Java also provides the option of using a finally block which is always executed, regardless of
whether the exception was handled or not. This is usually used for closing files, releasing
resources, or cleanup activities.
This approach allows Java to respond immediately and precisely to problems, helping in
writing clean and safe programs.
3. After printing this message, the JVM terminates the program immediately.
This default behavior is not user-friendly, which is why developers are encouraged to handle
exceptions using try-catch blocks, so that the program can inform the user more gracefully
and possibly recover or take alternative action.
✅ Q11. What is the role of the throw keyword in exception handling? Provide an example.
Answer:
The throw keyword in Java is used to manually throw an exception during the execution of a
program. While Java automatically throws exceptions when certain errors occur (like dividing
by zero), the throw keyword allows the programmer to explicitly trigger an exception,
usually in response to custom logic or input validation.
This is especially useful when a program wants to enforce a rule or business logic, and exit
the current method or execution path by throwing an exception. The throw keyword must
be followed by an instance of a class that inherits from Throwable (either a built-in exception
or a user-defined one).
For example, if a method should not accept a negative number as input, you can manually
throw an IllegalArgumentException.
✅ Short Example (as requested):
if (age < 0) {
throw new IllegalArgumentException("Age cannot be negative");
}
In the above code, if the condition is met, an exception is created and thrown. If not caught,
this will stop the program. If caught using try-catch, the program can continue in a controlled
way.
The throw keyword is essential when the programmer wants to generate exceptions on
purpose for safety, validation, or custom error handling.
✅ Q12. When does the throw keyword contribute to exception handling in Java?
Answer:
The throw keyword contributes to exception handling in Java when there is a need to raise
an exception intentionally in a specific situation. Unlike exceptions that arise automatically
during program execution (like division by zero), the throw keyword is used when the
programmer detects something wrong (like invalid input, illegal state, or unexpected data)
and wants to interrupt the normal program flow.
This is often done for:
Custom validations (e.g., input must not be negative).
Manually triggering built-in exceptions with custom messages.
Throwing user-defined exceptions that represent business-specific problems.
When throw is used inside a method, the method must either handle the exception using
try-catch, or declare it using throws (if it's a checked exception). This gives more control to
the developer in managing the flow of the program during error conditions.
Thus, the throw keyword helps in customizing error reporting, improving code safety, and
making program behavior predictable and robust when unexpected conditions arise.
Checked by
Yes No
compiler
InvalidAgeException, NegativeNumberException,
Examples
AccountBlockedException EmptyInputException
✅ Q17. What is a byte stream in Java? Give a detailed explanation of commonly used byte
stream classes.
Answer:
In Java, byte streams are used to handle input and output of raw binary data such as audio,
images, video, or other non-text files. Byte streams process data in the form of 8-bit bytes,
and do not perform any character encoding or decoding. These streams are useful when we
are working with files where the data is not meant to be human-readable.
All byte stream classes in Java are derived from two abstract classes:
InputStream for reading data.
OutputStream for writing data.
These abstract classes are part of the java.io package and provide a foundation for several
useful subtypes.
In conclusion, byte streams are used when raw binary data needs to be transferred, and
each of the classes above helps improve performance, efficiency, or functionality while
working with files or sockets.
✅ Q18. What do you mean by character stream in Java? Explain the commonly used
character stream classes.
Answer:
Character streams in Java are used to perform input and output operations on text data.
Unlike byte streams, which handle 8-bit data, character streams deal with 16-bit Unicode
characters, making them suitable for reading and writing text in any language.
Java automatically handles character encoding and decoding with character streams,
making them ideal for text files like .txt, .csv, .html, and XML files.
Character stream classes are based on two abstract classes:
Reader (for reading characters)
Writer (for writing characters)
These base classes are extended by many specific classes to support different functionalities.
✅ Major Advantages:
1. Automatic Encoding/Decoding:
o Character streams automatically handle character encoding, ensuring that
characters are not misinterpreted during reading/writing. This is crucial when
working with non-English or special characters.
2. Works Directly with Strings and Characters:
o You can read and write directly using characters or strings instead of dealing
with raw bytes, making the code easier to write and understand.
3. Avoids Data Corruption:
o Text data remains accurate, unlike byte streams, which can corrupt characters
if encoding is not handled manually.
4. Better for Internationalization:
o Supports Unicode, so it can handle multiple languages and character sets
without extra effort.
5. Provides Useful Methods:
o Character stream classes like BufferedReader offer methods like readLine(),
making it easier to process line-by-line input.
6. Cleaner and More Readable Code:
o Reading and writing with character streams is more intuitive for text files, and
reduces complexity compared to byte streams.
✅ Conclusion:
Character streams are specialized for text handling, offer automatic encoding support, and
provide more programmer-friendly methods. While byte streams are required for binary
data, character streams are always preferred for handling text files due to their safety and
simplicity.
This life cycle ensures controlled and predictable execution of multithreaded programs.
✅ Q25. Differentiate between extending the Thread class and implementing the Runnable
interface.
✅ Importance:
Synchronization is essential in multithreaded environments where threads share data, to
ensure data consistency, avoid race conditions, and maintain program correctness.
✅ 1. Synchronized Methods:
Declared using the synchronized keyword.
Entire method is locked; only one thread can execute it at a time.
✅ 2. Synchronized Blocks:
Allows synchronization of only specific part of a method.
Useful when only a section of code needs to be protected.
✅ 3. Static Synchronization:
Used to synchronize static methods.
The lock is on the class object, not on the instance.
✅ 4. Locks (java.util.concurrent.locks.Lock):
More flexible than synchronized blocks.
Allows try-locking, timed locking, and explicit unlock.
✅ 5. Volatile Keyword:
Ensures visibility of changes made by one thread to other threads.
Used for variables to prevent caching of values per thread.
Each mechanism serves different needs, and choosing the right one depends on the
complexity, performance, and safety requirements of the application.
Without synchronization, threads can interfere with each other, causing errors that are hard
to detect and debug. Thus, synchronization is a critical concept in multithreading to ensure
correctness and stability.
✅ Why it is Needed:
Imagine a situation where one thread produces data and another thread consumes it. The
consumer should wait until the producer produces data. This coordination is possible using
inter-thread communication.
✅ Achieved Using:
Java provides the following methods from the Object class:
1. wait() – causes the current thread to wait until another thread calls notify() or
notifyAll() on the same object.
2. notify() – wakes up one waiting thread.
3. notifyAll() – wakes up all waiting threads on that object.
These methods can only be called from within synchronized context (block or method),
otherwise a runtime exception is thrown.
This mechanism allows threads to pause and resume execution in a coordinated way,
making multithreading more efficient and intelligent.
✅ Types of Semaphores:
1. Counting Semaphore:
o Can have any number of permits.
o Used to limit the number of threads accessing a resource.
2. Binary Semaphore (Mutex):
o Has only 1 permit (like a lock).
o Either the resource is available or not.
✅ Key Methods:
acquire() – waits until a permit is available.
release() – releases a permit, allowing another thread to proceed.
Semaphores are useful in implementing resource pools, connection limits, and managing
bounded resources in concurrent applications.
✅ Q33. Provide examples illustrating the use of wait, notify, and notifyAll
methods for inter-thread communication (very short code).
Answer:
Here is a very short example to demonstrate the use of wait(), notify(), and notifyAll():
class SharedResource {
synchronized void produce() throws InterruptedException {
System.out.println("Producing...");
wait(); // Waits for notification
System.out.println("Resumed after notification");
}