Java Tutorial
🔍

Java String Basics

Java String Basics

Every Java program deals with text — usernames, messages, product names, addresses, error messages. All of that text is handled using String. It is the most used class in Java, and also one of the most misunderstood.

A String in Java is a sequence of characters. What makes it different from a plain char[] is that String comes with built-in methods for searching, comparing, transforming, and combining text — and it has a special behaviour called immutability that every developer must understand to avoid bugs and write efficient code.

Creating Strings — Two Ways

There are two ways to create a String in Java, and they behave differently in memory.

Java
1// File: StringCreationDemo.java 2 3public class StringCreationDemo { 4 5 public static void main(String[] args) { 6 7 // Way 1 — String literal (most common, recommended) 8 // Java stores this in the String Pool — a special memory area 9 String name1 = "Priya"; 10 String name2 = "Priya"; // reuses the same object from the pool 11 12 // Way 2 — new keyword (creates a new object every time) 13 String name3 = new String("Priya"); 14 String name4 = new String("Priya"); // another new object 15 16 // == compares references (memory addresses) 17 System.out.println("name1 == name2 : " + (name1 == name2)); // true — same pool object 18 System.out.println("name1 == name3 : " + (name1 == name3)); // false — different objects 19 System.out.println("name3 == name4 : " + (name3 == name4)); // false — both new objects 20 21 // .equals() compares content — always use this for comparison 22 System.out.println("name1.equals(name3) : " + name1.equals(name3)); // true — same content 23 System.out.println("name3.equals(name4) : " + name3.equals(name4)); // true — same content 24 } 25}
Output:
name1 == name2 : true
name1 == name3 : false
name3 == name4 : false
name1.equals(name3) : true
name3.equals(name4) : true
Memory picture:

String Pool (special area in heap):
  ┌──────────────┐
  │  "Priya"     │ ◄── name1 and name2 both point here
  └──────────────┘

Heap (regular area):
  ┌──────────────┐   ┌──────────────┐
  │  "Priya"     │   │  "Priya"     │
  └──────────────┘   └──────────────┘
       ▲                    ▲
     name3                name4

Use String literals (String s = "hello") in almost all situations. They are more memory-efficient because Java reuses the same object for identical strings in the pool. Use new String(...) only in rare cases where you explicitly need a separate object.

String Immutability — The Most Important Concept

A String object cannot be changed after it is created. This is called immutability. When you call methods like toUpperCase(), replace(), or trim() on a String, they do not modify the original — they return a brand new String object with the result.

Java
1// File: ImmutabilityDemo.java 2 3public class ImmutabilityDemo { 4 5 public static void main(String[] args) { 6 7 String city = "mumbai"; 8 9 System.out.println("Original : " + city); 10 11 // toUpperCase() does NOT change 'city' — it returns a NEW String 12 String upperCity = city.toUpperCase(); 13 14 System.out.println("city after toUpperCase() : " + city); // still "mumbai" 15 System.out.println("upperCity : " + upperCity); // "MUMBAI" 16 17 // Common beginner mistake — forgetting to capture the result 18 city.toUpperCase(); // result is thrown away — city is unchanged 19 System.out.println("city after ignored call : " + city); // still "mumbai" 20 21 // Correct — capture the returned string 22 city = city.toUpperCase(); // reassign to update the variable 23 System.out.println("city after reassignment : " + city); // "MUMBAI" 24 25 System.out.println(); 26 27 // Chaining is safe because each step returns a new String 28 String messy = " Hello, World! "; 29 String cleaned = messy.trim().toLowerCase().replace(",", ""); 30 System.out.println("messy : '" + messy + "'"); 31 System.out.println("cleaned: '" + cleaned + "'"); 32 // messy is completely unchanged 33 } 34}
Output:
Original : mumbai
city after toUpperCase() : mumbai
upperCity                : MUMBAI
city after ignored call  : mumbai
city after reassignment  : MUMBAI

messy  : '  Hello, World!  '
cleaned: 'hello world!'

The most common beginner mistake is calling a String method and ignoring the return value — and then wondering why the String did not change. The rule is: always capture the result. String methods never modify the object they are called on.

String Length and Character Access

