Topics Overview: Cloning (4) Generics & Wildcards (5) Exception Handling (6) Streams (4) 17th Aug Ques (4)

Oppe 2!

Cloning

Q1.
In an athletic meet, the athletes from each school should register for 1 relay event and 2 individual events. Complete the Java program that does the following: create a dummy athlete object, create object a1 of type Athlete by cloning the dummy athlete object, create another object a2 of type Athlete by cloning a1, and then update the chest number, and individual events of a1 and a2.

Class Athlete has/should have the following functionality:

Class AthleteCloneTest contains the main method that takes the inputs and invokes appropriate methods to achieve the functionality.

Solution:

import java.util.ArrayList;
import java.util.Scanner;

class Athlete implements Cloneable {
    private String athleteChestNum;
    private ArrayList<String> events;

    public Athlete() {
        athleteChestNum = "000";
        events = new ArrayList<String>();
        events.add("Relay");       // index 0
        events.add("Ind Evt 1");   // index 1
        events.add("Ind Evt 2");   // index 2
    }

    // Mutator method to set chest number
    public void setAthleteChestNum(String num) {
        this.athleteChestNum = num;
    }

    // Mutator to update individual event 1 (index 1)
    public void setIndividualEvt1(String evt1) {
        events.set(1, evt1);
    }

    // Mutator to update individual event 2 (index 2)
    public void setIndividualEvt2(String evt2) {
        events.set(2, evt2);
    }

    // Deep cloning method
    @Override
    public Object clone() throws CloneNotSupportedException {
        Athlete cloned = (Athlete) super.clone();
        cloned.events = new ArrayList<String>(this.events); // deep copy of list
        return cloned;
    }

    // Print object
    public String toString() {
        return athleteChestNum + " " + events;
    }
}

public class AthleteCloneTest {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        Athlete dummyAthlete = new Athlete();

        try {
            Athlete a1 = (Athlete) dummyAthlete.clone();
            a1.setAthleteChestNum(sc.next());
            a1.setIndividualEvt1(sc.next());
            a1.setIndividualEvt2(sc.next());

            Athlete a2 = (Athlete) a1.clone();
            a2.setAthleteChestNum(sc.next());
            a2.setIndividualEvt1(sc.next());
            a2.setIndividualEvt2(sc.next());

            System.out.println("a1 " + a1);
            System.out.println("a2 " + a2);
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }

        sc.close();
    }
}

Q2.
Complete the Java program to create two objects a1 and a2 of type Airplane. a2 should be created from a1 using cloning such that any later changes to a2 do not affect a1.

• Class Airplane implements Cloneable interface and has/should have the following members:

– Instance variables String company, eng of type Engine, and
String model
– Constructor to initialize the instance variables
– Mutator methods as needed
– Overridden method toString()
– Implement method clone() that achieves deep copy using cloning

• Class Engine implements Cloneable interface and has/should have the following members:

– Instance variables String name and int numEngines
– Constructor to initialize the instance variables
– Mutator methods as needed
– Overridden method toString()
– Implement method clone()

• Class AirplaneCloneTest contains the main method that takes the inputs and invokes appropriate methods to achieve the functionality.

What you have to do

• Implement method clone() in class Airplane

• Implement method clone() in class Engine

Solution:

import java.util.Scanner;

class Airplane implements Cloneable {
    private String company;
    private String model;
    private Engine eng;

    public Airplane(String c, String m, Engine e) {
        company = c;
        model = m;
        eng = e;
    }

    public String toString() {
        return company + ": " + model + eng;
    }

    public void setEngine(String n, int num) {
        eng.setName(n);
        eng.setNumEngines(num);
    }

    public void setModel(String m) {
        model = m;
    }

    // ✅ Deep clone
    public Airplane clone() throws CloneNotSupportedException {
        Airplane copy = (Airplane) super.clone(); // Shallow copy
        copy.eng = eng.clone(); // Deep clone of Engine
        return copy;
    }
}

class Engine implements Cloneable {
    private String name;
    private int numEngines;

    public Engine(String n, int num) {
        name = n;
        numEngines = num;
    }

    public void setName(String n) {
        name = n;
    }

    public void setNumEngines(int n) {
        numEngines = n;
    }

    public String toString() {
        return "[" + name + ", " + numEngines + "]";
    }

    // ✅ Deep clone for Engine
    public Engine clone() throws CloneNotSupportedException {
        return (Engine) super.clone(); // Strings and ints are immutable / primitives
    }
}

public class AirplaneCloneTest {
    public static void main(String[] args) throws CloneNotSupportedException {
        Scanner sc = new Scanner(System.in);

        // Create object a1
        Airplane a1 = new Airplane(
            sc.nextLine(),     // company
            sc.next(),         // model
            new Engine(sc.next(), sc.nextInt()) // engine name, number
        );

        // Clone a1 to a2
        Airplane a2 = a1.clone();

        sc.nextLine(); // consume newline
        a2.setModel(sc.next());               // update model of a2
        a2.setEngine(sc.next(), sc.nextInt()); // update engine of a2

        System.out.println(a1); // a1 should be unchanged
        System.out.println(a2); // a2 reflects new model and engine

        sc.close();
    }
}

Q3. Write a program to clone an object e1 of class Employee by implementing the interface Cloneable. After cloning, update the department and the address of e1. Complete the program as detailed below to achieve this functionality.

Solution:

import java.util.*;

// Class Address implements Cloneable
class Address implements Cloneable {
    private String addr;

    public Address(String addr) {
        this.addr = addr;
    }

    public String getAddr() {
        return addr;
    }

    public void setAddr(String addr) {
        this.addr = addr;
    }

