Java Lab Programs for AY 2024-25
Java Lab Programs for AY 2024-25
Java allows developers to create user-defined exceptions by extending the `Exception` class. This makes exception handling straightforward by using the familiar try-catch paradigm. For example, define an `AgeException` that is thrown when an invalid age is encountered: `class AgeException extends Exception { AgeException(String message) { super(message); } }`. Throw this exception using `throw new AgeException("Age must be greater than zero.");` in validation logic. Catch this in a catch block to handle scenarios where invalid data might disrupt the flow .
JDBC in Java connects to databases to perform CRUD operations (Create, Read, Update, Delete). For a student database, use a DriverManager to establish a connection: `Connection con = DriverManager.getConnection(url, user, password)`. Use Statement or PreparedStatement to execute SQL commands. For creation and insertion, `PreparedStatement pstmt = con.prepareStatement("INSERT INTO students VALUES (?, ?, ?)");` sets parameters and executes updates. Reading uses `ResultSet rs = stmt.executeQuery("SELECT * FROM students");` to fetch and iterate results. Updating and deleting involve executing `UPDATE` and `DELETE` statements, respectively, and using executeUpdate() to apply changes. This process streamlines database interactions via a consistent, SQL-based approach .
Java allows multiple inheritance through interfaces, as classes can implement multiple interfaces. For example, consider an `ArrayStack` class that implements two interfaces, `Arr` with a `disp()` method and `Stack` with `push()` and `pop()` methods. An implementation might look like: `public class ArrayStack implements Arr, Stack { ... }`. This design allows `ArrayStack` to inherit the functionality specified by both interfaces without encountering the complexity of inheriting from multiple concrete classes, thereby adhering to the concept of multiple inheritance .
Java handles file operations using the java.io package, which includes classes like FileReader, FileWriter for reading and writing files. For reading, create a FileReader: `FileReader fr = new FileReader("filename.txt");`. To write, use FileWriter: `FileWriter fw = new FileWriter("filename.txt");`. Use BufferedReader for efficient reading: `BufferedReader br = new BufferedReader(fr);`. For example, copying data from one file to another involves reading content with BufferedReader and writing with BufferedWriter: `BufferedWriter bw = new BufferedWriter(fw); String line; while ((line = br.readLine()) != null) { bw.write(line); bw.newLine(); }`. This setup allows flexible and efficient file manipulation .
The producer-consumer problem is solved in Java using inter-thread communication through the wait() and notify() methods. A shared resource, typically a buffer, is accessed by two threads: a producer, which adds data to the buffer, and a consumer, which removes data. Java's synchronized methods or blocks are used to ensure that the threads do not interfere with each other when modifying the buffer. The producer calls wait() when the buffer is full, and notify() is called by the consumer when it removes data from the buffer, thereby allowing the producer to resume work. Conversely, the consumer waits when the buffer is empty, and is notified once data is available .
A TreeMap in Java is a Red-Black tree-based implementation of the Map interface, where data is stored in sorted order of keys. To manage student data, create a TreeMap with roll numbers as keys and student names as values: `TreeMap<Integer, String> studentMap = new TreeMap<>();`. Add students using `studentMap.put(rollNumber, studentName);`. The TreeMap automatically sorts entries by roll numbers, allowing operations like retrieving the first or last entry using `firstEntry()` and `lastEntry()`, respectively .
Jagged arrays in Java are arrays of arrays with different column sizes. An example could involve creating a two-dimensional array where each row is a different length. For instance, `int[][] jaggedArray = new int[3][]; jaggedArray[0] = new int[2]; jaggedArray[1] = new int[3]; jaggedArray[2] = new int[1];` This allows each row in the array to hold a different number of elements, demonstrating how jagged arrays can accommodate non-uniform data structures .
Dynamic polymorphism in Java is achieved through dynamic method dispatch, which allows method calls to be resolved at runtime. This is done by using a superclass reference to refer to a subclass object. Method overriding is the basis for this mechanism. For example, suppose there is a superclass Person with a method `displayDetails()`, and subclasses Employee and Manager that override this method. At runtime, the overridden method of the actual object pointed to by the superclass reference is called, implementing dynamic method dispatch. This allows for flexible and reusable code structures .
A Java program can handle predefined exceptions using try-catch blocks by encasing the code that may throw exceptions within a try block and providing catch blocks to handle different exceptions. For example, handle an `ArithmeticException` and `ArrayIndexOutOfBoundsException` as follows: `try { int data = 100 / 0; } catch (ArithmeticException e) { System.out.println("Arithmetic exception caught: " + e); } try { int[] arr = new int[5]; System.out.println(arr[10]); } catch (ArrayIndexOutOfBoundsException e) { System.out.println("Array index out of bounds: " + e); }`. This allows the program to continue running after exceptions occur .
Single inheritance in Java can be demonstrated by creating a super class Account with attributes and methods common to all accounts, and a subclass SavingsAccount that extends Account. The 'super' keyword is used within SavingsAccount to access constructors, methods, and fields of the superclass. For instance, in the constructor of SavingsAccount, `super(balance);` would call the constructor of Account to initialize balance. This illustrates how derived classes can reuse and extend the functionality of their base classes .