Creating Strings
Creating Strings in Java
Java provides multiple ways to create String objects.
String Literals
// String literal - stored in string pool
String name = "Hello World";
// String pool is a special area in heap memory
// JVM tries to reuse strings with same content
String a = "Hello";
String b = "Hello";
System.out.println(a == b); // true (same object in pool)
Using new Keyword
// Creates new String object in heap (not in pool)
String name = new String("Hello World");
String a = new String("Hello");
String b = new String("Hello");
System.out.println(a == b); // false (different objects)
System.out.println(a.equals(b)); // true (same content)
From char Array
char[] chars = {'H', 'e', 'l', 'l', 'o'};
String str = new String(chars); // "Hello"
// With offset and length
char[] chars2 = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'};
String str2 = new String(chars2, 0, 5); // "Hello"
From byte Array
byte[] bytes = {72, 101, 108, 108, 111};
String str = new String(bytes); // "Hello"
// With charset
String str2 = new String(bytes, StandardCharsets.UTF_8);
String Concatenation
// + operator creates new String object
String first = "Hello";
String second = " World";
String result = first + second; // "Hello World"
// Compile-time constant folding
String a = "Hello" + " World"; // "Hello World" (compiled as single string)
String b = "Hello";
String c = b + " World"; // Runtime concatenation
String Length
String str = "Hello";
int len = str.length(); // 5 (method, not field like arrays)
// Empty string
String empty = "";
int emptyLen = empty.length(); // 0
Key Differences
| Literal | new String() |
|---|---|
| Stored in string pool | Stored in heap |
| Reuses existing objects | Creates new object |
a == b may be true |
a == b is always false |
| More memory efficient | Less efficient |
Immutability
String Immutability
Strings in Java are immutable - once created, their values cannot be changed.
Why Immutable?
// Strings are immutable for security and performance
String str = "Hello";
// This does NOT modify the original string
String upper = str.toUpperCase(); // "HELLO"
// str is still "Hello"
// A new string is created for the result
Immutability Benefits
// 1. Security - Strings can't be modified
String password = "secret";
// No other code can change this value
// 2. Thread Safety - Safe to share between threads
String shared = "constant";
// Multiple threads can read without synchronization
// 3. Hash Code Caching - Can be cached since content doesn't change
String str = "Hello";
int hash = str.hashCode(); // Computed once, cached
// 4. String Pool - Can safely reuse strings
String a = "Hello";
String b = "Hello";
// Both point to same object in pool
String Concatenation Performance
// BAD: Creates many intermediate String objects
String result = "";
for (int i = 0; i < 1000; i++) {
result += i; // Creates new String each time!
}
// O(n^2) time complexity
// GOOD: Use StringBuilder
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1000; i++) {
sb.append(i);
}
String result = sb.toString();
// O(n) time complexity
String Methods Return New Strings
String str = "Hello World";
// Each method returns a NEW string
String upper = str.toUpperCase(); // "HELLO WORLD"
String lower = str.toLowerCase(); // "hello world"
String trimmed = str.trim(); // "Hello World"
String replaced = str.replace('o', '0'); // "Hell0 W0rld"
// Original string unchanged
System.out.println(str); // "Hello World"
Memory Implications
// Each string operation creates new object
String a = "Hello";
String b = a.toUpperCase(); // New object created
String c = b.concat(" World"); // Another new object
// This can waste memory in loops
// Use StringBuilder for multiple concatenations
String Pool
String Pool
String pool is a special memory area in the JVM heap where String literals are stored.
How It Works
// String literals are automatically interned
String a = "Hello";
String b = "Hello";
// Both point to same object in pool
System.out.println(a == b); // true
System.out.println(a.equals(b)); // true
// new String() creates new object outside pool
String c = new String("Hello");
System.out.println(a == c); // false
System.out.println(a.equals(c)); // true
intern() Method
// Manually add string to pool
String a = new String("Hello"); // Not in pool
String b = a.intern(); // Added to pool
String c = "Hello"; // Already in pool
System.out.println(b == c); // true
// Useful for saving memory with many duplicate strings
Pool Size and Performance
// Pool is limited in size
// Too many strings can cause performance issues
// Modern JVMs use different pool strategies:
// - Java 6: PermGen (fixed size, can cause OutOfMemoryError)
// - Java 7+: Heap (garbage collected, more flexible)
Common Patterns
// Pattern 1: Check equality correctly
String user = getUserInput();
if (user.equals("quit")) { // Always use equals()
exit();
}
// Pattern 2: Switch on strings (Java 7+)
switch (command) {
case "start":
start();
break;
case "stop":
stop();
break;
}
// Pattern 3: String comparison
String a = "Hello";
String b = new String("Hello");
// WRONG: Use equals()
if (a == b) { } // false!
// RIGHT: Use equals()
if (a.equals(b)) { } // true!
Memory Optimization
// Bad: Creates many objects
String[] words = new String[1000];
for (int i = 0; i < 1000; i++) {
words[i] = new String("hello"); // 1000 objects!
}
// Good: Reuses pool objects
String[] words = new String[1000];
for (int i = 0; i < 1000; i++) {
words[i] = "hello".intern(); // Reuses pool object
}
Comparison Summary
| Expression | What it checks |
|---|---|
a == b |
Reference equality (same object?) |
a.equals(b) |
Content equality (same value?) |
a.intern() == b.intern() |
Both in pool? |
Best Practice
Always use equals() to compare String content, never ==.
Operations
Common String Operations
Length and Access
String str = "Hello World";
int len = str.length(); // 11
char first = str.charAt(0); // 'H'
char last = str.charAt(10); // 'd'
// Iterate through characters
for (int i = 0; i < str.length(); i++) {
System.out.println(str.charAt(i));
}
// Enhanced for loop (Java 5+)
for (char c : str.toCharArray()) {
System.out.println(c);
}
Substrings
String str = "Hello World";
String sub1 = str.substring(6); // "World"
String sub2 = str.substring(0, 5); // "Hello"
// substring(beginIndex, endIndex)
// endIndex is exclusive!
Search
String str = "Hello World";
int index = str.indexOf('l'); // 2 (first occurrence)
int index2 = str.lastIndexOf('l'); // 9 (last occurrence)
int index3 = str.indexOf("World"); // 6
int index4 = str.indexOf("xyz"); // -1 (not found)
boolean contains = str.contains("World"); // true
boolean starts = str.startsWith("Hello"); // true
boolean ends = str.endsWith("World"); // true
Transformation
String str = "Hello World";
String upper = str.toUpperCase(); // "HELLO WORLD"
String lower = str.toLowerCase(); // "hello world"
String trimmed = str.trim(); // "Hello World"
// Replace
String replaced = str.replace('l', 'L'); // "HeLLo WorLd"
String replaced2 = str.replace("World", "Java"); // "Hello Java"
// ReplaceAll (regex)
String cleaned = str.replaceAll("[^a-zA-Z]", ""); // "HelloWorld"
Split and Join
// Split
String csv = "apple,banana,cherry";
String[] fruits = csv.split(",");
// ["apple", "banana", "cherry"]
// With limit
String data = "a:b:c:d";
String[] parts = data.split(":", 2); // ["a", "b:c:d"]
// Join
String joined = String.join(" - ", fruits); // "apple - banana - cherry"
// Join with delimiter
String result = String.join(",", "a", "b", "c"); // "a,b,c"
Conversion
// To char array
char[] chars = "Hello".toCharArray();
// From char array
String str = new String(chars);
// To int
int num = Integer.parseInt("123");
double dbl = Double.parseDouble("3.14");
// From int
String fromInt = String.valueOf(123); // "123"
String fromInt2 = Integer.toString(123); // "123"
String fromInt3 = 123 + ""; // "123"
// Format
String formatted = String.format("Name: %s, Age: %d", "Alice", 25);
Formatting
// String.format()
String name = "Alice";
int age = 25;
String msg = String.format("%s is %d years old", name, age);
// System.out.printf()
System.out.printf("Name: %s, Age: %d%n", name, age);
// Format specifiers
// %s - string
// %d - integer
// %f - float
// %c - character
// %b - boolean
Practice Problems
Given two strings s and t, return true if t is an anagram of s.
Example:
Input: s = "anagram", t = "nagaram"
Output: true
Both have same characters with same frequencies
Optimal Solution — O(n) time, O(1) space
Count character frequencies using array.
public boolean isAnagram(String s, String t) {
if (s.length() != t.length()) return false;
int[] count = new int[26];
for (char c : s.toCharArray()) count[c - 'a']++;
for (char c : t.toCharArray()) count[c - 'a']--;
for (int i : count) if (i != 0) return false;
return true;
}Edge Cases:
- Different lengths
- Single character
- All same characters
Reverse a string in-place using a char array.
Example:
Input: s = ["h","e","l","l","o"]
Output: ["o","l","l","e","h"]
Reverse the character array
Optimal Solution — O(n) time, O(1) space
Two pointers from both ends, swap characters.
public void reverseString(char[] s) {
int left = 0, right = s.length - 1;
while (left < right) {
char temp = s[left];
s[left] = s[right];
s[right] = temp;
left++;
right--;
}
}Edge Cases:
- Single character
- Two characters
- Empty string
Find the index of the first non-repeating character.
Example:
Input: s = "leetcode"
Output: 0
'l' is the first unique character
Optimal Solution — O(n) time, O(1) space
Count frequencies, then find first with count 1.
public int firstUniqChar(String s) {
int[] count = new int[26];
for (char c : s.toCharArray()) count[c - 'a']++;
for (int i = 0; i < s.length(); i++) {
if (count[s.charAt(i) - 'a'] == 1) return i;
}
return -1;
}Edge Cases:
- All characters repeat
- No unique character
- First character unique
Find length of longest substring without repeating characters.
Example:
Input: s = "abcabcbb"
Output: 3
The answer is "abc", with length 3
Optimal Solution — O(n) time, O(min(n, 26)) space
Sliding window with HashSet to track characters.
public int lengthOfLongestSubstring(String s) {
Set<Character> set = new HashSet<>();
int max = 0, left = 0;
for (int right = 0; right < s.length(); right++) {
while (set.contains(s.charAt(right))) {
set.remove(s.charAt(left));
left++;
}
set.add(s.charAt(right));
max = Math.max(max, right - left + 1);
}
return max;
}Edge Cases:
- Empty string
- All same characters
- All unique
Quiz
1. Why are Strings immutable in Java?
2. What is the difference between == and equals() for Strings?
3. What happens when you concatenate strings in a loop?
4. What is the string pool?
Flashcards
Question
What is the difference between String literal and new String()?
Click to reveal answer
Answer
Literal is stored in string pool and may be reused. new String() creates a new object in heap memory.
Question
How do you compare String content?
Click to reveal answer
Answer
Use equals() method: str1.equals(str2). Never use == for content comparison.
Question
What is the time complexity of String concatenation with +?
Click to reveal answer
Answer
O(n^2) for loops because each concatenation creates a new String. Use StringBuilder for O(n).
Question
What does String.intern() do?
Click to reveal answer
Answer
Adds the string to the string pool and returns the pool reference. Useful for saving memory with duplicates.
Question
What is Strings in Java?
Click to reveal answer
Answer
Strings in Java is a key concept in Java programming.
Revision Notes
Key Takeaways
- 1.Strings are immutable in Java
- 2.Use equals() for content comparison, never ==
- 3.String literals are stored in string pool
- 4.Use StringBuilder for multiple concatenations
Interview Tips
- •Always use equals() to compare Strings
- •Remember String is immutable - operations return new Strings
- •Know the difference between == and equals()
- •Practice common string algorithms: anagram, palindrome, substring
Cheat Sheet
Cheat Sheet
- Length:
str.length() - Access:
str.charAt(index) - Substring:
str.substring(start, end) - Search:
str.indexOf(char),str.contains(str) - Compare:
str1.equals(str2) - Transform:
str.toUpperCase(),str.trim() - Split:
str.split(delimiter) - Join:
String.join(delimiter, elements)