    @Override
    public Address clone() throws CloneNotSupportedException {
        return (Address) super.clone();
    }

    public String toString() {
        return addr;
    }
}

// Class Department implements Cloneable
class Department implements Cloneable {
    private String dept;

    public Department(String dept) {
        this.dept = dept;
    }

    public String getDept() {
        return dept;
    }

    public void setDept(String dept) {
        this.dept = dept;
    }

    @Override
    public Department clone() throws CloneNotSupportedException {
        return (Department) super.clone();
    }

    public String toString() {
        return dept;
    }
}

// Class Person implements Cloneable
class Person implements Cloneable {
    private String name;
    private Address addr;

    public Person(String name, Address addr) {
        this.name = name;
        this.addr = addr;
    }

    public String getName() {
        return name;
    }

    public Address getAddr() {
        return addr;
    }

    public void setAddr(Address addr) {
        this.addr = addr;
    }

    @Override
    public Person clone() throws CloneNotSupportedException {
        Person p = (Person) super.clone();
        p.addr = addr.clone(); // deep copy
        return p;
    }

    public String toString() {
        return name + ", " + addr;
    }
}

// Class Employee extends Person
class Employee extends Person implements Cloneable {
    private Department dept;

    public Employee(String name, Address addr, Department dept) {
        super(name, addr);
        this.dept = dept;
    }

    public Department getDept() {
        return dept;
    }

    public void setDept(Department dept) {
        this.dept = dept;
    }

    public void updateEmp(String newAddr, String newDept) {
        getAddr().setAddr(newAddr);
        dept.setDept(newDept);
    }

    @Override
    public Employee clone() throws CloneNotSupportedException {
        Employee e = (Employee) super.clone();
        e.dept = dept.clone(); // deep copy
        return e;
    }

    public String toString() {
        return super.toString() + ", " + dept;
    }
}

// Main class
public class FClass {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String n = sc.next();     // name
        String a1 = sc.next();    // address
        String d1 = sc.next();    // department
        String a2 = sc.next();    // new address
        String d2 = sc.next();    // new department

        try {
            Employee e1 = new Employee(n, new Address(a1), new Department(d1));
            Employee e2 = e1.clone(); // deep clone
            e1.updateEmp(a2, d2);     // update only e1
            System.out.println(e1 + ", " + e2);
        } catch (CloneNotSupportedException e) {
            System.out.println("clone() not supported");
        }
    }
}

Q4.

Naresh (aka Customer c1) buys a set of items from a shop. Suresh (aka Customer c2) also buys all items bought by Naresh except the first item, in place of which Suresh buys another item. Write a program that defines two classes Items and Customer, and clones the object of class Customer to model the scenario given above. Classes Items and Customer should be cloneable, and must have the functionality to clone (deep copy) c2 from c1.

You are given as input the number of items bought by Naresh, the names of the items, and the new item that Suresh will be buying. The code to change the first item and the name in the second customer object after the cloning has been provided in the given code. You should complete the program as specified below.

Define a class Items that implements interface Cloneable, and has the following members:

Define a class Customer that implements interface Cloneable, and has the following members:

Solution:

import java.util.*;

class Items implements Cloneable {
    public String[] item;

    // Constructor to initialize item array
    public Items(String[] item) {
        this.item = new String[item.length];
        for (int i = 0; i < item.length; i++) {
            this.item[i] = item[i];
        }
    }

    // Clone method (deep copy)
    public Items clone() throws CloneNotSupportedException {
        Items cloned = (Items) super.clone();
        cloned.item = this.item.clone(); // deep copy of array
        return cloned;
    }

    // toString() for Items
    public String toString() {
        return String.join(" ", item);
    }
}

class Customer implements Cloneable {
    private String name;
    private Items items;

    // Constructor
    public Customer(String name, Items items) {
        this.name = name;
        this.items = items;
    }

    // Getter for Items
    public Items getItems() {
        return items;
    }

    // Setter for name
    public void setName(String name) {
        this.name = name;
    }

    // Clone method (deep copy)
    public Customer clone() throws CloneNotSupportedException {
        Customer cloned = (Customer) super.clone();
        cloned.items = this.items.clone(); // deep copy of items
        return cloned;
    }

    // toString() for Customer
    public String toString() {
        return name + " " + items.toString();
    }
}

public class Order {
    public static void main(String[] args) throws CloneNotSupportedException {
        Scanner sc = new Scanner(System.in);

        int n = sc.nextInt(); // number of items
        String[] itm = new String[n];
        for (int i = 0; i < n; i++) {
            itm[i] = sc.next(); // reading item names
        }

        // Create original customer c1
        Customer c1 = new Customer("naresh", new Items(itm));

        // Clone c1 to create c2
        Customer c2 = c1.clone();

        // Modify c2's first item and name
        c2.getItems().item[0] = sc.next(); // update first item
        c2.setName("suresh");

        // Output
        System.out.println(c1);
        System.out.println(c2);
    }
}

Generics & Wildcards

Q1.
Complete the Java code given below that takes as input a string array, where each string is assured to be either an integer or a double in string format. Your code must segregate the two types - integer and double - and print the double values followed by the integer values. For this, your code must iterate through the input array, and add each element to the appropriate array based on its type.

Solution:

import java.util.Scanner;

class ConvertArrays{
    public Double doubleArr[] = new Double[3];
    public Integer intArr[] = new Integer[3];
    public int x = 0, y = 0, z = 0; // z unused

    public void convert(String[] arr){
        // loop through the arr and store each element in the appropriate array
        for (String s : arr) {
            // if it matches an integer format (optional sign + digits), store as Integer
            if (s.matches("[-+]?\\d+")) {
                intArr[y++] = Integer.parseInt(s);
            } else {
                // otherwise it's a double (e.g., has decimal point or exponent)
                doubleArr[x++] = Double.parseDouble(s);
            }
        }
    }