Java
1// File: StringLengthCharDemo.java 2 3public class StringLengthCharDemo { 4 5 public static void main(String[] args) { 6 7 String message = "Hello, India!"; 8 9 // length() — number of characters including spaces and punctuation 10 System.out.println("String : " + message); 11 System.out.println("Length : " + message.length()); // 13 12 13 // charAt(index) — character at a specific position (0-based index) 14 System.out.println("charAt(0) : " + message.charAt(0)); // H 15 System.out.println("charAt(7) : " + message.charAt(7)); // I 16 System.out.println("Last char : " + message.charAt(message.length() - 1)); // ! 17 18 System.out.println(); 19 20 // Loop through every character 21 System.out.println("Characters one by one:"); 22 for (int i = 0; i < message.length(); i++) { 23 System.out.print(message.charAt(i) + " "); 24 } 25 System.out.println(); 26 27 System.out.println(); 28 29 // isEmpty() — true only if length is 0 30 String empty = ""; 31 String spaces = " "; 32 String text = "hello"; 33 34 System.out.println("empty.isEmpty() : " + empty.isEmpty()); // true 35 System.out.println("spaces.isEmpty() : " + spaces.isEmpty()); // false — has spaces 36 System.out.println("text.isEmpty() : " + text.isEmpty()); // false 37 38 // isBlank() — true if empty OR only whitespace (Java 11+) 39 System.out.println("empty.isBlank() : " + empty.isBlank()); // true 40 System.out.println("spaces.isBlank() : " + spaces.isBlank()); // true — only spaces 41 System.out.println("text.isBlank() : " + text.isBlank()); // false 42 } 43}
Output:
String  : Hello, India!
Length  : 13
charAt(0) : H
charAt(7) : I
Last char : !

Characters one by one:
H e l l o ,   I n d i a ! 

empty.isEmpty()  : true
spaces.isEmpty() : false
text.isEmpty()   : false
empty.isBlank()  : true
spaces.isBlank() : true
text.isBlank()   : false

isEmpty() only returns true for a string with zero characters. isBlank() (Java 11+) also returns true for strings that contain only spaces, tabs, or other whitespace — which is more useful when validating user input where someone might enter just spaces.

Common String Methods

These are the methods every Java developer uses daily.

Java
1// File: CommonStringMethods.java 2 3public class CommonStringMethods { 4 5 public static void main(String[] args) { 6 7 String sentence = " Welcome to DevStackFlow "; 8 9 // trim() — removes leading and trailing whitespace 10 System.out.println("Original : '" + sentence + "'"); 11 System.out.println("trimmed : '" + sentence.trim() + "'"); 12 13 // strip() — same as trim() but handles Unicode whitespace (Java 11+) 14 System.out.println("stripped : '" + sentence.strip() + "'"); 15 16 System.out.println(); 17 18 String product = "Wireless Headphones - Premium Edition"; 19 20 // toUpperCase() / toLowerCase() 21 System.out.println("upper: " + product.toUpperCase()); 22 System.out.println("lower: " + product.toLowerCase()); 23 24 System.out.println(); 25 26 // contains() — checks if a substring exists anywhere 27 System.out.println("contains 'Headphones': " + product.contains("Headphones")); // true 28 System.out.println("contains 'laptop' : " + product.contains("laptop")); // false 29 30 // startsWith() / endsWith() 31 System.out.println("starts 'Wireless': " + product.startsWith("Wireless")); // true 32 System.out.println("ends 'Edition' : " + product.endsWith("Edition")); // true 33 34 System.out.println(); 35 36 // replace() — replaces all occurrences 37 String original = "I love Java. Java is great. Java forever."; 38 String replaced = original.replace("Java", "Python"); 39 System.out.println("original : " + original); 40 System.out.println("replaced : " + replaced); 41 42 System.out.println(); 43 44 // substring() — extracts a part of the string 45 String fullName = "Priya Sharma"; 46 System.out.println("Full name : " + fullName); 47 System.out.println("First name : " + fullName.substring(0, 5)); // "Priya" 48 System.out.println("Last name : " + fullName.substring(6)); // "Sharma" 49 50 System.out.println(); 51 52 // indexOf() — position of first occurrence (-1 if not found) 53 String email = "priya@flipkart.com"; 54 int atPos = email.indexOf('@'); 55 System.out.println("Email : " + email); 56 System.out.println("@ at pos : " + atPos); // 5 57 System.out.println("Username : " + email.substring(0, atPos)); // priya 58 System.out.println("Domain : " + email.substring(atPos + 1)); // flipkart.com 59 } 60}
Output:
Original : '  Welcome to DevStackFlow  '
trimmed  : 'Welcome to DevStackFlow'
stripped : 'Welcome to DevStackFlow'

