Object Oriented Programming With JavaUnit 812 min read
String Manipulation & Wrapper Classes: Methods, Buffer, Builder, Parsing, Autoboxing
Unit 8 of Object Oriented Programming With Java covers Java’s immutable String class, its mutable alternatives (StringBuffer/StringBuilder), core string manipulation methods, wrapper classes for primitives, autoboxing/unboxing, and parsing techniques—with real-world examples from eSewa, Daraz, and Ncell.
TAKEAWAYS:
- Strings are immutable: Every modification creates a new object (e.g.,
concat()orreplace()). StringBuffervsStringBuilder: Thread-safeBuffer(synchronized) vs fasterBuilder(unsynchronized).- Wrapper classes: Convert primitives (
int,double) to objects (Integer,Double) for collections/generics. - Autoboxing/unboxing: Automatic conversion between primitives and wrappers (e.g.,
int x = 5;→Integer x = 5;). - Parsing: Convert strings to numbers/booleans using
Integer.parseInt(),Double.valueOf(), etc. - Common pitfalls:
==checks references (not content),equals()checks values, andsubstring()is zero-based.
1. The String Class: Immutable and Efficient
Java’s String is immutable (cannot be changed after creation). This ensures thread safety but requires careful handling for performance.
Key Methods
String str = "Hello";
| Method | Example | Description |
|---|---|---|
length() |
str.length() → 5 |
Returns string length. |
charAt(index) |
str.charAt(1) → 'e' |
Gets character at index (0-based). |
substring(start,end) |
str.substring(0,3) → "Hel" |
Extracts substring (end is exclusive). |
concat() |
"Hi".concat("!") → "Hi!" |
Concatenates (creates new String). |
toUpperCase() |
"abc".toUpperCase() → "ABC" |
Converts to uppercase. |
equals() |
"abc".equals("ABC") → false |
Case-sensitive comparison. |
equalsIgnoreCase() |
"abc".equalsIgnoreCase("ABC") → true |
Case-insensitive comparison. |
startsWith() |
"file.txt".startsWith("file") → true |
Checks prefix. |
split(regex) |
"a,b,c".split(",") → ["a","b","c"] |
Splits by delimiter. |
Why Immutability?
- Thread Safety: No risk of corruption in multi-threaded apps (e.g.,
Ncell’s SMS system). - Security: Passwords/tokens can’t be altered accidentally.
- Caching: Java pools
Stringobjects (e.g.,"Hello"is reused).
Performance Impact
String s = "";
for (int i = 0; i < 1000; i++) {
s += i; // Creates 1000 new String objects!
}
Problem: Concatenation in loops is O(n²) due to repeated object creation.
Solution: Use StringBuilder (see Section 3).
2. Real-World Example: eSewa’s Transaction IDs
eSewa generates unique transaction IDs like TXN1234567890 using:
String id = "TXN" + System.currentTimeMillis() + (int)(Math.random() * 1000);
- Why
String?- Immutable → safe for concurrent access (multiple users paying bills simultaneously).
- Methods like
substring()help extract prefixes (e.g.,"TXN").
- Why not
StringBuilder?- IDs are created once and never modified → immutability is sufficient.
3. Mutable Strings: StringBuffer and StringBuilder
For frequent modifications, use:
StringBuffer: Thread-safe (synchronized), slower.StringBuilder: Faster (no synchronization), preferred in single-threaded apps.
Key Methods
StringBuffer sb = new StringBuffer("Hello");
| Method | Example | Description |
|---|---|---|
append() |
sb.append("!") → "Hello!" |
Adds to the end. |
insert(index, str) |
sb.insert(1, "i") → "Hillo!" |
Inserts at position. |
delete(start,end) |
sb.delete(1,3) → "Hlo!" |
Deletes substring (end exclusive). |
reverse() |
"abc".reverse() → "cba" |
Reverses the string. |
replace(start,end,newStr) |
sb.replace(1,3,"XYZ") → "HXYZlo!" |
Replaces a substring. |
Performance Comparison
| Operation | String (immutable) |
StringBuffer |
StringBuilder |
|---|---|---|---|
| Concatenation | O(n²) | O(n) | O(n) |
| Thread Safety | ✅ (safe) | ✅ (synchronized) | ❌ (unsafe) |
| Use Case | Constants | Multi-threaded | Single-threaded |
FIGURE: StringBuilder Operations
flowchart LR
A["Start: \"Hello\""]
B["Append '!' → \"Hello!\""]
C["Insert 'i' at 1 → \"Hillo!\""]
D["Delete 1-3 → \"Hlo!\""]
A --> B --> C --> D4. Real-World Example: Daraz’s Order Queue
Daraz uses StringBuilder to efficiently build order summaries for thousands of users:
StringBuilder orderSummary = new StringBuilder();
orderSummary.append("Order #").append(orderId)
.append("\nItems: ").append(items)
.append("\nTotal: Rs.").append(total);
- Why
StringBuilder?- Avoids the O(n²) cost of
Stringconcatenation in loops. - Faster than
StringBuffer(no synchronization overhead).
- Avoids the O(n²) cost of
5. Wrapper Classes: Primitives to Objects
Java primitives (int, double) cannot be used in collections (e.g., ArrayList). Wrapper classes convert them to objects:
| Primitive | Wrapper Class | Example |
|---|---|---|
int |
Integer |
Integer num = 10; |
double |
Double |
Double pi = 3.14; |
char |
Character |
Character c = 'A'; |
boolean |
Boolean |
Boolean flag = true; |
Key Methods
Integer num = 10;
| Method | Example | Description |
|---|---|---|
parseInt() |
Integer.parseInt("123") → 123 |
Converts String to int. |
valueOf() |
Double.valueOf("3.14") → 3.14 |
Converts String to wrapper. |
toString() |
num.toString() → "10" |
Converts wrapper to String. |
intValue() |
num.intValue() → 10 |
Converts wrapper to primitive. |
FIGURE: Autoboxing/Unboxing
flowchart LR
A["Primitive: int x = 5"] -->|"Autoboxing"| B["Wrapper: Integer x = 5"]
B -->|"Unboxing"| C["Primitive: int y = x"]6. Autoboxing and Unboxing
Java automatically converts between primitives and wrappers:
// Autoboxing (primitive → wrapper)
int a = 10;
Integer b = a; // int → Integer
// Unboxing (wrapper → primitive)
Integer c = 20;
int d = c; // Integer → int
Use Case: Simplifies code when working with collections:
List<Integer> numbers = new ArrayList<>();
numbers.add(5); // Autoboxing: int → Integer
int num = numbers.get(0); // Unboxing: Integer → int
Performance Note
- Autoboxing adds minor overhead (e.g.,
ArrayList<Integer>is slower thanint[]). - Avoid in performance-critical loops (e.g., game physics).
7. Real-World Example: Ncell’s Call Duration Calculation
Ncell uses Double wrappers to store call durations (in seconds) for billing:
Double duration = 120.5; // Wrapper for precision
double seconds = duration; // Unboxing for calculations
- Why
Double?- Call durations can be fractional (e.g.,
120.5seconds). Doubleallows storage inArrayList<Double>for easy sorting/filtering.
- Call durations can be fractional (e.g.,
8. Parsing Strings to Primitives
Convert String to primitives using:
String numStr = "123";
int num = Integer.parseInt(numStr); // "123" → 123
| Method | Example | Description |
|---|---|---|
Integer.parseInt() |
Integer.parseInt("42") → 42 |
Parses String to int. |
Double.parseDouble() |
Double.parseDouble("3.14") → 3.14 |
Parses String to double. |
Boolean.parseBoolean() |
Boolean.parseBoolean("true") → true |
Parses String to boolean. |
Error Handling
try {
int num = Integer.parseInt("abc"); // Throws NumberFormatException
} catch (NumberFormatException e) {
System.out.println("Invalid number!");
}
Use Case: Validating user input (e.g., age in a form).
9. Real-World Example: NEPSE Stock Price Validation
NEPSE’s API returns stock prices as String (e.g., "120.50"). To calculate changes:
String priceStr = "120.50";
double price = Double.parseDouble(priceStr); // "120.50" → 120.50
double change = (price - previousPrice) / previousPrice * 100;
- Why parsing?
- Ensures correct numeric operations (e.g.,
String+String="120.50100.00").
- Ensures correct numeric operations (e.g.,
10. Common Pitfalls and Best Practices
| Pitfall | Solution |
|---|---|
Using == for String comparison |
Use equals() (e.g., "abc".equals("ABC") → false). |
| Concatenation in loops | Use StringBuilder (e.g., log generation). |
Forgetting try-catch for parsing |
Handle NumberFormatException (e.g., user input). |
| Unnecessary autoboxing | Use primitives in performance-critical code. |
FIGURE: String Comparison Pitfall
flowchart LR
A["String s1 = \"abc\";"] --> B["String s2 = new String(\"abc\");"]
B --> C["s1 == s2 → false (reference comparison)"]
B --> D["s1.equals(s2) → true (content comparison)"]11. Exam Tip
String Immutability:
- Always remember
Stringis immutable. Modifications create new objects. - Example:
"a" + "b"is optimized to"ab"(compiler usesStringpool).
- Always remember
StringBuffervsStringBuilder:StringBufferis thread-safe (use in multi-threaded apps like bank transactions).StringBuilderis faster (use in single-threaded apps like order processing).
Wrapper Classes:
- Know the 8 primitive wrappers (
Integer,Double, etc.). - Autoboxing/unboxing is automatic but has overhead.
- Know the 8 primitive wrappers (
Parsing:
parseInt()throwsNumberFormatExceptionfor invalid inputs (e.g.,"abc").- Always validate user input before parsing.
Code Examples:
- Be ready to write programs for:
- Reversing a string using
StringBuilder. - Checking if a string length is prime (using
Integerwrapper). - Concatenating strings efficiently in a loop.
- Reversing a string using
- Be ready to write programs for:
Past Exam Question Analysis:
Question: "Why do we need wrapper classes?" Answer:
Wrapper classes (e.g.,
Integer) convert primitives to objects, enabling:- Storage in collections (
ArrayList<Integer>). - Autoboxing/unboxing for concise code.
- Methods like
Integer.parseInt()for string-to-number conversion.
- Storage in collections (
Question: "Differentiate
StringBufferandString." Answer:Feature StringStringBufferMutability Immutable Mutable Thread Safety ✅ (safe) ✅ (synchronized) Performance Slower for edits Faster for edits Use Case Constants, caching Dynamic string building
Final Worked Example: Prime Length Check
import java.io.*;
public class PrimeString {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.print("Enter a string: ");
String input = br.readLine();
int length = input.length();
boolean isPrime = isPrime(length);
if (isPrime) {
FileWriter writer = new FileWriter("Prime.txt");
writer.write(input);
writer.close();
} else {
FileWriter writer = new FileWriter("Composite.txt");
writer.write(input);
writer.close();
}
}
public static boolean isPrime(int num) {
if (num <= 1) return false;
for (int i = 2; i <= Math.sqrt(num); i++) {
if (num % i == 0) return false;
}
return true;
}
}
Trace:
| Step | Action | Output File |
|---|---|---|
Input: "abc" |
Length = 3 → isPrime(3) → true |
Prime.txt |
Input: "abcd" |
Length = 4 → isPrime(4) → false |
Composite.txt |
Key Points:
- Uses
String.length()to get length. isPrime()usesint(primitive) for efficiency.- Files are written based on prime check.
Based on the TU BITM syllabus for Object Oriented Programming With Java (IT234), unit 8.
Discussion
Loading…