    public <T> void display(T[] arr){
        for(T elements : arr)
            System.out.print(elements + " ");
        System.out.println();
    }
}

public class Programming {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String arr[] = new String[6];
        for (int i = 0; i < arr.length; i++) {
            arr[i] = scanner.next();
        }
        ConvertArrays conArrays = new ConvertArrays();
        conArrays.convert(arr);
        System.out.println("===After conversion Arrays===");
        conArrays.display(conArrays.doubleArr);
        conArrays.display(conArrays.intArr);
    }
}

Q2.

Given as input two integers n_1,n_2 and two double values d_1,d_2 complete the Java code to form two complex numbers c_1 and c_2, as described below, and print their sum.

The real parts of c_1 and c_2 are n_1 and d_1 respectively, whereas their imaginary parts are n_2 and d_2, respectively.

Define a generic class ComplexNum with the following members:

Solution:

import java.util.*;

class ComplexNum<T extends Number> {
    T r; // real part
    T i; // imaginary part

    // Constructor to initialize real and imaginary parts
    public ComplexNum(T r, T i) {
        this.r = r;
        this.i = i;
    }

    // Method to add this ComplexNum with another, and return the result as ComplexNum<Double>
    public ComplexNum<Double> add(ComplexNum<?> other) {
        double realSum = this.r.doubleValue() + other.r.doubleValue();
        double imagSum = this.i.doubleValue() + other.i.doubleValue();
        return new ComplexNum<Double>(realSum, imagSum);
    }

    // toString method override for formatted output
    public String toString() {
        return r.doubleValue() + " + " + i.doubleValue() + "i";
    }
}

class FClass {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        // Read inputs
        int n1 = sc.nextInt();
        int n2 = sc.nextInt();
        double d1 = sc.nextDouble();
        double d2 = sc.nextDouble();

        // Create complex numbers with different generic types
        ComplexNum<Integer> c1 = new ComplexNum<>(n1, n2);
        ComplexNum<Double> c2 = new ComplexNum<>(d1, d2);

        // Add c1 and c2
        ComplexNum<Double> c3 = c1.add(c2);

        // Print the result
        System.out.println(c1 + " + " + c2 + " = " + c3);
    }
}

Q3.
Write a Java code that takes as input a positive number (length of an array here), and two arrays of that length - one of integers and another of strings. The code must also take an integer and a String as input, and print the number of occurrences of the integer and the string in the integer array and the string array, respectively.


Format of Input:

  1. Length of the arrays
  2. Elements in the integer array (in separate lines)
  3. Element to count in the integer array
  4. Elements in the string array (in separate lines)
  5. Element to count in the string array

Variables Used in the Code:

Solution:

import java.util.*;
class ArrayExample <T>{
  T[] a;
  
public ArrayExample(T[] arr){
        a = arr;
      }
      public void display(){
        for(int i = 0; i < a.length; i++){
          System.out.print(a[i] + " ");
        }
        System.out.println();
      }
      public int elementCount(T x){
        int count = 0;
        for(int i = 0; i < a.length; i++){
          if(a[i].equals(x)){
            count = count + 1;
          }
        }
        return count; 
      } 
}
public class ArrayObject{
      public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int len = sc.nextInt(); //Taking input for length of array
        Integer[] x = new Integer[len];
        for(int i = 0; i < len; i++){
          x[i] = sc.nextInt(); 
        }
        ArrayExample<Integer> obj = new ArrayExample<Integer>(x);
        int s1 = sc.nextInt(); 
        String[] y = new String[len];
        for(int i = 0; i < len; i++){
          y[i] = sc.next(); //Taking input for String array
        }
        ArrayExample<String> obj1 = new ArrayExample<String>(y);

    String s2 = sc.next(); //Taking input for the value to be counted
    obj.display();
    System.out.println(obj.elementCount(s1));
    obj1.display();
    System.out.println(obj1.elementCount(s2));
  }
}

Q4.
You are given two integers as input to form an object (r1) of type Rectangle and two double values as input to form an object r2 of type Rectangle. Complete the Java code to print the larger area among the areas of r1 and r2.

Define a generic class Rectangle with the following members:

Class Test has method main(), and takes two integers and two double values as input to create two objects of Rectangle type. It then invokes the necessary methods and prints large area.

Solution:

import java.util.*;

class Rectangle<T extends Number> {
    private T length;
    private T breadth;

    public Rectangle(T len, T bre) {
        length = len;
        breadth = bre;
    }

    // Method to calculate area
    public double area() {
        return length.doubleValue() * breadth.doubleValue();
    }

    // Generic method to compare area with another Rectangle object
    public double compareArea(Rectangle<?> other) {
        double thisArea = this.area();
        double otherArea = other.area();
        return Math.max(thisArea, otherArea);
    }
}

public class Test {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        // Create r1 from integer inputs
        Rectangle<Integer> r1 = new Rectangle<>(sc.nextInt(), sc.nextInt());

        // Create r2 from double inputs
        Rectangle<Double> r2 = new Rectangle<>(sc.nextDouble(), sc.nextDouble());

        // Compare and print larger area
        double large_area = r1.compareArea(r2);
        System.out.println(large_area);
    }
}

Q5. (This question particularly is not from Generics & Wildcards but Reflection)

Given a class name as input, complete the Java code to print the count of public and declared methods, fields and constructors in the class. For each method in class ClassStats below, fill in the missing code as described in the comments. Each method takes the class name as input.

Solution:

import java.lang.reflect.*;
import java.util.*;