upper: WIRELESS HEADPHONES - PREMIUM EDITION
lower: wireless headphones - premium edition

contains 'Headphones': true
contains 'laptop'    : false
starts 'Wireless': true
ends 'Edition'   : true

original : I love Java. Java is great. Java forever.
replaced : I love Python. Python is great. Python forever.

Full name  : Priya Sharma
First name : Priya
Last name  : Sharma

@ at pos : 5
Username : priya
Domain   : flipkart.com

String Comparison — equals() vs equalsIgnoreCase() vs ==

Java
1// File: StringComparisonDemo.java 2 3public class StringComparisonDemo { 4 5 public static void main(String[] args) { 6 7 String input = "Admin"; 8 String stored = "admin"; 9 String ref = input; 10 11 // == compares references — almost always wrong for content comparison 12 System.out.println("== check:"); 13 System.out.println(" input == stored : " + (input == stored)); // false 14 System.out.println(" input == ref : " + (input == ref)); // true (same object) 15 16 System.out.println(); 17 18 // equals() — exact content match, case-sensitive 19 System.out.println("equals():"); 20 System.out.println(" 'Admin'.equals('admin') : " + input.equals(stored)); // false 21 System.out.println(" 'Admin'.equals('Admin') : " + input.equals("Admin")); // true 22 23 // equalsIgnoreCase() — content match, case-insensitive 24 System.out.println(); 25 System.out.println("equalsIgnoreCase():"); 26 System.out.println(" 'Admin'.equalsIgnoreCase('admin') : " 27 + input.equalsIgnoreCase(stored)); // true 28 29 // compareTo() — lexicographic comparison (like dictionary order) 30 // Returns 0 if equal, negative if first < second, positive if first > second 31 System.out.println(); 32 System.out.println("compareTo():"); 33 String a = "Apple"; 34 String b = "Banana"; 35 String c = "Apple"; 36 System.out.println(" 'Apple' compareTo 'Banana' : " + a.compareTo(b)); // negative 37 System.out.println(" 'Apple' compareTo 'Apple' : " + a.compareTo(c)); // 0 38 System.out.println(" 'Banana' compareTo 'Apple' : " + b.compareTo(a)); // positive 39 40 System.out.println(); 41 42 // Best practice — put the known string first to avoid NullPointerException 43 String userInput = null; 44 45 // Risky — throws NullPointerException if userInput is null 46 // if (userInput.equals("admin")) { ... } 47 48 // Safe — known non-null string calls equals 49 boolean isAdmin = "admin".equals(userInput); 50 System.out.println("Safe null check: " + isAdmin); // false — no NPE 51 } 52}
Output:
== check:
  input == stored : false
  input == ref    : true

equals():
  'Admin'.equals('admin') : false
  'Admin'.equals('Admin') : true

equalsIgnoreCase():
  'Admin'.equalsIgnoreCase('admin') : true

compareTo():
  'Apple' compareTo 'Banana'  : -1
  'Apple' compareTo 'Apple'   : 0
  'Banana' compareTo 'Apple'  : 1

Safe null check: false

Always use equals() or equalsIgnoreCase() for string content comparison — never ==. When comparing against a known string constant, put the constant on the left side: "admin".equals(userInput). This way, even if userInput is null, no NullPointerException is thrown.

String Concatenation

Java
1// File: ConcatenationDemo.java 2 3public class ConcatenationDemo { 4 5 public static void main(String[] args) { 6 7 // + operator — simplest, works anywhere 8 String firstName = "Rohan"; 9 String lastName = "Mehta"; 10 String fullName = firstName + " " + lastName; 11 System.out.println("Full name : " + fullName); 12 13 // concat() method — same as +, but only works with Strings 14 String greeting = "Hello, ".concat(firstName).concat("!"); 15 System.out.println("Greeting : " + greeting); 16 17 // String.format() — structured output with placeholders 18 String orderId = "ORD-501"; 19 double amount = 1299.50; 20 String status = "PLACED"; 21 String summary = String.format("Order %s | Rs.%.2f | %s", orderId, amount, status); 22 System.out.println("Summary : " + summary); 23 24 System.out.println(); 25 26 // Concatenation with non-String types — Java calls toString() automatically 27 int age = 24; 28 double salary = 45000.0; 29 boolean active = true; 30 31 System.out.println("Age: " + age); 32 System.out.println("Salary: " + salary); 33 System.out.println("Active: " + active); 34 35 System.out.println(); 36 37 // + with numbers — beware of operator precedence 38 int x = 10, y = 20; 39 System.out.println("Result: " + x + y); // "Result: 1020" — string concat 40 System.out.println("Result: " + (x + y)); // "Result: 30" — arithmetic first 41 System.out.println(x + y + " is the sum"); // "30 is the sum" — left to right 42 43 System.out.println(); 44 45 // StringBuilder — efficient for building strings in loops 46 StringBuilder sb = new StringBuilder(); 47 String[] items = {"Laptop", "Mouse", "Keyboard", "Monitor"}; 48 for (int i = 0; i < items.length; i++) { 49 sb.append(items[i]); 50 if (i < items.length - 1) sb.append(", "); 51 } 52 System.out.println("Cart items : " + sb.toString()); 53 } 54}
Output:
Full name   : Rohan Mehta
Greeting    : Hello, Rohan!
Summary     : Order ORD-501 | Rs.1299.50 | PLACED

