Programming in Java

Unit 12: I/O Fundamentals & Generics

From byte streams to type-safe collections โ€” master Java's I/O architecture, serialization, and generics to build robust, production-ready applications.

โฑ๏ธ 6 hrs theory + 5 hrs lab  |  ๐Ÿ’ฐ โ‚น5Kโ€“โ‚น15K/month  |  ๐Ÿ“ 30 MCQs (Bloom's Mapped)

๐Ÿ’ผ Jobs this unlocks: Java Backend Developer (โ‚น5โ€“10 LPA)  |  Software Engineer (โ‚น6โ€“14 LPA)  |  File Automation Freelancer (โ‚น5Kโ€“15K/mo)

Section A

Opening Hook โ€” Every Aadhaar Record Travels Through Java I/O

๐Ÿข How 1.4 Billion Aadhaar Records Move Securely Across India

When you walk into an Aadhaar enrolment centre in Lucknow, the operator captures your fingerprints, iris scan, photo, and demographics. That citizen object โ€” a Java object containing your name, DOB, address, and biometric hashes โ€” must travel from a local machine in UP to UIDAI's central servers in Bengaluru.

How? Java Serialization. The citizen object is serialized (converted to a byte stream) using ObjectOutputStream, encrypted, written to a file, transmitted over the network, and deserialized at the UIDAI server using ObjectInputStream. The biometric data is marked transient โ€” it gets separate, more secure handling.

Every Aadhaar record โ€” all 1.4 billion of them โ€” has been read, written, serialized, and deserialized using Java I/O. Meanwhile, the APIs serving Aadhaar verification to banks and telecom companies use Generics to ensure type-safe data containers, so a Response<AadhaarData> can never accidentally hold a PANCard object.

What if YOU could build this? What if you could serialize any Java object to disk, read CSV files line-by-line at blazing speed, and build type-safe data structures that catch errors at compile time instead of runtime? That's exactly what this unit teaches you.

๐Ÿ‡ฎ๐Ÿ‡ณ UIDAI (Aadhaar)๐Ÿ‡ฎ๐Ÿ‡ณ Infosys๐Ÿ‡ฎ๐Ÿ‡ณ TCS๐Ÿ‡ฎ๐Ÿ‡ณ Razorpay๐Ÿ‡ฎ๐Ÿ‡ณ PhonePe๐Ÿ‡ฎ๐Ÿ‡ณ IRCTC
UIDAI's Aadhaar system is the world's largest biometric ID program. Built primarily in Java, it processes over 100 million authentication requests daily. The I/O layer alone handles petabytes of serialized data monthly. Java's stream-based I/O architecture was a key reason UIDAI chose it โ€” reliable, cross-platform, and battle-tested.
Section B

Learning Outcomes โ€” Bloom's Taxonomy Mapped (12 Outcomes)

Bloom's LevelLearning Outcome
๐Ÿ”ต RememberList the core classes in Java's byte stream and character stream hierarchies
๐Ÿ”ต RememberDefine serialization, deserialization, and the role of the transient keyword
๐Ÿ”ต UnderstandExplain how BufferedReader improves performance over raw FileReader using internal buffering
๐Ÿ”ต UnderstandDescribe why generics provide compile-time type safety and eliminate the need for explicit casting
๐ŸŸข ApplyWrite a Java program that reads a CSV file using BufferedReader and writes parsed output using BufferedWriter
๐ŸŸข ApplyImplement a generic class GenericStack<T> with push, pop, and peek operations
๐ŸŸข AnalyzeCompare Scanner vs BufferedReader for reading user input โ€” performance, parsing, and use cases
๐ŸŸข AnalyzeDifferentiate between <? extends T> (upper bound) and <? super T> (lower bound) using the PECS rule
๐ŸŸ  EvaluateAssess when to use byte streams vs character streams for different file types (binary vs text)
๐ŸŸ  EvaluateJudge the trade-offs of making a field transient vs serializing sensitive data with encryption
๐ŸŸ  CreateDesign a GenericPair<K,V> class and use it in a real-world key-value store scenario
๐ŸŸ  CreateBuild a complete Student Record Serializer that writes/reads student objects to/from binary files
Section C

Concept Explanation โ€” I/O Fundamentals & Generics

Part A โ€” Java I/O (Input / Output)

1. Byte Streams โ€” InputStream & OutputStream Hierarchy

Java I/O is built on the concept of streams โ€” an ordered sequence of data. Think of a stream like a water pipe: data flows through it in one direction, byte by byte (or character by character). Byte streams handle raw binary data โ€” images, audio, serialized objects, PDFs.

๐Ÿ“Š Byte Stream Class Hierarchy

InputStream (abstract) โ€” reads bytes

  • FileInputStream โ€” reads bytes from a file
  • BufferedInputStream โ€” adds buffering for performance
  • ObjectInputStream โ€” deserializes objects
  • ByteArrayInputStream โ€” reads from byte array in memory
  • DataInputStream โ€” reads primitive types (int, float, etc.)

OutputStream (abstract) โ€” writes bytes

  • FileOutputStream โ€” writes bytes to a file
  • BufferedOutputStream โ€” adds buffering for performance
  • ObjectOutputStream โ€” serializes objects
  • ByteArrayOutputStream โ€” writes to byte array in memory
  • DataOutputStream โ€” writes primitive types
Java
// Copy a file byte-by-byte using FileInputStream / FileOutputStream
import java.io.*;

public class ByteCopyDemo {
    public static void main(String[] args) {
        try (
            FileInputStream fis = new FileInputStream("input.jpg");
            FileOutputStream fos = new FileOutputStream("output.jpg")
        ) {
            int byteData;
            while ((byteData = fis.read()) != -1) {
                fos.write(byteData);
            }
            System.out.println("File copied successfully!");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
Forgetting to close streams! If you don't close streams, the file may remain locked, data may not flush to disk, and your program leaks resources. Always use try-with-resources (shown above) โ€” Java automatically calls close() when the block exits.

2. Character Streams โ€” Reader & Writer Hierarchy

Byte streams handle raw bytes. But text files use characters (Unicode). Reading a Hindi text file with FileInputStream can corrupt characters because it doesn't understand encoding. That's why Java provides character streams โ€” they handle encoding/decoding automatically.

๐Ÿ“Š Character Stream Class Hierarchy

Reader (abstract) โ€” reads characters

  • FileReader โ€” reads characters from a file
  • BufferedReader โ€” reads lines efficiently with buffering
  • InputStreamReader โ€” bridge from byte stream to character stream
  • StringReader โ€” reads from a String

Writer (abstract) โ€” writes characters

  • FileWriter โ€” writes characters to a file
  • BufferedWriter โ€” writes efficiently with buffering
  • OutputStreamWriter โ€” bridge from character stream to byte stream
  • PrintWriter โ€” convenient print/println methods
Java
// Reading and writing text files using FileReader / FileWriter
import java.io.*;

public class CharStreamDemo {
    public static void main(String[] args) {
        // Writing to a file
        try (FileWriter fw = new FileWriter("greeting.txt")) {
            fw.write("เคจเคฎเคธเฅเคคเฅ‡! Welcome to Java I/O.\n");
            fw.write("This handles Unicode perfectly.\n");
            System.out.println("File written successfully.");
        } catch (IOException e) {
            e.printStackTrace();
        }

        // Reading from a file
        try (FileReader fr = new FileReader("greeting.txt")) {
            int ch;
            while ((ch = fr.read()) != -1) {
                System.out.print((char) ch);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
File written successfully. เคจเคฎเคธเฅเคคเฅ‡! Welcome to Java I/O. This handles Unicode perfectly.

3. Buffered Streams โ€” BufferedReader & BufferedWriter

Analogy: Imagine filling a water tank. You can carry water one glass at a time (unbuffered โ€” 1000 trips), or carry a full bucket each time (buffered โ€” 50 trips). Buffered streams read/write large chunks internally, dramatically reducing disk I/O calls.

BufferedReader wraps a FileReader and provides the essential readLine() method โ€” the most commonly used I/O method in real Java applications.

Java
// Reading a file line-by-line with BufferedReader
import java.io.*;

public class BufferedDemo {
    public static void main(String[] args) {
        // Writing with BufferedWriter
        try (BufferedWriter bw = new BufferedWriter(
                new FileWriter("students.csv"))) {
            bw.write("Name,Roll,CGPA"); bw.newLine();
            bw.write("Arjun Patel,101,8.5"); bw.newLine();
            bw.write("Sneha Iyer,102,9.2"); bw.newLine();
            bw.write("Rahul Verma,103,7.8"); bw.newLine();
        } catch (IOException e) { e.printStackTrace(); }

        // Reading with BufferedReader
        try (BufferedReader br = new BufferedReader(
                new FileReader("students.csv"))) {
            String line;
            while ((line = br.readLine()) != null) {
                System.out.println(line);
            }
        } catch (IOException e) { e.printStackTrace(); }
    }
}
Name,Roll,CGPA Arjun Patel,101,8.5 Sneha Iyer,102,9.2 Rahul Verma,103,7.8

The File Class โ€” Inspect Before You Read

The java.io.File class doesn't read or write โ€” it represents a file path and provides metadata operations:

Java
import java.io.File;

public class FileOps {
    public static void main(String[] args) {
        File f = new File("students.csv");
        System.out.println("Exists: " + f.exists());       // true
        System.out.println("Name: " + f.getName());       // students.csv
        System.out.println("Size: " + f.length() + " bytes");
        System.out.println("Readable: " + f.canRead());  // true
        System.out.println("Writable: " + f.canWrite()); // true
        System.out.println("Path: " + f.getAbsolutePath());

        // Create a directory
        File dir = new File("backup");
        if (dir.mkdir()) System.out.println("Directory created!");

        // List files
        File cwd = new File(".");
        for (String name : cwd.list()) {
            System.out.println("  โ†’ " + name);
        }
    }
}

Scanner vs BufferedReader โ€” Which to Use?

FeatureScannerBufferedReader
Packagejava.utiljava.io
Primary UseParsing tokens (int, double, etc.)Reading lines of text fast
SpeedSlower (regex-based parsing)Faster (buffered I/O)
Buffer Size1 KB default8 KB default
Thread-safe?NoYes (synchronized)
Key MethodnextInt(), nextLine()readLine()
Best ForConsole input, small filesLarge files, production code
Interview rule of thumb: Use Scanner for quick console input in coding contests and labs. Use BufferedReader for production file processing โ€” it's 3โ€“5ร— faster for large files. Amazon and Flipkart interview questions often ask this comparison.

4. Serialization & Deserialization

Serialization = converting a Java object into a byte stream (so it can be saved to a file or sent over a network). Deserialization = reverse โ€” byte stream back to a Java object.

Think of serialization like sending a parcel via India Post. You "serialize" your gift (pack it in a box with a label), send it over the network (postal system), and the receiver "deserializes" it (opens the box). The Serializable interface is like the packing label โ€” without it, India Post (JVM) refuses to accept the parcel.

Full Code: StudentSerializer

Java
import java.io.*;

// Step 1: Implement Serializable
class Student implements Serializable {
    private static final long serialVersionUID = 1L;
    String name;
    int rollNo;
    double cgpa;
    transient String password; // Will NOT be serialized

    Student(String name, int rollNo, double cgpa, String password) {
        this.name = name;
        this.rollNo = rollNo;
        this.cgpa = cgpa;
        this.password = password;
    }

    public String toString() {
        return "Student{" + name + ", Roll:" + rollNo
             + ", CGPA:" + cgpa + ", Pass:" + password + "}";
    }
}

public class StudentSerializer {
    public static void main(String[] args) {
        Student s1 = new Student("Arjun Patel", 101, 8.5, "secret123");
        Student s2 = new Student("Sneha Iyer", 102, 9.2, "pass456");

        // SERIALIZE โ€” write objects to file
        try (ObjectOutputStream oos = new ObjectOutputStream(
                new FileOutputStream("students.ser"))) {
            oos.writeObject(s1);
            oos.writeObject(s2);
            System.out.println("โœ… Students serialized to students.ser");
        } catch (IOException e) { e.printStackTrace(); }

        // DESERIALIZE โ€” read objects back
        try (ObjectInputStream ois = new ObjectInputStream(
                new FileInputStream("students.ser"))) {
            Student d1 = (Student) ois.readObject();
            Student d2 = (Student) ois.readObject();
            System.out.println("๐Ÿ“– Deserialized:");
            System.out.println(d1);
            System.out.println(d2);
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}
โœ… Students serialized to students.ser ๐Ÿ“– Deserialized: Student{Arjun Patel, Roll:101, CGPA:8.5, Pass:null} Student{Sneha Iyer, Roll:102, CGPA:9.2, Pass:null}
Notice password is null after deserialization! The transient keyword told Java to skip that field during serialization. This is how sensitive data (passwords, OTPs, session tokens) is protected. In Aadhaar's system, biometric hashes are marked transient โ€” they travel through a separate, encrypted channel.
Always define serialVersionUID! Without it, Java auto-generates one based on class structure. If you add a field later, the UID changes, and deserialization of old files throws InvalidClassException. Set it explicitly: private static final long serialVersionUID = 1L;

Full Code: CSVFileReader

Java
import java.io.*;

public class CSVFileReader {
    public static void main(String[] args) {
        String csvFile = "students.csv";
        String delimiter = ",";

        System.out.println("โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—");
        System.out.println("โ•‘       STUDENT RECORDS FROM CSV           โ•‘");
        System.out.println("โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•");

        try (BufferedReader br = new BufferedReader(
                new FileReader(csvFile))) {
            String header = br.readLine(); // skip header
            System.out.printf("%-20s %-10s %-8s%n",
                "NAME", "ROLL", "CGPA");
            System.out.println("โ”€".repeat(38));

            String line;
            int count = 0;
            while ((line = br.readLine()) != null) {
                String[] parts = line.split(delimiter);
                if (parts.length == 3) {
                    System.out.printf("%-20s %-10s %-8s%n",
                        parts[0], parts[1], parts[2]);
                    count++;
                }
            }
            System.out.println("โ”€".repeat(38));
            System.out.println("Total records: " + count);
        } catch (IOException e) {
            System.err.println("Error reading file: " + e.getMessage());
        }
    }
}
โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•— โ•‘ STUDENT RECORDS FROM CSV โ•‘ โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• NAME ROLL CGPA โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ Arjun Patel 101 8.5 Sneha Iyer 102 9.2 Rahul Verma 103 7.8 โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ Total records: 3

Part B โ€” Java Generics

5. Why Generics? โ€” Type Safety at Compile Time

Before Java 5, collections stored Object types. You could put a String and an Integer in the same ArrayList, and it would only crash at runtime with a ClassCastException. Generics fix this โ€” they catch type errors at compile time.

Generics = vaccine syringe. A hospital syringe is the same physical device whether it holds a Covishield dose, an insulin injection, or a B12 shot. The syringe (generic class) works with any vaccine (type parameter). But once you label a syringe "Covishield" (Syringe<Covishield>), you can't accidentally fill it with insulin โ€” the label (compiler) prevents the mistake at preparation time, not after injection.
Java
// WITHOUT generics (Java 4 style) โ€” DANGEROUS
ArrayList list = new ArrayList();
list.add("Hello");
list.add(42);  // No compile error!
String s = (String) list.get(1); // ๐Ÿ’ฅ ClassCastException at RUNTIME!

// WITH generics (Java 5+) โ€” SAFE
ArrayList<String> safeList = new ArrayList<>();
safeList.add("Hello");
// safeList.add(42);  โŒ Compile error! Caught early.
String s2 = safeList.get(0); // No cast needed โœ…

Generic Class: Box<T>

Java
class Box<T> {
    private T item;

    public void put(T item) { this.item = item; }
    public T get() { return item; }
    public String toString() { return "Box[" + item + "]"; }
}

// Usage:
Box<String> nameBox = new Box<>();
nameBox.put("Arjun");
String name = nameBox.get(); // No cast needed!

Box<Integer> ageBox = new Box<>();
ageBox.put(22);
int age = ageBox.get(); // Auto-unboxing

Generic Method: <T> T getFirst(T[] arr)

Java
public class GenericMethodDemo {
    // Generic method โ€” works with any array type
    public static <T> T getFirst(T[] arr) {
        if (arr == null || arr.length == 0) return null;
        return arr[0];
    }

    public static void main(String[] args) {
        String[] names = {"Arjun", "Sneha", "Rahul"};
        Integer[] marks = {85, 92, 78};

        System.out.println(getFirst(names));  // Arjun
        System.out.println(getFirst(marks));  // 85
    }
}

Full Code: GenericStack<T>

Java
import java.util.ArrayList;

class GenericStack<T> {
    private ArrayList<T> stack = new ArrayList<>();

    public void push(T item) {
        stack.add(item);
        System.out.println("Pushed: " + item);
    }

    public T pop() {
        if (stack.isEmpty()) throw new RuntimeException("Stack empty!");
        return stack.remove(stack.size() - 1);
    }

    public T peek() {
        if (stack.isEmpty()) throw new RuntimeException("Stack empty!");
        return stack.get(stack.size() - 1);
    }

    public boolean isEmpty() { return stack.isEmpty(); }
    public int size() { return stack.size(); }

    public String toString() { return "Stack" + stack.toString(); }
}

public class StackDemo {
    public static void main(String[] args) {
        GenericStack<String> bookStack = new GenericStack<>();
        bookStack.push("Java: The Complete Reference");
        bookStack.push("Head First Java");
        bookStack.push("Effective Java");

        System.out.println("Top: " + bookStack.peek());
        System.out.println("Popped: " + bookStack.pop());
        System.out.println(bookStack);

        GenericStack<Integer> markStack = new GenericStack<>();
        markStack.push(85);
        markStack.push(92);
        System.out.println("Marks stack: " + markStack);
    }
}
Pushed: Java: The Complete Reference Pushed: Head First Java Pushed: Effective Java Top: Effective Java Popped: Effective Java Stack[Java: The Complete Reference, Head First Java] Pushed: 85 Pushed: 92 Marks stack: Stack[85, 92]

Full Code: GenericPair<K,V>

Java
class GenericPair<K, V> {
    private K key;
    private V value;

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

    public K getKey()   { return key; }
    public V getValue() { return value; }

    public String toString() {
        return "(" + key + " โ†’ " + value + ")";
    }
}

public class PairDemo {
    public static void main(String[] args) {
        // Roll number โ†’ Student name
        GenericPair<Integer, String> p1 =
            new GenericPair<>(101, "Arjun Patel");

        // Subject โ†’ Marks
        GenericPair<String, Double> p2 =
            new GenericPair<>("Java", 92.5);

        // Aadhaar โ†’ Phone
        GenericPair<String, String> p3 =
            new GenericPair<>("XXXX-XXXX-1234", "+91-98765-43210");

        System.out.println(p1);
        System.out.println(p2);
        System.out.println(p3);
    }
}
(101 โ†’ Arjun Patel) (Java โ†’ 92.5) (XXXX-XXXX-1234 โ†’ +91-98765-43210)

6. Bounded Types & Wildcards

Bounded Type: <T extends Comparable<T>>

Sometimes you need to restrict what types can be used. <T extends Comparable<T>> means "T must implement Comparable" โ€” this lets you compare and sort.

Full Code: BoundedSorter

Java
import java.util.Arrays;

class BoundedSorter {
    // Only types that implement Comparable can use this method
    public static <T extends Comparable<T>> T findMax(T[] arr) {
        T max = arr[0];
        for (T item : arr) {
            if (item.compareTo(max) > 0) {
                max = item;
            }
        }
        return max;
    }

    public static <T extends Comparable<T>> void bubbleSort(T[] arr) {
        int n = arr.length;
        for (int i = 0; i < n - 1; i++) {
            for (int j = 0; j < n - i - 1; j++) {
                if (arr[j].compareTo(arr[j+1]) > 0) {
                    T temp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = temp;
                }
            }
        }
    }

    public static void main(String[] args) {
        Integer[] marks = {78, 92, 85, 64, 97};
        System.out.println("Max mark: " + findMax(marks));
        bubbleSort(marks);
        System.out.println("Sorted: " + Arrays.toString(marks));

        String[] cities = {"Mumbai", "Ahmedabad", "Chennai", "Delhi"};
        System.out.println("Max city: " + findMax(cities));
        bubbleSort(cities);
        System.out.println("Sorted: " + Arrays.toString(cities));
    }
}
Max mark: 97 Sorted: [64, 78, 85, 92, 97] Max city: Mumbai Sorted: [Ahmedabad, Chennai, Delhi, Mumbai]

Wildcards: ?, ? extends T, ? super T (PECS Rule)

๐Ÿ“Š Wildcard Types Explained

<?> โ€” Unbounded Wildcard: Accepts any type. Use when you only need to read and don't care about the type. Example: List<?> can be List<String>, List<Integer>, etc.

<? extends T> โ€” Upper Bounded (Producer): Accepts T or any subclass of T. You can read from it (it "produces" T values). Example: List<? extends Number> accepts List<Integer>, List<Double>.

<? super T> โ€” Lower Bounded (Consumer): Accepts T or any superclass of T. You can write to it (it "consumes" T values). Example: List<? super Integer> accepts List<Number>, List<Object>.

๐Ÿง  PECS Rule: Producer Extends, Consumer Super

  • If you read from a collection (it produces values) โ†’ use extends
  • If you write to a collection (it consumes values) โ†’ use super
  • If you both read and write โ†’ don't use wildcards, use exact type
Java
import java.util.*;

public class WildcardDemo {
    // Producer Extends โ€” reads from the list
    public static double sumOfList(List<? extends Number> list) {
        double sum = 0;
        for (Number n : list) {
            sum += n.doubleValue();
        }
        return sum;
    }

    // Consumer Super โ€” writes to the list
    public static void addIntegers(List<? super Integer> list) {
        list.add(10);
        list.add(20);
        list.add(30);
    }

    public static void main(String[] args) {
        List<Integer> intList = Arrays.asList(10, 20, 30);
        List<Double> dblList = Arrays.asList(1.5, 2.5, 3.5);

        System.out.println("Int sum: " + sumOfList(intList));  // 60.0
        System.out.println("Dbl sum: " + sumOfList(dblList));  // 7.5

        List<Number> numList = new ArrayList<>();
        addIntegers(numList); // Works โ€” Number is super of Integer
        System.out.println("Numbers: " + numList); // [10, 20, 30]
    }
}

Diamond Operator <> โ€” Type Inference

Since Java 7, you don't need to repeat the type on the right side:

Java
// Before Java 7:
Map<String, List<Integer>> map = new HashMap<String, List<Integer>>();

// Java 7+ with diamond operator:
Map<String, List<Integer>> map = new HashMap<>(); // Compiler infers types โœ…
Generics don't exist at runtime! Java uses type erasure โ€” the compiler checks types, then removes all generic information from the bytecode. ArrayList<String> and ArrayList<Integer> become the same ArrayList class at runtime. This is why you can't do new T() or instanceof List<String>.
Section D

Learn by Doing โ€” 3-Tier Lab: Student Record File Serializer

๐ŸŸข Tier 1 โ€” GUIDED TASK: Serialize & Deserialize Student Records

โฑ๏ธ 45โ€“60 minutesBeginnerStep-by-step instructions

Step 1: Create the Student class

Create a class Student that implements Serializable. Fields: name (String), rollNo (int), cgpa (double), password (String, transient).

Step 2: Serialize to file

In main(), create 3 Student objects. Use ObjectOutputStream wrapped in FileOutputStream to write them to "student_records.ser".

Step 3: Deserialize from file

Use ObjectInputStream wrapped in FileInputStream to read the objects back. Print each. Verify that password is null.

Step 4: Add CSV export

After deserialization, write the student data to "student_export.csv" using BufferedWriter. Include a header row: Name,Roll,CGPA.

Step 5: Read & display CSV

Use BufferedReader to read "student_export.csv" and print it in a formatted table.

๐ŸŽ‰ Congratulations! You've built a complete serialize โ†’ export โ†’ read pipeline โ€” the same pattern used in IRCTC ticket data processing.

๐ŸŸก Tier 2 โ€” SEMI-GUIDED: Generic Collection Manager

โฑ๏ธ 60โ€“90 minutesIntermediateHints provided, you fill the gaps

Your Mission:

Build a GenericCollectionManager<T> that can store, search, sort, and serialize a list of any Comparable type.

Hints:

  1. Class Signature: class GenericCollectionManager<T extends Comparable<T> & Serializable>
  2. Methods to implement: add(T), remove(T), sort(), search(T), saveToFile(String), loadFromFile(String)
  3. Sorting: Use your bubbleSort or Collections.sort()
  4. Serialization: Serialize the entire ArrayList<T>
  5. Test with: GenericCollectionManager<String> for city names and GenericCollectionManager<Integer> for marks
Stretch Goal: Add a filter(Predicate<T>) method using Java 8 lambdas that returns filtered results.

๐Ÿ”ด Tier 3 โ€” OPEN CHALLENGE: Student Management System with File Persistence

โฑ๏ธ 2โ€“3 hoursAdvancedNo instructions โ€” real-world mini-project

The Brief:

Build a console-based Student Management System with these features:

  1. Menu-driven: Add student, View all, Search by roll, Delete by roll, Sort by CGPA, Export to CSV, Import from CSV, Save (serialize), Load (deserialize), Exit
  2. Use Generics: Store students in GenericStack<Student> or ArrayList<Student>
  3. File I/O: CSV import/export + binary serialization
  4. Error handling: File not found, invalid input, empty list
  5. Bonus: Add an undo feature using your GenericStack
This project is a portfolio piece. Upload it to GitHub with a README. Mention "File I/O, Serialization, Generics" in your resume. Recruiters at TCS, Infosys, and Wipro specifically look for these skills in campus recruitment.
Section E

Problem Set โ€” Syntax, Programming, Industry & Interview

Syntax Questions (5)

  1. Write the syntax to create a FileReader object that reads from "data.txt".
  2. Write the syntax for declaring a generic class Container with type parameter T.
  3. Write the statement to serialize an object emp using ObjectOutputStream oos.
  4. Write the syntax for a bounded generic method that accepts only Comparable types.
  5. Write a try-with-resources statement that creates a BufferedReader wrapping a FileReader.

Programming Problems (8)

  1. File Word Counter: Write a program that reads a text file using BufferedReader and counts the total number of words, lines, and characters.
  2. File Copy Utility: Write a program that copies a text file from source to destination using BufferedReader and BufferedWriter. Display byte count after copy.
  3. Student Serializer: Create a Student class with 5 fields (one transient). Serialize an array of 5 students to a file, then deserialize and display them.
  4. CSV Parser: Read a CSV file containing employee records (Name, Dept, Salary). Parse each line, calculate total salary, and write a summary report to a new file.
  5. Generic Stack: Implement a GenericStack<T> with push, pop, peek, isEmpty, size, and display. Test with String and Integer types.
  6. Generic Pair: Implement a GenericPair<K,V> class. Write a method that accepts an array of pairs and returns the pair with the maximum value (V must extend Comparable).
  7. Bounded Sorter: Write a generic method sort(T[] arr) where T extends Comparable<T>. Use insertion sort. Test with Integer[] and String[].
  8. File-Based Phone Book: Build a phone book that saves contacts to a file using serialization. Support: add, search, delete, display all, save, load.

Industry-Level Problems (3)

  1. Log File Analyzer: Given a server log file (timestamp, level, message), read it using BufferedReader, count ERROR vs WARN vs INFO entries, and write a summary report. Use GenericPair<String, Integer> to store level-count pairs.
  2. Config File Reader: Build a generic config reader that reads key=value pairs from a .properties file and stores them in a Map<String, String>. Support type-safe getters: getInt(key), getString(key), getBoolean(key).
  3. Data Pipeline: Read student records from CSV โ†’ validate (remove invalid rows) โ†’ serialize valid records โ†’ deserialize and generate a marks report โ†’ write report to a text file. Use generics for the validation step.

Interview Questions (3)

  1. TCS/Infosys: "What is the difference between Serializable and Externalizable? When would you use each?" Write a comparison with code examples.
  2. Amazon/Flipkart: "Explain the PECS rule with a real-world example. Why can't you add elements to a List<? extends Number>?" Provide code that demonstrates the compiler error.
  3. Wipro/HCL: "What is type erasure in Java generics? What are its limitations? Can you create a generic array? Why or why not?"
Section F

MCQ Assessment Bank โ€” 30 Questions (Bloom's Mapped)

Remember / Identify (Q1โ€“Q6)

Q1

Which class is used to read bytes from a file in Java?

  1. FileReader
  2. FileInputStream
  3. BufferedReader
  4. Scanner
Remember
โœ… Answer: (B) FileInputStream โ€” It reads raw bytes from a file. FileReader reads characters, not bytes.
Q2

Which interface must a class implement to be serializable?

  1. Cloneable
  2. Comparable
  3. Serializable
  4. Iterable
Remember
โœ… Answer: (C) Serializable โ€” It's a marker interface in java.io that signals the JVM that objects of this class can be serialized.
Q3

What does the transient keyword do?

  1. Makes a field constant
  2. Prevents a field from being serialized
  3. Makes a field thread-safe
  4. Makes a field accessible across packages
Remember
โœ… Answer: (B) โ€” transient fields are skipped during serialization. After deserialization, they get their default value (null for objects, 0 for numbers).
Q4

Which method of BufferedReader reads a complete line?

  1. read()
  2. readLine()
  3. nextLine()
  4. getLine()
Remember
โœ… Answer: (B) readLine() โ€” Returns a String containing the contents of the line, excluding the line terminator. Returns null at end of stream.
Q5

In Java generics, what does <T> represent?

  1. A specific class called T
  2. A type parameter placeholder
  3. The Thread class
  4. A wildcard type
Remember
โœ… Answer: (B) โ€” T is a type parameter that acts as a placeholder for any reference type. It is replaced by an actual type when the generic class/method is used.
Q6

Which class is used to serialize objects in Java?

  1. ObjectWriter
  2. FileWriter
  3. ObjectOutputStream
  4. DataOutputStream
Remember
โœ… Answer: (C) ObjectOutputStream โ€” Its writeObject() method converts a Serializable object into a byte stream.

Understand / Explain (Q7โ€“Q12)

Q7

Why is BufferedReader faster than FileReader for reading large files?

  1. It uses multithreading
  2. It reads data in large chunks from disk, reducing I/O calls
  3. It compresses the file first
  4. It skips whitespace automatically
Understand
โœ… Answer: (B) โ€” BufferedReader maintains an internal 8KB buffer. Instead of reading one character at a time from disk, it reads a large chunk at once and serves subsequent read() calls from memory.
Q8

What problem do generics solve in Java?

  1. Memory management
  2. Runtime type safety by catching type errors at compile time
  3. Faster execution speed
  4. Multi-threading synchronization
Understand
โœ… Answer: (B) โ€” Generics provide compile-time type checking, eliminating ClassCastException at runtime and removing the need for explicit type casting.
Q9

Why can't primitive types (int, double) be used as generic type parameters?

  1. Primitives are too large
  2. Generics work with Object references; primitives are not objects
  3. Primitives don't have methods
  4. It's a bug in Java
Understand
โœ… Answer: (B) โ€” Generics use type erasure, replacing T with Object at runtime. Since primitives don't extend Object, you must use wrapper classes (Integer, Double, etc.).
Q10

What happens if you serialize an object with a transient field and then deserialize it?

  1. The program throws an exception
  2. The transient field retains its original value
  3. The transient field gets its default value (null/0/false)
  4. The entire object becomes null
Understand
โœ… Answer: (C) โ€” Transient fields are not written to the byte stream. Upon deserialization, they are initialized to their type's default value.
Q11

What is the purpose of serialVersionUID?

  1. To uniquely identify each serialized object
  2. To ensure compatibility between serialized data and the class version
  3. To encrypt the serialized data
  4. To count how many times an object has been serialized
Understand
โœ… Answer: (B) โ€” serialVersionUID acts as a version number. If the class structure changes, the UID mismatch causes InvalidClassException, preventing corrupt deserialization.
Q12

What does "type erasure" mean in Java generics?

  1. Generic types are removed from memory after use
  2. The compiler replaces generic types with Object (or bounds) and removes type info from bytecode
  3. Types are encrypted during compilation
  4. Generic classes run slower than non-generic classes
Understand
โœ… Answer: (B) โ€” Type erasure ensures backward compatibility with pre-Java 5 code. The compiler enforces type safety, then removes all <T> information from the .class file.

Apply / Implement (Q13โ€“Q18)

Q13

Which code correctly reads a file line by line?

  1. FileReader fr = new FileReader("f.txt"); fr.readLine();
  2. BufferedReader br = new BufferedReader(new FileReader("f.txt")); br.readLine();
  3. Scanner sc = new Scanner("f.txt"); sc.readLine();
  4. InputStream is = new InputStream("f.txt"); is.readLine();
Apply
โœ… Answer: (B) โ€” BufferedReader wraps FileReader and provides readLine(). FileReader alone doesn't have readLine(). Scanner uses nextLine(), not readLine().
Q14

What is the output of this code?
Box<String> b = new Box<>(); b.put("Java"); System.out.println(b.get().length());

  1. 4
  2. Java
  3. Compile error
  4. Runtime error
Apply
โœ… Answer: (A) 4 โ€” b.get() returns "Java" (String), and "Java".length() returns 4. No casting needed because of generics.
Q15

Which statement correctly serializes an object?

  1. oos.serialize(obj);
  2. oos.writeObject(obj);
  3. oos.write(obj);
  4. oos.save(obj);
Apply
โœ… Answer: (B) โ€” ObjectOutputStream.writeObject(obj) is the method used for serialization.
Q16

What will this code print?
GenericPair<String, Integer> p = new GenericPair<>("Java", 12); System.out.println(p.getKey() + p.getValue());

  1. Java12
  2. 12Java
  3. Compile error
  4. Java 12
Apply
โœ… Answer: (A) Java12 โ€” String concatenation: "Java" + 12 (auto-boxed Integer converted to String) = "Java12".
Q17

Which declaration creates a FileWriter that appends to an existing file?

  1. new FileWriter("f.txt")
  2. new FileWriter("f.txt", true)
  3. new FileWriter("f.txt", "append")
  4. new FileWriter("f.txt").append()
Apply
โœ… Answer: (B) โ€” The second parameter (true) in FileWriter's constructor enables append mode. Without it, the file is overwritten.
Q18

What does this method signature mean?
public static <T extends Comparable<T>> T findMax(T[] arr)

  1. T must be a subclass of Comparable
  2. T can be any type
  3. T must implement the Comparable interface
  4. Both A and C
Apply
โœ… Answer: (D) โ€” In generics, "extends" covers both class extension and interface implementation. T must be a type that implements Comparable<T>.

Analyze / Compare (Q19โ€“Q24)

Q19

When should you use byte streams instead of character streams?

  1. When reading text files in Hindi
  2. When processing binary files (images, audio, serialized objects)
  3. When reading CSV files
  4. When using Scanner
Analyze
โœ… Answer: (B) โ€” Byte streams handle raw binary data. Character streams handle text with proper encoding. Using character streams on binary files can corrupt the data.
Q20

What is the key difference between List<?> and List<Object>?

  1. They are identical
  2. List<?> accepts List<String>, List<Integer>, etc.; List<Object> only accepts List<Object>
  3. List<Object> is faster
  4. List<?> can only hold null
Analyze
โœ… Answer: (B) โ€” Due to generics invariance, List<String> is NOT a subtype of List<Object>. But List<String> IS a subtype of List<?>. Wildcards provide flexibility.
Q21

Why is Scanner slower than BufferedReader for large file processing?

  1. Scanner doesn't buffer data
  2. Scanner uses regex-based parsing internally, adding overhead
  3. Scanner can't read files
  4. Scanner compresses data before reading
Analyze
โœ… Answer: (B) โ€” Scanner internally uses regex patterns to parse tokens (nextInt, nextDouble, etc.), which adds CPU overhead. BufferedReader.readLine() just reads raw characters without parsing.
Q22

According to the PECS rule, which wildcard should be used for a method that READS items from a list?

  1. <? super T>
  2. <? extends T>
  3. <?>
  4. No wildcard needed
Analyze
โœ… Answer: (B) โ€” PECS: Producer Extends, Consumer Super. When reading (producing) from a collection, use extends. When writing (consuming) into a collection, use super.
Q23

What happens if two classes have the same serialVersionUID but different field structures?

  1. Deserialization succeeds silently
  2. Deserialization may produce corrupt data or throw exceptions for incompatible fields
  3. The JVM automatically migrates the data
  4. The program won't compile
Analyze
โœ… Answer: (B) โ€” If the UID matches but fields are incompatible (type changes), deserialization may throw InvalidClassException or set missing fields to defaults.
Q24

Why can't you do new T() inside a generic class?

  1. T is not a real class
  2. Type erasure removes T at runtime, so JVM doesn't know which constructor to call
  3. Generics don't support constructors
  4. T must be abstract
Analyze
โœ… Answer: (B) โ€” Due to type erasure, T becomes Object at runtime. The JVM can't determine the actual class to instantiate. Workaround: pass a Class<T> parameter and use reflection.

Evaluate / Create (Q25โ€“Q30)

Q25

A banking application needs to log transaction details. Which approach is better?

  1. Use System.out.println()
  2. Use BufferedWriter with FileWriter in append mode
  3. Store in a local variable
  4. Use Scanner to write
Evaluate
โœ… Answer: (B) โ€” BufferedWriter with append mode provides persistent logging to disk, high performance through buffering, and doesn't overwrite previous entries.
Q26

You need to store employee data where some fields contain sensitive information (Aadhaar number). Best approach?

  1. Don't serialize the class at all
  2. Mark sensitive fields as transient and handle them separately with encryption
  3. Store everything in plain text
  4. Use static fields for sensitive data
Evaluate
โœ… Answer: (B) โ€” Mark sensitive fields transient to exclude from default serialization. Encrypt and store them separately through custom readObject/writeObject methods or a separate secure channel.
Q27

Which design is better for a reusable cache system?

  1. class Cache { Object[] data; }
  2. class Cache<K, V> { Map<K, V> data; }
  3. class Cache { String[] keys; String[] values; }
  4. class Cache { int[] data; }
Evaluate
โœ… Answer: (B) โ€” Generic Cache<K,V> provides type safety, reusability across different key-value types, and eliminates casting. This is exactly how libraries like Guava Cache and Caffeine are designed.
Q28

You're designing an API response wrapper for an Indian fintech app. Which approach?

  1. class Response { Object data; int statusCode; }
  2. class Response<T> { T data; int statusCode; String message; }
  3. class Response { String jsonData; }
  4. class Response extends HashMap
Create
โœ… Answer: (B) โ€” Generic Response<T> is industry standard. PhonePe, Razorpay, and Paytm all use this pattern: Response<PaymentData>, Response<UserProfile>, etc.
Q29

Design a method that can print any List regardless of its element type. Which signature is correct?

  1. void printList(List<Object> list)
  2. void printList(List<?> list)
  3. void printList(List list)
  4. void printList(List<String> list)
Create
โœ… Answer: (B) โ€” List<?> (unbounded wildcard) accepts any List type. List<Object> only accepts List<Object> due to generic invariance. Raw List (C) loses type safety.
Q30

You need to build a configuration loader that reads properties from files and returns typed values. Best class design?

  1. One method per type: getInt(), getString(), etc.
  2. A generic method: <T> T get(String key, Class<T> type)
  3. Return everything as String and let caller cast
  4. Use Object return type everywhere
Create
โœ… Answer: (B) โ€” A single generic method with Class<T> parameter provides type safety and avoids code duplication. This is the pattern used by Spring Framework's Environment.getProperty(key, type).
Section G

Short Answer Questions (8)

Q1. Differentiate between byte streams and character streams in Java.

Byte streams (InputStream/OutputStream) handle raw binary data โ€” images, audio, serialized objects. They read/write one byte (8 bits) at a time. Best for non-text files.

Character streams (Reader/Writer) handle text data with proper Unicode encoding. They read/write one character (16 bits) at a time. Essential for text files, especially those in Hindi, Tamil, or other non-ASCII scripts.

Key difference: Character streams automatically handle encoding/decoding (UTF-8, UTF-16), while byte streams treat all data as raw bytes.

Q2. What is serialization? Why is it needed?

Serialization is the process of converting a Java object into a byte stream so it can be saved to a file, transmitted over a network, or stored in a database. Deserialization is the reverse โ€” reconstructing the object from bytes.

Why needed: (1) Persisting object state between program runs. (2) Sending objects between JVMs across a network (RMI, socket programming). (3) Caching objects. (4) Deep copying objects.

Requirement: The class must implement java.io.Serializable.

Q3. Explain the role of the transient keyword with an example.

The transient keyword marks a field to be excluded from serialization. When the object is serialized, transient fields are skipped. After deserialization, they contain default values (null for objects, 0 for numbers, false for boolean).

Use case: Passwords, OTPs, session tokens, cached computed values, and database connections should never be serialized for security and safety reasons.

Example: transient String password; โ€” after deserialization, password will be null.

Q4. Why are generics preferred over using Object type?

Type safety: Generics catch type errors at compile time, not runtime. With Object, a ClassCastException only shows up when the program runs.

No casting: With ArrayList<String>, you get String directly. With ArrayList (raw), you must cast: (String) list.get(0).

Code reusability: Write one class (Box<T>) that works for any type, instead of BoxString, BoxInteger, etc.

Readability: List<Student> clearly communicates intent; List doesn't.

Q5. What is the PECS rule? Explain with an example.

PECS = Producer Extends, Consumer Super.

Producer Extends: If a method reads from a collection (it "produces" values), use <? extends T>. Example: double sum(List<? extends Number> list) โ€” can accept List<Integer>, List<Double>, etc.

Consumer Super: If a method writes to a collection (it "consumes" values), use <? super T>. Example: void addInts(List<? super Integer> list) โ€” can accept List<Number>, List<Object>.

Analogy: A vending machine (producer) extends โ€” it gives you specific snacks. A trash can (consumer) is super โ€” it accepts anything.

Q6. Compare Scanner and BufferedReader for file reading.

Scanner (java.util): Good for parsing typed input (nextInt, nextDouble). Uses regex internally โ€” slower. 1KB buffer. Not thread-safe. Best for console input and small files.

BufferedReader (java.io): Reads raw text lines fast. 8KB buffer. Thread-safe (synchronized). No built-in parsing โ€” you must use Integer.parseInt() etc. Best for large files and production code.

Bottom line: Scanner for convenience, BufferedReader for performance.

Q7. What is a bounded type parameter? Give syntax and use case.

A bounded type parameter restricts the types that can be used as a generic argument.

Syntax: <T extends UpperBound> โ€” T must be UpperBound or a subtype of it.

Example: <T extends Comparable<T>> ensures T can be compared, enabling sorting and finding max/min.

Multiple bounds: <T extends Comparable<T> & Serializable> โ€” T must implement both interfaces.

Use case: A generic sort method that only works with types that have a natural ordering.

Q8. Explain try-with-resources for I/O operations.

Try-with-resources (Java 7+) automatically closes resources (streams, connections) when the try block finishes, even if an exception occurs.

Syntax: try (BufferedReader br = new BufferedReader(new FileReader("f.txt"))) { ... }

Requirements: The resource must implement AutoCloseable (or Closeable). All Java I/O streams implement this.

Benefit: Eliminates resource leaks. No need for explicit finally { br.close(); } blocks. Cleaner, safer code.

Section H

Long Answer Questions (3)

Q1. Explain the Java I/O stream hierarchy with a complete diagram. Discuss byte streams vs character streams with code examples for reading and writing files. (15 marks)

Answer Structure:

1. Stream Hierarchy Overview

Java I/O is built on four abstract base classes:

CategoryInputOutput
Byte StreamsInputStreamOutputStream
Character StreamsReaderWriter

2. Byte Streams (Binary Data)

Handle raw binary data โ€” 8 bits at a time. Used for images, audio, serialized objects, PDFs.

Key classes: FileInputStream, FileOutputStream, BufferedInputStream, BufferedOutputStream, ObjectInputStream, ObjectOutputStream, DataInputStream, DataOutputStream.

Java
// Byte stream example: copying an image file
try (FileInputStream fis = new FileInputStream("photo.jpg");
     FileOutputStream fos = new FileOutputStream("backup.jpg")) {
    byte[] buffer = new byte[4096];
    int bytesRead;
    while ((bytesRead = fis.read(buffer)) != -1) {
        fos.write(buffer, 0, bytesRead);
    }
}

3. Character Streams (Text Data)

Handle Unicode text โ€” 16 bits at a time. Automatically handle encoding (UTF-8, UTF-16).

Key classes: FileReader, FileWriter, BufferedReader, BufferedWriter, PrintWriter, InputStreamReader, OutputStreamWriter.

Java
// Character stream example: reading a text file
try (BufferedReader br = new BufferedReader(new FileReader("notes.txt"))) {
    String line;
    while ((line = br.readLine()) != null) {
        System.out.println(line);
    }
}

4. Buffered Streams โ€” Performance Optimization

BufferedReader/BufferedWriter use an internal buffer (8KB default), reducing the number of physical disk I/O operations. A file read with FileReader makes one disk call per character; BufferedReader makes one disk call per 8192 characters.

5. When to Use Which

ScenarioUse
Read/write images, audioByte streams (FileInputStream/FileOutputStream)
Read/write text filesCharacter streams (BufferedReader/BufferedWriter)
Serialize Java objectsObjectOutputStream/ObjectInputStream
Read typed console inputScanner
High-performance text readingBufferedReader

Q2. Explain Java serialization and deserialization. Discuss the Serializable interface, transient keyword, and serialVersionUID with a complete working program. (15 marks)

Answer Structure:

1. What is Serialization?

Converting a Java object's state to a byte stream for storage or transmission. The byte stream can be saved to a file, sent over a network (sockets, RMI), or stored in a database as a BLOB.

2. Serializable Interface

A marker interface (no methods) in java.io. A class must implement it to be serializable. If a non-serializable object is passed to writeObject(), a NotSerializableException is thrown.

3. transient Keyword

Fields marked transient are excluded from serialization. After deserialization, they hold default values. Use for: passwords, cached values, logger references, non-serializable fields.

4. serialVersionUID

A version identifier for the class. If the class changes (fields added/removed) and the UID doesn't match, deserialization throws InvalidClassException. Best practice: always declare it explicitly.

5. Complete Program

Java
import java.io.*;

class Employee implements Serializable {
    private static final long serialVersionUID = 2L;
    String name;
    int empId;
    double salary;
    transient String sessionToken;

    Employee(String name, int empId, double salary, String token) {
        this.name = name; this.empId = empId;
        this.salary = salary; this.sessionToken = token;
    }

    public String toString() {
        return name + " | ID:" + empId + " | โ‚น" + salary
             + " | Token:" + sessionToken;
    }
}

public class SerializationDemo {
    public static void main(String[] args) throws Exception {
        Employee e = new Employee("Priya", 1001, 85000, "abc-xyz-123");

        // Serialize
        ObjectOutputStream oos = new ObjectOutputStream(
            new FileOutputStream("emp.ser"));
        oos.writeObject(e);
        oos.close();

        // Deserialize
        ObjectInputStream ois = new ObjectInputStream(
            new FileInputStream("emp.ser"));
        Employee d = (Employee) ois.readObject();
        ois.close();

        System.out.println(d);
        // Output: Priya | ID:1001 | โ‚น85000.0 | Token:null
    }
}

Key observations: sessionToken is null after deserialization because it was marked transient. All other fields are correctly restored.

Q3. Explain Java generics in detail โ€” generic classes, generic methods, bounded types, and wildcards. Provide code for a generic data structure. (15 marks)

Answer Structure:

1. What Are Generics?

Generics allow you to write classes, interfaces, and methods that work with any type while providing compile-time type safety. Introduced in Java 5 (2004).

2. Generic Class

Java
class Container<T> {
    private T data;
    public void set(T data) { this.data = data; }
    public T get() { return data; }
}

3. Generic Method

Java
public static <T> void printArray(T[] arr) {
    for (T item : arr) System.out.print(item + " ");
}

4. Bounded Types

<T extends Number> restricts T to Number or its subclasses. Multiple bounds: <T extends Comparable<T> & Serializable>.

5. Wildcards (PECS Rule)

<?> = any type, <? extends T> = read-only (producer), <? super T> = write-only (consumer).

6. Complete Generic Data Structure โ€” Sorted List

Java
import java.util.*;

class SortedList<T extends Comparable<T>> {
    private List<T> items = new ArrayList<>();

    public void add(T item) {
        items.add(item);
        Collections.sort(items);
    }

    public T getMin() { return items.get(0); }
    public T getMax() { return items.get(items.size()-1); }
    public String toString() { return items.toString(); }
}

// Works with Integer, String, or any Comparable type!
SortedList<Integer> marks = new SortedList<>();
marks.add(78); marks.add(92); marks.add(65);
System.out.println(marks); // [65, 78, 92]

7. Type Erasure

The compiler removes all generic type information from bytecode for backward compatibility. Box<String> and Box<Integer> become the same Box class at runtime. This is why you can't use instanceof with generics or create generic arrays.

Section I

Lab Program 10 โ€” Java I/O: Console & File Operations

๐Ÿ”ฌ Lab 10: Read/Write Using Console (Scanner/BufferedReader) AND File (FileReader/FileWriter/BufferedWriter)

โฑ๏ธ 90โ€“120 minutesIntermediateFull code + viva + extension

Aim:

To demonstrate Java I/O operations for both console-based and file-based input/output using Scanner, BufferedReader, FileReader, FileWriter, and BufferedWriter.

Full Code:

Java
import java.io.*;
import java.util.Scanner;

public class Lab10_JavaIO {

    // โ”€โ”€ PART 1: Console Input with Scanner โ”€โ”€
    public static void consoleWithScanner() {
        Scanner sc = new Scanner(System.in);
        System.out.println("โ•โ•โ• PART 1: Console Input (Scanner) โ•โ•โ•");

        System.out.print("Enter your name: ");
        String name = sc.nextLine();

        System.out.print("Enter your age: ");
        int age = sc.nextInt();

        System.out.print("Enter your CGPA: ");
        double cgpa = sc.nextDouble();

        System.out.println("\n๐Ÿ“‹ Scanner Output:");
        System.out.println("Name: " + name);
        System.out.println("Age: " + age);
        System.out.println("CGPA: " + cgpa);
        sc.close();
    }

    // โ”€โ”€ PART 2: Console Input with BufferedReader โ”€โ”€
    public static void consoleWithBufferedReader() throws IOException {
        BufferedReader br = new BufferedReader(
            new InputStreamReader(System.in));
        System.out.println("\nโ•โ•โ• PART 2: Console Input (BufferedReader) โ•โ•โ•");

        System.out.print("Enter city name: ");
        String city = br.readLine();

        System.out.print("Enter pincode: ");
        int pin = Integer.parseInt(br.readLine());

        System.out.println("\n๐Ÿ“‹ BufferedReader Output:");
        System.out.println("City: " + city + ", PIN: " + pin);
    }

    // โ”€โ”€ PART 3: File Write with FileWriter โ”€โ”€
    public static void writeWithFileWriter() throws IOException {
        System.out.println("\nโ•โ•โ• PART 3: Writing with FileWriter โ•โ•โ•");
        FileWriter fw = new FileWriter("lab10_output.txt");
        fw.write("Line 1: Welcome to Java I/O Lab.\n");
        fw.write("Line 2: FileWriter writes character by character.\n");
        fw.write("Line 3: เคจเคฎเคธเฅเคคเฅ‡ โ€” Unicode works!\n");
        fw.close();
        System.out.println("โœ… Written to lab10_output.txt using FileWriter.");
    }

    // โ”€โ”€ PART 4: File Read with FileReader โ”€โ”€
    public static void readWithFileReader() throws IOException {
        System.out.println("\nโ•โ•โ• PART 4: Reading with FileReader โ•โ•โ•");
        FileReader fr = new FileReader("lab10_output.txt");
        int ch;
        while ((ch = fr.read()) != -1) {
            System.out.print((char) ch);
        }
        fr.close();
    }

    // โ”€โ”€ PART 5: File Write with BufferedWriter โ”€โ”€
    public static void writeWithBufferedWriter() throws IOException {
        System.out.println("\nโ•โ•โ• PART 5: Writing with BufferedWriter โ•โ•โ•");
        try (BufferedWriter bw = new BufferedWriter(
                new FileWriter("lab10_students.csv"))) {
            bw.write("Name,Roll,CGPA,City"); bw.newLine();
            bw.write("Arjun Patel,101,8.5,Ahmedabad"); bw.newLine();
            bw.write("Sneha Iyer,102,9.2,Chennai"); bw.newLine();
            bw.write("Rahul Verma,103,7.8,Lucknow"); bw.newLine();
            bw.write("Priya Sharma,104,8.9,Delhi"); bw.newLine();
            bw.write("Kiran Das,105,7.2,Kolkata"); bw.newLine();
        }
        System.out.println("โœ… Written to lab10_students.csv using BufferedWriter.");
    }

    // โ”€โ”€ PART 6: File Read with BufferedReader โ”€โ”€
    public static void readWithBufferedReader() throws IOException {
        System.out.println("\nโ•โ•โ• PART 6: Reading CSV with BufferedReader โ•โ•โ•");
        try (BufferedReader br = new BufferedReader(
                new FileReader("lab10_students.csv"))) {
            String header = br.readLine();
            System.out.printf("%-18s %-8s %-8s %-12s%n",
                "NAME", "ROLL", "CGPA", "CITY");
            System.out.println("โ”".repeat(46));

            String line;
            int count = 0;
            double totalCgpa = 0;
            while ((line = br.readLine()) != null) {
                String[] parts = line.split(",");
                if (parts.length == 4) {
                    System.out.printf("%-18s %-8s %-8s %-12s%n",
                        parts[0], parts[1], parts[2], parts[3]);
                    totalCgpa += Double.parseDouble(parts[2]);
                    count++;
                }
            }
            System.out.println("โ”".repeat(46));
            System.out.printf("Total: %d students | Avg CGPA: %.2f%n",
                count, totalCgpa / count);
        }
    }

    // โ”€โ”€ MAIN METHOD โ”€โ”€
    public static void main(String[] args) throws IOException {
        System.out.println("โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—");
        System.out.println("โ•‘      LAB 10 โ€” JAVA I/O OPERATIONS           โ•‘");
        System.out.println("โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•\n");

        // Uncomment to test console input:
        // consoleWithScanner();
        // consoleWithBufferedReader();

        // File operations (no console input needed):
        writeWithFileWriter();
        readWithFileReader();
        writeWithBufferedWriter();
        readWithBufferedReader();

        System.out.println("\n๐ŸŽ‰ Lab 10 complete!");
    }
}
โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•— โ•‘ LAB 10 โ€” JAVA I/O OPERATIONS โ•‘ โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• โ•โ•โ• PART 3: Writing with FileWriter โ•โ•โ• โœ… Written to lab10_output.txt using FileWriter. โ•โ•โ• PART 4: Reading with FileReader โ•โ•โ• Line 1: Welcome to Java I/O Lab. Line 2: FileWriter writes character by character. Line 3: เคจเคฎเคธเฅเคคเฅ‡ โ€” Unicode works! โ•โ•โ• PART 5: Writing with BufferedWriter โ•โ•โ• โœ… Written to lab10_students.csv using BufferedWriter. โ•โ•โ• PART 6: Reading CSV with BufferedReader โ•โ•โ• NAME ROLL CGPA CITY โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ” Arjun Patel 101 8.5 Ahmedabad Sneha Iyer 102 9.2 Chennai Rahul Verma 103 7.8 Lucknow Priya Sharma 104 8.9 Delhi Kiran Das 105 7.2 Kolkata โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ” Total: 5 students | Avg CGPA: 8.32 ๐ŸŽ‰ Lab 10 complete!

๐ŸŽค Viva Questions (5)

  1. Q: What is the difference between FileReader and BufferedReader?
    A: FileReader reads one character at a time from disk. BufferedReader wraps FileReader and reads large chunks into an internal buffer, then serves reads from memory. BufferedReader also provides readLine().
  2. Q: Why do we use try-with-resources instead of manually closing streams?
    A: try-with-resources guarantees the stream is closed even if an exception occurs, preventing resource leaks. Manual close() in finally blocks is verbose and error-prone.
  3. Q: What happens if you write to a file using FileWriter without specifying append mode?
    A: The file is overwritten. Previous contents are lost. To append, use new FileWriter("file.txt", true).
  4. Q: How does BufferedWriter's newLine() differ from writing "\n"?
    A: newLine() writes the platform-specific line separator (\r\n on Windows, \n on Linux). Using "\n" directly may cause issues on Windows systems.
  5. Q: Can BufferedReader read binary files (e.g., .jpg)?
    A: No, BufferedReader is a character stream designed for text. For binary files, use BufferedInputStream/FileInputStream. Using character streams on binary data can corrupt it.

๐Ÿš€ Extension Challenge

Modify the lab program to:

  1. Accept student records from console using Scanner
  2. Write them to CSV using BufferedWriter
  3. Read the CSV back and find the student with highest CGPA
  4. Write a "topper report" to a separate text file
  5. Add error handling for invalid CGPA values (must be 0.0โ€“10.0)
Section J

Industry Spotlight โ€” A Day in the Life

๐Ÿ‘จโ€๐Ÿ’ป Rahul Deshpande, 28 โ€” Backend Developer at Amazon India, Hyderabad

Background: B.Tech (CSE) from COEP, Pune. First learned Java I/O during his 3rd semester. Interned at a Pune-based startup where he built file-processing microservices. Joined Amazon India through off-campus hiring (LeetCode + system design).

A Typical Day:

9:30 AM โ€” Morning standup with the Seller Central team. Current sprint: optimise bulk product upload pipeline โ€” sellers upload 50,000+ products via CSV files.

10:00 AM โ€” Code review a colleague's PR. The new CSV parser uses BufferedReader with a 32KB buffer for faster reads. Rahul spots a missing try-with-resources and flags it.

11:00 AM โ€” Write a generic BatchProcessor<T extends Serializable> class that serializes failed upload batches for retry. Uses ObjectOutputStream to save failed records to S3.

1:00 PM โ€” Lunch at Amazon's cafeteria. Quick chat about generics vs raw types with a junior dev who's getting ClassCastExceptions.

2:00 PM โ€” Debug a production issue: a seller's CSV file has BOM (Byte Order Mark) characters. Solution: use InputStreamReader with explicit UTF-8 encoding instead of plain FileReader.

4:00 PM โ€” Design review for a new feature: Response<T> wrapper for all Seller API responses. Uses generics to ensure type-safe JSON deserialization.

5:30 PM โ€” Mentor a junior developer on Java serialization best practices โ€” serialVersionUID, transient fields, custom readObject/writeObject.

DetailInfo
Tools Used DailyJava 17, IntelliJ IDEA, BufferedReader/Writer, ObjectStreams, Generics, AWS S3, DynamoDB
Entry Salary (2024)โ‚น15โ€“22 LPA (Amazon SDE-1)
Mid-Level (3โ€“5 yrs)โ‚น25โ€“40 LPA (SDE-2)
Senior (7+ yrs)โ‚น45โ€“70 LPA (SDE-3)
Companies Using Java I/O + GenericsAmazon, Flipkart, Razorpay, PhonePe, Paytm, TCS, Infosys, Wipro, UIDAI, IRCTC
Rahul's advice: "I/O and Generics seem boring when you're learning, but they're in EVERY Java interview and EVERY production codebase. When I was debugging a CSV parser at 2 AM during Prime Day, I was grateful I understood buffering. Learn it well โ€” it's the plumbing of Java."
Section K

Earn With It โ€” File Automation Scripts โ‚น5Kโ€“โ‚น15K/month

๐Ÿ’ฐ Your Earning Path After This Unit

Portfolio Piece: A Java-based Student Record Management System with CSV import/export, serialization, and generic data structures โ€” hosted on GitHub.

Freelance Gig Ideas:

โ€ข CSV/Excel file parser for small businesses (inventory, attendance) โ€” โ‚น3,000โ€“โ‚น8,000/project

โ€ข Bulk file renamer/organiser script (photos, invoices, receipts) โ€” โ‚น2,000โ€“โ‚น5,000

โ€ข Automated report generator: read data from files โ†’ generate formatted text/CSV reports โ€” โ‚น5,000โ€“โ‚น12,000

โ€ข Log file analyzer for local IT companies โ€” โ‚น4,000โ€“โ‚น10,000

โ€ข Data migration scripts (convert old file formats to new CSV/JSON) โ€” โ‚น5,000โ€“โ‚น15,000

PlatformBest ForTypical Rate
InternshalaIndian student freelance projectsโ‚น3,000โ€“โ‚น10,000/project
FiverrQuick file processing gigs$15โ€“$60/gig
UpworkJava automation projects$20โ€“$50/hour
LinkedInDirect outreach to IT companiesโ‚น5,000โ€“โ‚น15,000/project
Local BusinessesShops, schools, clinics needing file automationโ‚น2,000โ€“โ‚น8,000/project

โฑ๏ธ Time to First Earning: 2โ€“4 weeks (complete the lab programs + build one real project + create Fiverr/Internshala profile)

Quick win: Many local businesses in India still manage data in text files or messy spreadsheets. Offer to build a Java program that reads their old data, cleans it, and generates organised CSV reports. Charge โ‚น5,000 for the first project. Get a testimonial. Scale up.
Section L

Chapter Summary

๐Ÿง  Key Takeaways โ€” Unit 12

  • Byte Streams (InputStream/OutputStream) handle binary data; Character Streams (Reader/Writer) handle text with Unicode support.
  • BufferedReader/BufferedWriter dramatically improve I/O performance through internal buffering (8KB default).
  • The File class provides file metadata operations โ€” exists, size, create directory, list files.
  • Scanner is for convenience (parsing tokens); BufferedReader is for performance (reading large files fast).
  • Serialization converts objects to bytes (ObjectOutputStream); Deserialization reverses it (ObjectInputStream). Class must implement Serializable.
  • transient excludes fields from serialization; serialVersionUID ensures class version compatibility.
  • Generics provide compile-time type safety, eliminating ClassCastException and manual casting.
  • Generic classes (Box<T>), generic methods (<T> T getFirst()), and bounded types (<T extends Comparable<T>>) enable reusable, type-safe code.
  • Wildcards: <?> = any type, <? extends T> = read (Producer Extends), <? super T> = write (Consumer Super).
  • Diamond operator <> enables type inference in Java 7+.
  • Type erasure removes generic type info from bytecode for backward compatibility.

๐Ÿฆ Code Tweet โ€” Unit 12 in 280 Characters

Java I/O: InputStreamโ†’bytes, Readerโ†’chars. BufferedReader=fast. Serializable+ObjectOutputStream=save objects. transient=skip secrets. Generics: Box<T>=type-safe. <?extends T>=read, <?super T>=write. PECS rule. Diamond<>=less typing. ๐Ÿš€ #JavaIO #Generics

Section M

Checkpoint โ€” Self-Assessment

TopicTool / ConceptOutput / DeliverableEarning Ready?
Byte StreamsFileInputStream / FileOutputStreamFile copy programโœ… Yes โ€” binary file processing
Character StreamsFileReader / FileWriterText file read/writeโœ… Yes โ€” text processing scripts
Buffered I/OBufferedReader / BufferedWriterCSV parser with formatted outputโœ… Yes โ€” CSV automation gigs
File ClassFile operationsFile metadata inspectorโœ… Yes โ€” file management tools
SerializationObjectOutputStream / ObjectInputStreamStudent serializer programโœ… Yes โ€” data persistence
transient & serialVersionUIDConceptual + CodeSecure serialization demoโœ… Yes โ€” interview ready
Generic ClassesBox<T>, GenericStack<T>, GenericPair<K,V>Reusable data structuresโœ… Yes โ€” library design
Bounded Types<T extends Comparable<T>>BoundedSorter programโœ… Yes โ€” algorithm design
Wildcards & PECS<?>, <? extends T>, <? super T>Wildcard demo programsโœ… Yes โ€” API design
Lab 10Scanner, BufferedReader, FileWriter, BufferedWriterComplete I/O lab programโœ… Yes โ€” lab exam ready
Minimum Viable Earning Setup after this unit: A GitHub profile with 2โ€“3 Java file processing projects + an Internshala/Fiverr profile offering "Java File Automation & CSV Processing" = you can earn โ‚น5,000โ€“โ‚น15,000/month from file automation gigs while still in college.

โœ… Unit 12 complete. MCQs: 30. Lab 10 covered. Ready for Unit 13!

[QR: Link to EduArtha video tutorial โ€” Java I/O Fundamentals & Generics]