class ClassStats {
    public static int getPubMethodCount(String cname) {
        try {
            //add code to return the count of 
            //public methods in the given class	
            Class<?> cls = Class.forName(cname);
            Method[] methods = cls.getMethods();
            return methods.length;
        } catch (Exception e) {
            return 0;
        }
    }

    public static int getAllMethodCount(String cname) {
        try {
            //add code to return the count of all 
            //declared methods in the given class
            Class<?> cls = Class.forName(cname);
            Method[] methods = cls.getDeclaredMethods();
            return methods.length;
        } catch (Exception e) {
            return 0;
        }
    }

    public static int getPubFieldCount(String cname) {
        try {
            //add code to return the count of 
            //public fields (instance variables) in the given class
            Class<?> cls = Class.forName(cname);
            Field[] fields = cls.getFields();
            return fields.length;
        } catch (Exception e) {
            return 0;
        }
    }

    public static int getAllFieldCount(String cname) {
        try {
            //add code to return the count of 
            //all fields (instance variables) in the given class
            Class<?> cls = Class.forName(cname);
            Field[] fields = cls.getDeclaredFields();
            return fields.length;
        } catch (Exception e) {
            return 0;
        }
    }

    public static int getPubContCount(String cname) {
        try {
            //add code to return the count of 
            //public constructors in the given class
            Class<?> cls = Class.forName(cname);
            Constructor<?>[] cons = cls.getConstructors();
            return cons.length;
        } catch (Exception e) {
            return 0;
        }
    }

    public static int getAllContCount(String cname) {
        try {
            //add code to return the count of 
            //all constructors in the given class
            Class<?> cls = Class.forName(cname);
            Constructor<?>[] cons = cls.getDeclaredConstructors();
            return cons.length;
        } catch (Exception e) {
            return 0;
        }
    }
}

class FClass {
    public static void main(String[] args) {
        String cname;
        Scanner sc = new Scanner(System.in);
        cname = sc.nextLine();
        System.out.println("Constructor: " + 
                        ClassStats.getPubContCount(cname) + ", " + 
                        ClassStats.getAllContCount(cname));
        System.out.println("Fields: " + 
                        ClassStats.getPubFieldCount(cname) + ", " +
                        ClassStats.getAllFieldCount(cname));
        System.out.println("Methods: " + 
                        ClassStats.getPubMethodCount(cname) + ", " +
                        ClassStats.getAllMethodCount(cname));
    }
}

Exception Handling

Q1.
Complete the Java program that, given a list of four applicants for a job, raises an exception if any applicant’s age is not within the prescribed age limit. For each applicant a, if a’s age is ≥ 18 and ≤ 30, then the program should print the name of a, otherwise it should print a custom message.

Solution:

import java.util.Scanner;
import java.util.ArrayList;

class Applicant {
    String name;
    int age;
    
    Applicant(String n, int a) {
        name = n;
        age = a;
    }
    
    public String checkAndGetName() throws AgeOutOfBoundsException {
        //Complete definition of method checkAndGetName
        if (age >= 18 && age <= 30) {
            return name;
        } else {
            throw new AgeOutOfBoundsException(name);
        }
    }
}

//Define class AgeOutOfBoundsException
class AgeOutOfBoundsException extends Exception {
    public AgeOutOfBoundsException(String n) {
        // Constructor initializes the message
        super("Age of " + n + " is outside the limits");
    }
}

public class ExceptionTest {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        ArrayList<Applicant> aList = new ArrayList<Applicant>();
        
        for (int i = 0; i < 4; i++) {
            Applicant a = new Applicant(sc.next(), sc.nextInt());
            aList.add(a);
        }
        
        for (Applicant a : aList) {
            try {
                String name = a.checkAndGetName();
                System.out.println(name);
            }
            catch (AgeOutOfBoundsException oe) {
                System.out.println(oe.getMessage());
            }
        }
        sc.close();
    }
}

Q2.
Write a Java program that, given a list of books, prints the title of books whose publication year is between 2000 and 2022 (including 2000, 2022). Otherwise the program raises an exception and prints a custom message. Complete the program as specified below.


What you have to do

Solution:

import java.util.Scanner;
import java.util.ArrayList;

//Define class PublicationYearOutOfBoundsException
class PublicationYearOutOfBoundsException extends Exception {
    // Constructor that takes book title and sets the error message
    public PublicationYearOutOfBoundsException(String t) {
        super("Publication year of " + t + " is outside the acceptable range");
    }
}

class Book {
    private String title;
    private int publicationYear;

    public Book(String t, int year) {
        title = t;
        publicationYear = year;
    }

    // Define method checkAndGetTitle() in class Book
    public String checkAndGetTitle() throws PublicationYearOutOfBoundsException {
        if (publicationYear >= 2000 && publicationYear <= 2022) {
            return title;
        } else {
            throw new PublicationYearOutOfBoundsException(title);
        }
    }
}

public class ExceptionTest {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        ArrayList<Book> bookList = new ArrayList<>();

        for (int i = 0; i < 4; i++) {
            Book b = new Book(sc.next(), sc.nextInt());
            bookList.add(b);
        }

        for (Book b : bookList) {
            try {
                String title = b.checkAndGetTitle();
                System.out.println(title);
            } catch (PublicationYearOutOfBoundsException pe) {
                System.out.println(pe.getMessage());
            }
        }

        sc.close();
    }
}

Q3.
Write a Java program that accepts a string, an integer i and a character c as input.
The character at position i in the given string has to be replaced by the value of c.
If the index is more than the length of the string, then it updates the last character of the given string with the value of c. If the index i is negative, then it throws an appropriate error message.