Age: 24
Salary: 45000.0
Active: true

Result: 1020
Result: 30
30 is the sum

Cart items  : Laptop, Mouse, Keyboard, Monitor

The + operator creates a new String object every time. Inside a loop that concatenates many strings, this creates many temporary objects. StringBuilder avoids this — it accumulates all parts in a mutable buffer and converts to a String only once at the end with toString().

String Splitting and Joining

Java
1// File: SplitJoinDemo.java 2 3import java.util.Arrays; 4 5public class SplitJoinDemo { 6 7 public static void main(String[] args) { 8 9 // split() — breaks a string at a delimiter, returns String array 10 String csvRow = "Priya,28,Bengaluru,Engineering"; 11 String[] parts = csvRow.split(","); 12 13 System.out.println("CSV row : " + csvRow); 14 System.out.println("Parts : " + Arrays.toString(parts)); 15 System.out.println("Name : " + parts[0]); 16 System.out.println("Age : " + parts[1]); 17 System.out.println("City : " + parts[2]); 18 System.out.println("Dept : " + parts[3]); 19 20 System.out.println(); 21 22 // split with limit — limits number of resulting parts 23 String sentence = "one:two:three:four:five"; 24 String[] limited = sentence.split(":", 3); // max 3 parts 25 System.out.println("Limited split: " + Arrays.toString(limited)); 26 27 System.out.println(); 28 29 // String.join() — joins elements with a separator 30 String joined = String.join(", ", "Mumbai", "Delhi", "Bengaluru", "Pune"); 31 System.out.println("Joined cities: " + joined); 32 33 // join from an array 34 String[] skills = {"Java", "SQL", "Spring Boot", "Git"}; 35 String skillSet = String.join(" | ", skills); 36 System.out.println("Skills : " + skillSet); 37 38 System.out.println(); 39 40 // Practical use — parse a full name 41 String fullName = "Ananya Krishnan Iyer"; 42 String[] nameParts = fullName.split(" "); 43 System.out.println("First : " + nameParts[0]); 44 System.out.println("Middle: " + nameParts[1]); 45 System.out.println("Last : " + nameParts[2]); 46 } 47}
Output:
CSV row : Priya,28,Bengaluru,Engineering
Parts   : [Priya, 28, Bengaluru, Engineering]
Name    : Priya
Age     : 28
City    : Bengaluru
Dept    : Engineering

Limited split: [one, two, three:four:five]

Joined cities: Mumbai, Delhi, Bengaluru, Pune
Skills       : Java | SQL | Spring Boot | Git

First : Ananya
Middle: Krishnan
Last  : Iyer

split() accepts a regular expression as the delimiter — not just a plain character. Splitting on . (dot) does not work as expected because . means "any character" in regex. To split on a literal dot, use split("\\.").

String vs StringBuilder vs StringBuffer — Comparison Table

AspectStringStringBuilderStringBuffer
MutabilityImmutable — cannot changeMutable — can modifyMutable — can modify
Thread safetyYes — immutable is always thread-safeNo — not thread-safeYes — all methods synchronized
PerformanceSlow in loops — creates new object each timeFast — modifies in placeSlower than StringBuilder — sync overhead
When to useSingle values, constants, comparisonsBuilding strings in loops or one threadBuilding strings shared across multiple threads
Main methodsHundreds of read methodsappend(), insert(), delete(), reverse()Same as StringBuilder
Can use +YesNo — use append()No — use append()
StorageString Pool or HeapHeap onlyHeap only
Java versionSince Java 1.0Since Java 1.5Since Java 1.0

