IT234 Object Oriented Programming With Java

Object Oriented Programming With JavaUnit 1411 min read

Character Handling, Sealed Classes & Wrapper Classes in Java

Unit 14 of Object Oriented Programming With Java covers character classification, manipulation using StringBuffer, wrapper classes (autoboxing/unboxing), and sealed classes—key tools for text processing, type safety, and controlled inheritance hierarchies in Java applications.

TAKEAWAYS:

  • Character handling in Java uses Character class methods (e.g., isDigit(), isLetter()) and StringBuffer for dynamic string operations like append/insert/delete.
  • Wrapper classes (e.g., Integer, Double) convert primitives to objects and vice versa via autoboxing (implicit) and unboxing (explicit), enabling collections to store primitives.
  • Sealed classes restrict which classes can extend them, enforcing a closed hierarchy (e.g., enum or predefined subclasses) for better design control.
  • Exceptions for validation: Custom exceptions (e.g., InvalidPhoneNumberException) enforce constraints like phone number length (10 digits) in real-world data entry.
  • File I/O + character checks: Combine FileWriter/BufferedReader with Character.isLetter() to filter or process text (e.g., writing prime-length strings to files).
  • Sealed classes vs. abstract classes: Sealed classes allow limited subclassing (specified at declaration), while abstract classes require open extension unless sealed.

1. Character Handling in Java

Java provides built-in methods to classify and manipulate characters using the Character class and StringBuffer for dynamic operations.

A071@2
Character classification: 'A' (letter), '7' (digit), '@' (special)
startdigitdigitnon-digitq0q1q2
Finite Automaton for validating a 10-digit phone number (eSewa-style)

Key Methods of Character Class

Character.isDigit('5')   // true
Character.isLetter('A')  // true
Character.isWhitespace(' ') // true
Character.toUpperCase('a') // 'A'
Character.toLowerCase('B') // 'b'

Example: Check if a Character is Alphabet or Digit

import java.util.Scanner;

public class CharacterChecker {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.print("Enter a character: ");
        char ch = sc.next().charAt(0);

        if (Character.isLetter(ch)) {
            System.out.println(ch + " is an alphabet.");
        } else if (Character.isDigit(ch)) {
            System.out.println(ch + " is a digit.");
        } else {
            System.out.println(ch + " is a special character.");
        }
    }
}

Trace:

Input (ch) isLetter(ch) isDigit(ch) Output
'A' true false "A is an alphabet."
'7' false true "7 is a digit."
'@' false false "@ is a special character."

StringBuffer for Dynamic String Operations

StringBuffer is mutable (unlike String), supporting:

  • append(): Adds characters/strings.
  • insert(int pos, char ch): Inserts at position.
  • delete(int start, int end): Removes a substring.
StringBuffer sb = new StringBuffer("Hello");
sb.append(" World");  // "Hello World"
sb.insert(5, " Java"); // "Hello Java World"
sb.delete(5, 10);     // "Hello World"

Visual: StringBuffer Operations

flowchart LR
    A["Start: sb = \"Hello\""]
    B["sb.append(\" World\")"] --> C["sb = \"Hello World\""]
    D["sb.insert(5, \" Java\")"] --> E["sb = \"Hello Java World\""]
    F["sb.delete(5, 10)"] --> G["sb = \"Hello World\""]

Real-World Example: eSewa Transaction Validation

eSewa uses Character.isDigit() to validate:

  • Phone numbers (must be 10 digits).
  • Transaction PINs (must be numeric).
  • Special characters in usernames (blocked for security).

Code Snippet (eSewa-style validation):

public class TransactionValidator {
    public static boolean isValidPhone(String phone) {
        if (phone.length() != 10) return false;
        for (char ch : phone.toCharArray()) {
            if (!Character.isDigit(ch)) return false;
        }
        return true;
    }
}

2. Wrapper Classes and Autoboxing/Unboxing

Wrapper classes convert primitives (int, double) to objects (Integer, Double) and vice versa.

classDiagram
    class Integer {
        +int value
        +Integer(int)
        +toString()
    }
    class Double {
        +double value
        +Double(double)
        +isNaN()
    }
    class ArrayList {
        +add(Object)
        +get(int)
    }
    Integer --> ArrayList : stores
    Double --> ArrayList : stores
    note for Integer "Autoboxing: int → Integer\nUnboxing: Integer → int"
Wrapper classes enabling primitive storage in collections

Why Wrapper Classes?

  • Collections (e.g., ArrayList) store objects, not primitives.
  • Type safety: Methods like Integer.parseInt() validate input.
  • Utility methods: Double.isNaN(), Boolean.parseBoolean().

Common Wrapper Classes

Primitive Wrapper Class Example Methods
int Integer parseInt(), valueOf(), toString()
double Double parseDouble(), isNaN()
char Character isLetter(), toUpperCase()
boolean Boolean parseBoolean(), logicalAnd()

Autoboxing vs. Unboxing

  • Autoboxing: Implicit conversion (primitive → object).
    int num = 10;          // primitive
    Integer obj = num;     // autoboxing (int → Integer)
    
  • Unboxing: Implicit conversion (object → primitive).
    Integer obj = 20;
    int num = obj;         // unboxing (Integer → int)
    

Example: Prime-Length String File Writer

import java.io.*;

public class PrimeStringWriter {
    public static boolean isPrime(int n) {
        if (n <= 1) return false;
        for (int i = 2; i <= Math.sqrt(n); i++) {
            if (n % i == 0) return false;
        }
        return true;
    }