Implement the function replace such that it does the following:
It has three parameters - a character array (for the input string), an index and a character.
If the given index is in the range of the character array, it replaces the character at the given position; otherwise, catch ArrayIndexOutOfBoundsException.
In catch block (catches ArrayIndexOutOfBoundsException), if the index is beyond the length of the character array, it updates the last character of the given character array.
If the index is negative, then it rethrows the exception to forward the exception to the caller function main.

Solution:

import java.util.*;

class FClass {

    // implement function replace()
    public static char[] replace(char[] arr, int index, char c) throws ArrayIndexOutOfBoundsException {
        try {
            if (index < 0) {
                // If index is negative, explicitly throw exception
                throw new ArrayIndexOutOfBoundsException("Index cannot be negative");
            }
            arr[index] = c; // Try replacing normally
        } catch (ArrayIndexOutOfBoundsException e) {
            if (index >= arr.length) {
                // If index is beyond array length, update last character
                arr[arr.length - 1] = c;
            } else {
                // If index is negative, rethrow to main
                throw e;
            }
        }
        return arr;
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String s1 = sc.next();
        int i = sc.nextInt();
        char c = sc.next().charAt(0);
        try {
            String s2 = new String(replace(s1.toCharArray(), i, c));
            System.out.println(s2);
        } 
        catch(Exception e) {
            System.out.println(e.getMessage());
        }
    }
}

Q4.

Complete the following program which models a car rental kiosk, and handles user requests as detailed below.

The program should first accept the number of car rental requests, and then accept details of each request in the following format:

  1. Total number of passengers in the group for the rental request.
  2. Destination of the visit.

These values are used for initialization of fields inside the constructor of CarRental class.
There is a HashMap called available_destinations which contains a set of preassigned destinations and the fare for dropping at that destination. This map is also initialized in the constructor of CarRental class.

The carBooker() method processes the booking requests, and should have the following functionalities:

Solution:

import java.util.*;

// Define class WrongDestinationException
class WrongDestinationException extends Exception {
    public WrongDestinationException(String msg) {
        super(msg);
    }
}

// Define class ImproperHeadCountException
class ImproperHeadCountException extends Exception {
    public ImproperHeadCountException(String msg) {
        super(msg);
    }
}

class CarRental {
    int passenger_count;
    String chosen_destination;
    HashMap<String, Double> available_destinations;

    public CarRental(int pc, String dest) {
        passenger_count = pc;
        chosen_destination = dest;
        available_destinations = new HashMap<String, Double>();
        available_destinations.put("Marina Beach", 2000.0);
        available_destinations.put("Elliot's Beach", 5000.0);
        available_destinations.put("Film City", 8000.0);
    }

    public void carBooker() {
        try {
            if (passenger_count <= 0) {
                // message without hyphen
                throw new ImproperHeadCountException("Head count should be positive non zero value");
            }

            Double fare = available_destinations.get(chosen_destination);
            if (fare == null) {
                NullPointerException npe = new NullPointerException();
                // Wrapping WrongDestinationException inside NullPointerException
                npe.initCause(new WrongDestinationException("Invalid destination"));
                throw npe;
            }

            double perHead = fare / passenger_count;
            System.out.println("Destination: " + chosen_destination + ", Head cost: " + perHead);

        } catch (ImproperHeadCountException ihce) {
            System.out.println(ihce.getClass().getSimpleName() + ": " + ihce.getMessage());
        } catch (NullPointerException npe) {
            throw npe; // Will be caught in main
        }
    }
}

public class Test4 {
    public static void main(String args[]) {
        Scanner s = new Scanner(System.in);

        int num = s.nextInt(); // input the number of car rental requests
        try {
            for (int i = 1; i <= num; i++) {
                int heads = s.nextInt(); // enter head count
                s.nextLine(); // consume newline
                String dest = s.nextLine(); // enter destination
                CarRental obj = new CarRental(heads, dest);
                obj.carBooker();
            }
        } catch (Exception e) {
            // This will print the cause message from WrongDestinationException
            System.out.println(e.getCause());
        }
    }
}

Q5:
Recall that Java throws an ArithmeticException if there is an attempt to divide by zero. Similar to this, we can generate an exception if there is a division by three. Given two integers as input, complete the Java code given below to generate such an exception.

Create a class DivisionException that extends the class Exception.
Override the toString() method to return "Division by 3 is not allowed".

In the class Test, define divide(int a, int b) to return a/b, if the value of b is not equal to 3. If the value of b is 3, then throw an instance of DivisionException.

Inside the method main(), invoke divide(x, y), and handle any possible exception by printing the said message.

Solution:

import java.util.*;

// Custom exception class
class DivisionException extends Exception {
    public String toString() {
        return "Division by 3 is not allowed";
    }
}

public class Test {

    // Define divide() method
    public static int divide(int a, int b) throws DivisionException {
        if (b == 3) {
            throw new DivisionException();
        }
        return a / b;
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int x = sc.nextInt();
        int y = sc.nextInt();
        try {
            int c = divide(x, y);
            System.out.println(c);
        } catch (DivisionException e) {
            System.out.println(e);
        }
    }
}

Q6:
Write a Java program that accepts as input an array of 5 integers. Instead of accepting elements in the order of indices (from 0 to 4), it accepts the array as 5 pairs of integers, where each pair is an index-value pair. The first integer in a pair represents the array index (or position), with accepted values ranging from 0 to 4. The second integer is the value at that index inside the array. Note that the input may not be in the order of the indices.

If any of the given index is out of range, then your code must throw appropriate exceptions, as shown in the test cases. If all indices are within the permissible range, then the code must print the values of the array in a single line (each value followed by a space).

Define a checked exception InvalidInputEx.

Define a class IntList having the following:

Solution:

import java.util.*;