Real-World Example 1 — User Registration Validator

The Business Problem

Every app has a registration form. Before saving a new user to the database, the server must validate that the name is not empty, the email is in the correct format, and the phone number is exactly 10 digits. String methods handle all of this cleanly.

Java
1// File: RegistrationValidator.java 2 3public class RegistrationValidator { 4 5 // Validates a full name — not blank, at least two words 6 public static String validateName(String name) { 7 if (name == null || name.isBlank()) { 8 return "Name cannot be empty."; 9 } 10 String trimmed = name.trim(); 11 if (!trimmed.contains(" ")) { 12 return "Please enter both first and last name."; 13 } 14 if (trimmed.length() < 4) { 15 return "Name is too short."; 16 } 17 return "OK"; 18 } 19 20 // Validates email format — must contain @ and a domain with dot 21 public static String validateEmail(String email) { 22 if (email == null || email.isBlank()) { 23 return "Email cannot be empty."; 24 } 25 String trimmed = email.trim().toLowerCase(); 26 int atIndex = trimmed.indexOf('@'); 27 28 if (atIndex <= 0) { 29 return "Email must contain '@'."; 30 } 31 String domain = trimmed.substring(atIndex + 1); 32 if (!domain.contains(".") || domain.startsWith(".") || domain.endsWith(".")) { 33 return "Invalid email domain."; 34 } 35 return "OK"; 36 } 37 38 // Validates phone — exactly 10 digits, no spaces or dashes 39 public static String validatePhone(String phone) { 40 if (phone == null || phone.isBlank()) { 41 return "Phone cannot be empty."; 42 } 43 String digits = phone.trim().replaceAll("[\\s\\-]", ""); // remove spaces/dashes 44 if (digits.length() != 10) { 45 return "Phone must be exactly 10 digits."; 46 } 47 for (char ch : digits.toCharArray()) { 48 if (!Character.isDigit(ch)) { 49 return "Phone must contain only digits."; 50 } 51 } 52 return "OK"; 53 } 54 55 // Formats a display name from a raw full name input 56 public static String formatDisplayName(String rawName) { 57 if (rawName == null || rawName.isBlank()) return ""; 58 59 String[] parts = rawName.trim().toLowerCase().split("\\s+"); 60 StringBuilder formatted = new StringBuilder(); 61 62 for (String part : parts) { 63 if (part.length() > 0) { 64 // Capitalise first letter of each word 65 formatted.append(Character.toUpperCase(part.charAt(0))); 66 formatted.append(part.substring(1)); 67 formatted.append(" "); 68 } 69 } 70 return formatted.toString().trim(); 71 } 72}
Java
1// File: RegistrationDemo.java 2 3public class RegistrationDemo { 4 5 public static void main(String[] args) { 6 7 System.out.println("=== Registration Validation ===\n"); 8 9 // Test cases for name 10 String[] names = {null, "", " ", "Priya", " priya sharma ", "PriyaSharma"}; 11 System.out.println("Name Validation:"); 12 for (String name : names) { 13 System.out.printf(" %-25s → %s%n", 14 "'" + name + "'", 15 RegistrationValidator.validateName(name)); 16 } 17 18 System.out.println(); 19 20 // Test cases for email 21 String[] emails = {"", "priya", "priya@", "priya@gmail", "priya@gmail.com", "PRIYA@MEESHO.IN"}; 22 System.out.println("Email Validation:"); 23 for (String email : emails) { 24 System.out.printf(" %-25s → %s%n", 25 "'" + email + "'", 26 RegistrationValidator.validateEmail(email)); 27 } 28 29 System.out.println(); 30 31 // Test cases for phone 32 String[] phones = {"", "98765", "9876543210", "98765 43210", "abcdefghij"}; 33 System.out.println("Phone Validation:"); 34 for (String phone : phones) { 35 System.out.printf(" %-25s → %s%n", 36 "'" + phone + "'", 37 RegistrationValidator.validatePhone(phone)); 38 } 39 40 System.out.println(); 41 42 // Format display name 43 System.out.println("Display Name Formatting:"); 44 String[] rawNames = {"priya sharma", "ROHAN MEHTA", " sneha rao ", "deepak"}; 45 for (String raw : rawNames) { 46 System.out.printf(" %-25s → '%s'%n", 47 "'" + raw + "'", 48 RegistrationValidator.formatDisplayName(raw)); 49 } 50 } 51}
Output:
=== Registration Validation ===