    public static void main(String[] args) throws IOException {
        Scanner sc = new Scanner(System.in);
        System.out.print("Enter a string: ");
        String str = sc.nextLine();

        try (FileWriter fw = new FileWriter(isPrime(str.length()) ? "Prime.txt" : "Composite.txt")) {
            fw.write(str);
        }
    }
}

Trace:

Input (str) str.length() isPrime(length) File Written
"Java" 4 false "Composite.txt"
"Hello" 5 true "Prime.txt"

Real-World Example: NEPSE Stock Data Processing

NEPSE uses Double wrappers to:

  • Parse stock prices (e.g., "123.45" → Double.parseDouble()).
  • Store prices in ArrayList<Double> for analysis.
  • Handle NaN (invalid prices) with Double.isNaN().

3. Sealed Classes in Java

Sealed classes restrict which classes can extend them, enabling controlled inheritance.

CreditCardDebitCardUPIPaymentMethod
Sealed hierarchy for eSewa/Khalti payment methods (no further extensions allowed)

Syntax

public sealed class Shape permits Circle, Rectangle, Triangle {
    // common methods
}

public final class Circle extends Shape { ... }
public non-sealed class Rectangle extends Shape { ... } // can be extended further

Key Features

  • Permits clause: Specifies allowed subclasses.
  • Final/non-sealed: Subclasses can be final (no further extension) or non-sealed (allow extension).
  • Pattern matching: Works with instanceof for type checks.

Example: Sealed Class for Payment Methods

public sealed class PaymentMethod permits CreditCard, DebitCard, UPI {
    public void processPayment(double amount) {
        System.out.println("Processing " + amount);
    }
}

public final class CreditCard extends PaymentMethod { ... }
public non-sealed class UPI extends PaymentMethod { ... } // can extend further

Visual: Sealed Class Hierarchy

classDiagram
    class PaymentMethod {
        <<sealed>>
        +processPayment(amount: double)
    }
    class CreditCard {
        <<final>>
    }
    class UPI {
        <<non-sealed>>
    }
    PaymentMethod <|-- CreditCard
    PaymentMethod <|-- UPI

Real-World Example: Pathao Driver App

Pathao uses sealed classes to:

  • Restrict ride types (Bike, Car, Auto) under a sealed Vehicle class.
  • Enforce that only predefined vehicle types can be added (no arbitrary subclasses).

4. Custom Exceptions for Validation

Custom exceptions enforce business rules (e.g., phone number length).

Example: Invalid Phone Number Exception

class InvalidPhoneNumberException extends Exception {
    public InvalidPhoneNumberException(String message) {
        super(message);
    }
}

public class Mobile {
    private String type;
    private String phoneNo;

    public Mobile(String type, String phoneNo) throws InvalidPhoneNumberException {
        if (phoneNo.length() != 10 || !phoneNo.matches("\\d+")) {
            throw new InvalidPhoneNumberException("Phone number must be 10 digits.");
        }
        this.type = type;
        this.phoneNo = phoneNo;
    }
}

Trace:

Input (phoneNo) length() == 10 matches("\\d+") Exception Thrown?
"9843276541" true true None
"123" false true InvalidPhoneNumberException
"ABC1234567" false false InvalidPhoneNumberException

Real-World Example: Ncell SIM Registration

Ncell validates phone numbers using custom exceptions to:

  • Reject numbers with non-digit characters.
  • Block numbers outside Nepal’s country code (+977).

Exam Tip

  1. Character Handling:

    • Memorize Character methods (isDigit(), isLetter()).
    • Practice StringBuffer operations (append/insert/delete) with traces.
    • Common exam question: Check if a string’s length is prime and write to a file.
  2. Wrapper Classes:

    • Differentiate autoboxing (implicit) vs. unboxing (implicit).
    • Know when to use Integer.parseInt() vs. Integer.valueOf().
    • Exam trick: Collections store objects, so primitives need wrappers.
  3. Sealed Classes:

    • Understand permits clause and final/non-sealed subclasses.
    • Compare with abstract classes (sealed = restricted extension; abstract = open extension unless sealed).
    • Exam question: Write a sealed class hierarchy (e.g., Shape with Circle, Rectangle).
  4. Custom Exceptions:

    • Extend Exception or RuntimeException.
    • Use in constructors/validators (e.g., phone number length).
    • Exam tip: Always include a throws clause or try-catch for checked exceptions.
  5. File I/O + Character Checks:

    • Combine FileWriter/BufferedReader with Character.isLetter().
    • Example: Write strings with prime lengths to "Prime.txt".

Pro Tip: For file handling questions, always:

  1. Use try-with-resources (auto-closes files).
  2. Check file existence with Files.exists() (import java.nio.file.Files).
  3. Handle IOException in main() or throw it.

In the real world

  • eSewa/Khalti: Uses Character.isDigit() to validate phone numbers (10 digits) and PINs (numeric) during registration/login. Also employs StringBuffer to dynamically build transaction messages (e.g., appending recipient names).
  • NEPSE Stock Data: Stores stock prices as Double wrappers in ArrayList<Double> for analysis, using Double.parseDouble() to convert string inputs (e.g., "123.45") and Double.isNaN() to detect invalid entries.
  • NTC/Ncell Billing: Custom exceptions (e.g., InvalidPhoneNumberException) enforce constraints like 10-digit phone numbers for SIM registration, integrating with Character checks for digit validation.

Based on the TU BITM syllabus for Object Oriented Programming With Java (IT234), unit 14.

Discussion

Loading…