// define user defined exception InvalidInputEx
class InvalidInputEx extends Exception {
    public InvalidInputEx(String msg) {
        super(msg);
    }
}

// Define class IntList
class IntList {
    private int[] arr = new int[5];

    public void set_value(int index, int value) throws InvalidInputEx {
        try {
            arr[index] = value; // may throw ArrayIndexOutOfBoundsException
        } catch (ArrayIndexOutOfBoundsException e) {
            // Create custom checked exception with cause
            InvalidInputEx ie = new InvalidInputEx("Input index out of range");
            ie.initCause(e);
            throw ie;
        }
    }

    public int[] getArray() {
        return arr;
    }
}

class FClass {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        IntList ilist = new IntList();
        try {
            for (int i = 0; i < 5; i++) {
                int n = sc.nextInt(); // index
                int m = sc.nextInt(); // value
                ilist.set_value(n, m);
            }
        } catch (InvalidInputEx e) {
            System.out.println(e.getMessage());
            Throwable ori = e.getCause();
            System.out.println(ori.getMessage());
            return; // Exit if input was invalid
        }

        int[] i_arr = ilist.getArray();
        for (int i = 0; i < i_arr.length; i++)
            System.out.print(i_arr[i] + " ");
    }
}

Streams

Q1.
Complete the Java program that, given a list of students, prints the list of students who are eligible for a scholarship. These include the students with an average CGPA > 7.5 and whose annual family income is less than Rs.1,00,000. The program should also update the scholarship status of eligible students as “grade-1 scholarship” if their average CGPA is > 9.0; otherwise, the scholarship status should be updated as “grade-2 scholarship”.

Class Student has the following members:

Class StreamsTest has / should have the following members:

Solution:

import java.util.ArrayList;
import java.util.Scanner;
import java.util.List;
import java.util.stream.*;

class Student {
    private String name, scholarshipStatus;
    private double avgCGPA, income;

    public Student(String n, double a, double i) {
        name = n;
        avgCGPA = a;
        income = i;
        scholarshipStatus = "not eligible";
    }

    public String toString() {
        return name + " " + avgCGPA + " " +
            income + " " + scholarshipStatus;
    }

    public double getAvgCGPA() {
        return avgCGPA;
    }

    public double getIncome() {
        return income;
    }

    public void setScholarshipStatus(String ss) {
        scholarshipStatus = ss;
    }
}

// Main class
public class StreamsTest {

    // Define method getEligibleStream here
    public static Stream<Student> getEligibleStream(List<Student> list) {
        return list.stream()
            .filter(s -> s.getAvgCGPA() > 7.5 && s.getIncome() < 100000);
    }

    // Define method updateScholarshipStatus here
    public static void updateScholarshipStatus(List<Student> list) {
        for (Student s : list) {
            if (s.getAvgCGPA() > 9.0) {
                s.setScholarshipStatus("grade-1 scholarship");
            } else {
                s.setScholarshipStatus("grade-2 scholarship");
            }
        }
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        ArrayList<Student> sList = new ArrayList<Student>();
        Student s;
        for (int i = 0; i < 4; i++) {
            s = new Student(sc.next(), sc.nextDouble(), sc.nextDouble());
            sList.add(s);
        }

        List<Student> eList =
            getEligibleStream(sList).collect(Collectors.toList());
        updateScholarshipStatus(eList);

        for (Student st : eList) {
            System.out.println(st);
        }

        sc.close();
    }
}

Q2.
Write a Java program that, given as input name, age and chronicCondition of some patients, prints the filtered stream of patients whose age is below 30 and chronicCondition is Diabetes. Complete the program as specified below.


What you have to do

Solution:

import java.util.*;
import java.util.stream.*;

class Patient {
    private String name;
    private int age;
    private String chronicCondition;

    public Patient(String n, int a, String cC) {
        name = n;
        age = a;
        chronicCondition = cC;
    }

    public String toString() {
        return name + " - " + age;
    }

    public int getage() {
        return age;
    }

    public String getchronicCondition() {
        return chronicCondition;
    }

    // Define method patientProcessor
    public static Stream<Patient> patientProcessor(ArrayList<Patient> list) {
        return list.stream()
                   .filter(p -> p.getage() < 30 && p.getchronicCondition().equals("Diabetes"));
    }
}

public class StreamTest {
    public static void main(String[] args) {
        ArrayList<Patient> Patients = new ArrayList<>();
        Scanner sc = new Scanner(System.in);
        for (int i = 0; i < 4; i++) {
            Patient obj = new Patient(sc.next(), sc.nextInt(), sc.next());
            Patients.add(obj);
        }
        Stream<Patient> filteredStream = Patient.patientProcessor(Patients);
        filteredStream.forEach(System.out::println);
        sc.close();
    }
}

Q3.

A school is planning for a second Covid-19 vaccination drive on 30/03/2022, for students who have already taken the first dose. A student is eligible for the second dose if 28 days have passed since the first dose. Write a Java program to find the list of students who are eligible for the second dose of vaccination, based on the date of their first dose. Note that you must use the Stream class.

Things to be done:

  1. Define method isEligible() inside class Student that returns true if the student is eligible for the second dose.

  2. Define class StudentList inside which you have to define two methods - getEligibleList(List<Student>) and isEmpty(Stream<Student>).

  3. The method getEligibleList(List<Student>) returns a stream of eligible students using method isEligible() inside class Student

  4. The method isEmpty(Stream<Student>) checks if the stream is empty, in order to customize the output message. If the stream is empty, it should print the message: There are no eligible students. If the stream is not empty, then it prints the message: The list of eligible students are: followed by the roll numbers of eligible students.

Solution:

import java.util.stream.Stream;
import java.util.*;
import java.text.*;

class Student {
    private int roll_num;
    private Date dose_one = new Date(); 
    private Date dose_two = new Date();	

    public int getRollNo() {
        return roll_num;
    }	

    public Student(int roll_num, String dd_str) {
        SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
        this.roll_num = roll_num;
        try {			
            dose_one = sdf.parse(dd_str);		
            dose_two = sdf.parse("30/03/2022");
        }
        catch(ParseException e){
            System.out.println("Incorrect Date Format");
        }
    }	

    public boolean isEligible() {
        // Complete the method definition
        long diff = dose_two.getTime() - dose_one.getTime(); // in milliseconds
        long daysBetween = diff / (24 * 60 * 60 * 1000);      // convert to days
        return daysBetween >= 28;
    }
}

class StudentList {
    // Inside class StudentList, define method getEligibleList(List<Student>)
    // that uses the method isEligible() in class Student to return the 
    // stream of eligible students.
    public Stream<Student> getEligibleList(List<Student> students) {
        return students.stream().filter(s -> s.isEligible());
    }

    // Define method isEmpty(Stream<Student>) 
    // that helps customizing output message
    public boolean isEmpty(Stream<Student> stream) {
        return !stream.findAny().isPresent();
    }
}

public class SecondDose {
    public static void main(String[] args) {		
        Scanner sc = new Scanner(System.in);
        int roll_num;		
        String dose_one_str;
        List<Student> full_list = new ArrayList<Student>();
        
        int num = sc.nextInt(); 
        for (int i = 0; i < num; i++) {
            roll_num = sc.nextInt(); 
            dose_one_str = sc.next(); 			
            Student st = new Student(roll_num, dose_one_str);
            full_list.add(st); 
        }
        
        StudentList list = new StudentList();		
        Stream<Student> eligible_list = list.getEligibleList(full_list);
        
        if (!list.isEmpty(eligible_list)) {
            System.out.println("The list of eligible students are: ");
            // Need to regenerate stream since previous one was consumed
            eligible_list = list.getEligibleList(full_list);
            eligible_list.forEach(s -> System.out.println(s.getRollNo()));
        } else {
            System.out.println("There are no eligible students.");
        }
        
        sc.close();
    }
}

Q4.

The program stores a list of Employee objects, each of which has name, department and salary as instance variables. A user can query the list to find the Employees who belong to a specific department and have salary greater than or equal to the input salary. Complete the program as specified.

Define a class Employee as follows:

Define a function query that takes a list of employees, a department and a salary as input. It returns a stream comprising the Employee objects that have the same department and have salary greater and equal to the given salary.

Solution:

import java.util.*;
import java.util.stream.*;

// define class Employee
class Employee {
    private String name;
    private String department;
    private double salary;

    public Employee(String name, String department, double salary) {
        this.name = name;
        this.department = department;
        this.salary = salary;
    }

    public String getDep() {
        return department;
    }

    public double getSalary() {
        return salary;
    }

    @Override
    public String toString() {
        return name + " " + department + " " + salary;
    }
}

class FClass {
    // define method query
    public static Stream<Employee> query(List<Employee> empList, String department, double salary) {
        return empList.stream()
            .filter(e -> e.getDep().equals(department) && e.getSalary() >= salary);
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        var eList = new ArrayList<Employee>();
        eList.add(new Employee("Jack", "HR", 30000));
        eList.add(new Employee("Aria", "HR", 40000));
        eList.add(new Employee("Nora", "IT", 50000));
        eList.add(new Employee("Bella", "IT", 60000));
        eList.add(new Employee("Jacob", "IT", 70000));
        eList.add(new Employee("James", "HR", 80000));

        String d = sc.next();       // read department
        double s = sc.nextInt();    // read salary

        var st = query(eList, d, s);
        st.forEach(n -> System.out.println(n + " "));
    }
}

17 Aug Questions

Q1.

Merge Employee Bills

You are tasked with merging the bill data of employees from two different months. Each employee has at most one bill per month. The goal is to merge the two sets of data and calculate the total bill amount for each employee. If an employee appears in both months, their bill amounts should be summed.

What you have to do

Note: It has been observed that when there are several concurrent submissions, sometimes we get ClassNotFoundException. In this case, please refresh, try again, and try submitting multiple times.

Solution:

// Prefix goes here
import java.util.*;

class Employee {
    String name;
    int billAmount;

    public Employee(String name, int billAmount) {
        this.name = name;
        this.billAmount = billAmount;
    }

    public void addBillAmount(int additionalBill) {
        this.billAmount += additionalBill;
    }

    public String toString() {
        return name + ":" + billAmount;
    }
}

public class Test {

    // Method to merge two maps of employee bills
    public static Map<String, Employee> mergeEmployeeBills(Map<String, Employee> billMap1,
                                                           Map<String, Employee> billMap2) {
        Map<String, Employee> totalBills = new LinkedHashMap<>();

        // Copy entries from the first map (preserve insertion order)
        for (Map.Entry<String, Employee> entry : billMap1.entrySet()) {
            Employee e = entry.getValue();
            totalBills.put(entry.getKey(), new Employee(e.name, e.billAmount));
        }

        // Merge/append entries from the second map
        for (Map.Entry<String, Employee> entry : billMap2.entrySet()) {
            String id = entry.getKey();
            Employee e2 = entry.getValue();
            if (totalBills.containsKey(id)) {
                totalBills.get(id).addBillAmount(e2.billAmount);
            } else {
                totalBills.put(id, new Employee(e2.name, e2.billAmount));
            }
        }

        return totalBills;
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        Map<String, Employee> billMarch = new LinkedHashMap<>();
        Map<String, Employee> billApril = new LinkedHashMap<>();

        // Read March data (3 employees)
        for (int i = 1; i <= 3; i++) {
            String id = scanner.next();
            String name = scanner.next();
            int billAmount = Integer.parseInt(scanner.next());
            billMarch.put(id, new Employee(name, billAmount));
        }

        // Read April data (3 employees)
        for (int i = 1; i <= 3; i++) {
            String id = scanner.next();
            String name = scanner.next();
            int billAmount = Integer.parseInt(scanner.next());
            billApril.put(id, new Employee(name, billAmount));
        }

        // Merge and print totals
        Map<String, Employee> totalBills = mergeEmployeeBills(billMarch, billApril);
        for (Map.Entry<String, Employee> entry : totalBills.entrySet()) {
            System.out.println(entry.getKey() + " " + entry.getValue());
        }

        scanner.close();
    }
}