Name Validation:
  'null'                    → Name cannot be empty.
  ''                        → Name cannot be empty.
  '  '                      → Name cannot be empty.
  'Priya'                   → Please enter both first and last name.
  '  priya  sharma  '       → OK
  'PriyaSharma'             → Please enter both first and last name.

Email Validation:
  ''                        → Email cannot be empty.
  'priya'                   → Email must contain '@'.
  'priya@'                  → Invalid email domain.
  'priya@gmail'             → Invalid email domain.
  'priya@gmail.com'         → OK
  'PRIYA@MEESHO.IN'         → OK

Phone Validation:
  ''                        → Phone cannot be empty.
  '98765'                   → Phone must be exactly 10 digits.
  '9876543210'              → OK
  '98765 43210'             → OK
  'abcdefghij'              → Phone must contain only digits.

Display Name Formatting:
  'priya sharma'            → 'Priya Sharma'
  'ROHAN MEHTA'             → 'Rohan Mehta'
  '  sneha   rao  '         → 'Sneha Rao'
  'deepak'                  → 'Deepak'

Real-World Example 2 — Order Confirmation Message Builder

The Business Problem

After a customer places an order on an app like Swiggy or Amazon, the system generates a personalised confirmation message to send via SMS or push notification. The message includes the customer name, order ID, total amount, and estimated delivery time. String formatting and building techniques power this.

Java
1// File: OrderMessageBuilder.java 2 3public class OrderMessageBuilder { 4 5 // Builds an SMS confirmation message 6 public static String buildSmsMessage(String customerName, 7 String orderId, 8 double totalAmount, 9 String deliveryTime) { 10 11 // Use StringBuilder for multi-part message construction 12 StringBuilder msg = new StringBuilder(); 13 14 // Extract first name only — friendly tone 15 String firstName = customerName.contains(" ") 16 ? customerName.substring(0, customerName.indexOf(' ')) 17 : customerName; 18 19 msg.append("Hi ").append(firstName).append("! "); 20 msg.append("Your order ").append(orderId).append(" "); 21 msg.append("worth Rs.").append(String.format("%.2f", totalAmount)).append(" "); 22 msg.append("is confirmed. "); 23 msg.append("Estimated delivery: ").append(deliveryTime).append(". "); 24 msg.append("Track your order in the app."); 25 26 return msg.toString(); 27 } 28 29 // Builds a detailed receipt header 30 public static String buildReceiptHeader(String storeName, 31 String orderId, 32 String customerName) { 33 int width = 44; 34 String line = "=".repeat(width); 35 String storeDisplay = storeName.toUpperCase(); 36 37 // Centre the store name 38 int padding = (width - storeDisplay.length()) / 2; 39 String centred = " ".repeat(Math.max(0, padding)) + storeDisplay; 40 41 return String.format("%s%n%s%n%s%n%s: %s%n%s: %s%n%s", 42 line, centred, line, 43 "Order ID", orderId, 44 "Customer", customerName, 45 line); 46 } 47 48 // Masks sensitive part of an email for display 49 public static String maskEmail(String email) { 50 if (email == null || !email.contains("@")) return "***"; 51 int atIdx = email.indexOf('@'); 52 String user = email.substring(0, atIdx); 53 String domain = email.substring(atIdx); 54 55 // Show first 2 chars, mask the rest of username 56 if (user.length() <= 2) return user + "***" + domain; 57 return user.substring(0, 2) + "*".repeat(user.length() - 2) + domain; 58 } 59}
Java
1// File: OrderConfirmationDemo.java 2 3public class OrderConfirmationDemo { 4 5 public static void main(String[] args) { 6 7 // SMS confirmation for 3 different orders 8 System.out.println("=== SMS Confirmations ===\n"); 9 10 String[][] orders = { 11 {"Priya Sharma", "ORD-9921", "1299.50", "30-35 mins"}, 12 {"Rohan Mehta", "ORD-9922", "499.00", "2-3 days"}, 13 {"Ananya Krishnan", "ORD-9923", "8499.00", "1-2 days"}, 14 }; 15 16 for (String[] order : orders) { 17 String sms = OrderMessageBuilder.buildSmsMessage( 18 order[0], order[1], 19 Double.parseDouble(order[2]), 20 order[3]); 21 System.out.println(sms); 22 System.out.println(); 23 } 24 25 // Receipt header 26 System.out.println("=== Receipt Header ===\n"); 27 System.out.println(OrderMessageBuilder.buildReceiptHeader( 28 "Swiggy Instamart", "ORD-9921", "Priya Sharma")); 29 30 System.out.println(); 31 32 // Email masking 33 System.out.println("=== Email Masking ===\n"); 34 String[] emails = {"priya@gmail.com", "ro@flipkart.in", 35 "ananyakrishnan@meesho.in"}; 36 for (String email : emails) { 37 System.out.printf(" %-30s → %s%n", email, 38 OrderMessageBuilder.maskEmail(email)); 39 } 40 } 41}
Output:
=== SMS Confirmations ===