Q2.
Write a Java program that, given as input name, price and stock quantity of some products, prints the filtered stream of products that have price greater than 5000.00 and stock quantity more than 10. Complete the program as specified below.


What you have to do

Solution:

import java.util.*;
import java.util.stream.*;

class Product {
    private String name;
    private double price;
    private int stockQuantity;

    public Product(String n, double p, int sq) {
        name = n;
        price = p;
        stockQuantity = sq;
    }

    public String toString() {
        return name + " - " + price + " - In Stock: " + stockQuantity;
    }

    public double getPrice() {
        return price;
    }

    public int getStockQuantity() {
        return stockQuantity;
    }

    public static Stream<Product> productProcessor(ArrayList<Product> products) {
        return products.stream().filter(p -> p.getPrice() > 5000.00 && p.getStockQuantity() > 10);
    }
}

public class StreamTest {
    public static void main(String[] args) {
        ArrayList<Product> products = new ArrayList<>();
        Scanner sc = new Scanner(System.in);
        for (int i = 0; i < 4; i++) {
            Product product = new Product(sc.next(), sc.nextDouble(), sc.nextInt());
            products.add(product);
        }

        Stream<Product> filteredStream = Product.productProcessor(products);
        System.out.println("Premium Products with Sufficient Stock:");
        filteredStream.forEach(System.out::println);
        sc.close();
    }
}

Q3.

Complete the Java program to create two objects a1 and a2 of type Airplane.
a2 should be created from a1 using cloning such that any later changes to a2 do not affect a1.


What you have to do


import java.util.Scanner;

class Airplane implements Cloneable {
    private String company;
    private String model;
    private Engine eng;

    public Airplane(String c, String m, Engine e) {
        company = c;
        model = m;
        eng = e;
    }

    public void setEngine(String n, int num) {
        eng.setName(n);
        eng.setNumEngines(num);
    }

    public void setModel(String m) {
        model = m;
    }

    @Override
    public String toString() {
        return company + ": " + model + " " + eng;
    }

    // Deep clone: clone Airplane and its Engine
    @Override
    public Airplane clone() throws CloneNotSupportedException {
        Airplane copy = (Airplane) super.clone(); // shallow copy first
        copy.eng = eng.clone();                   // deep copy the composed Engine
        return copy;
    }
}

class Engine implements Cloneable {
    private String name;
    private int numEngines;

    public Engine(String n, int num) {
        name = n;
        numEngines = num;
    }

    public void setName(String n) {
        name = n;
    }

    public void setNumEngines(int num) {
        numEngines = num;
    }

    @Override
    public String toString() {
        return name + " " + numEngines;
    }

    // Shallow clone is sufficient here since Engine has only primitives/immutable fields
    @Override
    public Engine clone() throws CloneNotSupportedException {
        return (Engine) super.clone();
    }
}

public class AirplaneCloneTest {
    public static void main(String[] args) throws CloneNotSupportedException {
        Scanner sc = new Scanner(System.in);

        String company = sc.next();
        String model = sc.next();
        String engName = sc.next();
        int numEng = sc.nextInt();

        Airplane a1 = new Airplane(company, model, new Engine(engName, numEng));
        Airplane a2 = a1.clone();         // create a2 by cloning a1 (deep copy)

        // Modify a2 only
        a2.setModel(sc.next());
        a2.setEngine(sc.next(), sc.nextInt());

        System.out.println(a1);           // should remain unaffected
        System.out.println(a2);

        sc.close();
    }
}

Q4.
Write a Java program that takes an array of strings as input and attempts to convert each string to an integer. If any string cannot be converted to a valid integer (e.g., abc, 12a), a user-defined checked exception should be thrown.


What you have to do

Java documentation can be accessed at: https://docs.oracle.com/en/java/javase/11/docs/api

Solution :

import java.util.*;

class InvalidNumberFormatException extends Exception {
    @Override
    public String getMessage() {
        return "Invalid number format";
    }
}

class StringToIntConverter {
    private String[] strArr;

    public StringToIntConverter(String[] arr) {
        this.strArr = arr;
    }

    // Try converting every string to an int; throw checked exception if any fail
    public void convertAll() throws InvalidNumberFormatException {
        for (String s : strArr) {
            try {
                Integer.parseInt(s.trim());
            } catch (NumberFormatException e) {
                throw new InvalidNumberFormatException();
            }
        }
        System.out.println("All strings converted successfully");
    }
}

public class ConversionTest {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        sc.nextLine(); // consume newline
        String[] inputs = new String[n];
        for (int i = 0; i < n; i++) {
            inputs[i] = sc.nextLine();
        }

        try {
            StringToIntConverter conv = new StringToIntConverter(inputs);
            conv.convertAll();
        } catch (InvalidNumberFormatException e) {
            System.out.println(e.getMessage());
        }

        sc.close();
    }
}