Hi Priya! Your order ORD-9921 worth Rs.1299.50 is confirmed. Estimated delivery: 30-35 mins. Track your order in the app.

Hi Rohan! Your order ORD-9922 worth Rs.499.00 is confirmed. Estimated delivery: 2-3 days. Track your order in the app.

Hi Ananya! Your order ORD-9923 worth Rs.8499.00 is confirmed. Estimated delivery: 1-2 days. Track your order in the app.

=== Receipt Header ===

============================================
             SWIGGY INSTAMART
============================================
Order ID: ORD-9921
Customer: Priya Sharma
============================================

=== Email Masking ===

  priya@gmail.com               → pr***@gmail.com
  ro@flipkart.in                → ro***@flipkart.in
  ananyakrishnan@meesho.in      → an***************@meesho.in

Best Practices

Always use .equals() to compare strings, never ==. The == operator checks whether two variables point to the same object in memory. Two strings with identical content stored as different objects will return false with ==. This is a bug that is easy to write and hard to spot. Use "constant".equals(variable) with the constant on the left to also avoid NullPointerException if the variable is null.

Always capture the result of a String method. String methods return new strings — they do not modify the original. name.trim() does nothing useful unless you write name = name.trim() or String trimmedName = name.trim(). Forgetting this is the single most common String mistake.

Use StringBuilder inside loops. Every + inside a loop creates a new String object. In a loop that runs 1,000 times, this creates 1,000 temporary String objects. StringBuilder.append() modifies the same buffer the entire time. For loops, StringBuilder is always the right choice.

Use String.format() for structured output. "Rs." + amount + " for " + qty + " items" becomes hard to read as the pieces multiply. String.format("Rs.%.2f for %d items", amount, qty) is readable, predictable, and formats numbers cleanly.

Common Mistakes

Mistake 1 — Comparing Strings With ==

Java
1String s1 = new String("hello"); 2String s2 = new String("hello"); 3 4if (s1 == s2) { // false — different objects 5 System.out.println("Equal"); // never prints 6} 7 8if (s1.equals(s2)) { // true — same content 9 System.out.println("Equal"); // prints 10}

Mistake 2 — Ignoring the Return Value of String Methods

Java
1String username = " rohan_mehta "; 2 3username.trim(); // result thrown away — username unchanged 4username.toUpperCase(); // same mistake 5 6System.out.println(username); // still " rohan_mehta " 7 8// Correct 9username = username.trim().toUpperCase(); 10System.out.println(username); // "ROHAN_MEHTA"

Mistake 3 — NullPointerException From Calling Methods on a Null String

Java
1String input = null; 2System.out.println(input.length()); // NullPointerException 3 4// Safe pattern — check null first 5if (input != null && !input.isBlank()) { 6 System.out.println(input.length()); 7} 8 9// Or — put the known value first in equals() 10boolean isAdmin = "admin".equals(input); // false — no NPE even if input is null

Mistake 4 — Building Strings With + Inside a Loop

Java
1// Inefficient — creates a new String object on every iteration 2String result = ""; 3for (int i = 1; i <= 10000; i++) { 4 result = result + i + ","; // 10,000 temporary String objects created 5} 6 7// Efficient — one mutable buffer for the whole loop 8StringBuilder sb = new StringBuilder(); 9for (int i = 1; i <= 10000; i++) { 10 sb.append(i).append(","); // modifies the same object every time 11} 12String result2 = sb.toString();

Interview Questions

Q1. What is a String in Java and why is it immutable?

A String is a sequence of characters represented by the java.lang.String class. It is immutable — once a String object is created, its content cannot be changed. Immutability enables the String pool optimisation, where identical string literals can share the same object in memory without risk of one caller changing the content that another caller is reading. It also makes strings inherently thread-safe and safe to use as HashMap keys, since their hash code never changes.

Q2. What is the String pool in Java?

The String pool is a special region inside the heap where Java stores string literals. When you write String s = "hello", the JVM checks the pool first. If "hello" already exists there, it returns the existing reference — no new object is created. If not, it creates a new entry. This makes string literal reuse memory-efficient. Strings created with new String("hello") bypass the pool and always create a new object. You can add a new String to the pool manually using the intern() method.

Q3. What is the difference between equals() and == for Strings?

== compares references — it returns true only when both variables point to the exact same object in memory. equals() compares content — it returns true when both strings contain the same sequence of characters, regardless of whether they are the same object. Two strings created as literals with the same value may return true for == due to pool reuse, but two strings created with new String(...) containing the same value will return false for ==. Always use equals() for content comparison.

Q4. What is the difference between String, StringBuilder, and StringBuffer?

String is immutable — every operation produces a new object. StringBuilder is mutable and not thread-safe — use it for building strings in single-threaded code, especially inside loops. StringBuffer is mutable and thread-safe — all its methods are synchronised — use it when the same StringBuilder is accessed from multiple threads. For almost all common development scenarios, String for individual values and StringBuilder for building are the right choices. StringBuffer is rarely needed in modern Java where thread-local string building is preferred.

Q5. What does str.split(".") return?

An empty array — not what most beginners expect. split() takes a regular expression, and . in regex means "match any character". So "hello.world".split(".") matches every character and returns an empty array. To split on a literal dot, escape it: str.split("\\."). This is one of the most common beginner traps with split().

Q6. Why should you put the string constant on the left side of equals()?

"constant".equals(variable) is safe even when variable is null — calling .equals() on a non-null constant cannot throw NullPointerException. If you write variable.equals("constant") and variable is null, it throws NullPointerException. Since user input, database values, and API responses can all be null, putting the known non-null constant on the left is a defensive habit that prevents unnecessary null checks.

FAQs

Can you change a String after creating it in Java?

No. A String object's character content is fixed at creation. What you can do is reassign the variable to point to a new String — name = name.toUpperCase() — but the original "priya" object still exists in memory untouched until the garbage collector removes it. If you need to build or modify text frequently, use StringBuilder instead.

Is String a primitive type in Java?

No. String is a class — java.lang.String. It is a reference type, just like ArrayList or any custom class. However, Java gives it special syntax: you can create String literals with double quotes ("hello") without using the new keyword, and you can use + for concatenation. These conveniences make it feel primitive-like, but it is a full object with methods.

What is the difference between length for arrays and length() for Strings?

For arrays, length is a field — no parentheses: arr.length. For Strings, length() is a method — with parentheses: str.length(). Using str.length on a String causes a compile error, and arr.length() on an array also causes a compile error. The distinction exists because arrays are a special Java feature handled differently from objects, while String is a regular class.

What happens when you concatenate a String with null?

When null is concatenated with a String using +, Java converts null to the string "null" — no exception is thrown. So "Hello, " + null produces "Hello, null". However, calling .equals() or any method on a null reference throws NullPointerException.

What is the intern() method in Java?

intern() adds a String to the String pool (or returns the existing pool entry if one already exists with the same content). new String("hello").intern() returns the pooled reference for "hello". After calling intern(), you can compare with == reliably. In practice, intern() is rarely used in application code — it is more relevant in frameworks that process massive volumes of repeated strings.

Summary

String is Java's most used class, and its core behaviours are few and memorable. Strings are immutable — every method returns a new String, never modifying the original. String literals are pooled — identical literals share one object. Always compare with equals(), never ==. Always capture the return value of String methods.

The methods you will use most often are trim(), toLowerCase(), toUpperCase(), contains(), startsWith(), endsWith(), replace(), substring(), indexOf(), split(), equals(), equalsIgnoreCase(), and String.format(). These cover the vast majority of text processing tasks in real-world Java development.

For interviews, be ready to explain immutability and why it exists, describe the String pool, explain the difference between equals() and ==, and explain when to use StringBuilder over +. These appear in nearly every Java interview at every level.

What to Read Next

TopicLink
How StringBuilder and StringBuffer efficiently build mutable stringsJava StringBuilder and StringBuffer →
How String methods like format and regex work for advanced text processingJava String Class →
How the String pool relates to JVM memory managementJava Heap and Stack Memory →
How immutable classes are designed and why String follows this patternJava Immutable Class →
How the String class fits into Java's Object hierarchyJava Object Class →
Java String Basics | DevStackFlow