In Java, strings are objects that represent sequences of characters.
In context of
String
class , strings are immutable.Anything within double quotes is a string in java.
Two categories of string : immutable and mutable. For immutable string object ,
String
is the predefined class to manage whereas for Mutable string object ,StringBuffer
,StringBuilder
are usedMutation not respect to reference , but the memory.
You do not use any imports with strings, as
lang
package is implicit import
Different Ways to Declare a String
String Literal: Stored in the String Constant Pool (SCP).
String s1 = "Hello";
Using the
new
keyword: Creates a new String object in the heap.String s2 = new String("Hello");
Using
char
array:char[] helloArray = { 'H', 'e', 'l', 'l', 'o' }; String s3 = new String(helloArray);
Heap Memory vs String Constant Pool
All Java objects (created using new
), including strings, are stored in the heap memory. But String literals are stored by default in the SCP . SCP stores unique string literals. When a string is created using double quotes, it is stored in SCP if it doesnβt already exist.
Direct literas reside inside SCP (created without new)
(Strings Created using new)are in heap with copy in SCP
In heap area duplicates are allowed, they will have separate references
In SCP duplicates are not allowed
public class StringPoolExample {
public static void main(String[] args) {
String s1 = "Hello";
String s2 = "Hello";
System.out.println(s1 == s2);
// Outputs: true, both point to the same SCP object
String s3 = new String("Hello");
System.out.println(s1 == s3);
// Outputs: false, s3 refers to an object in the heap
}
}
The reassignment of a SCP string literal does not override the initial assigned memory
Anything concat to string will become string
Contact leads to memory creation on heap NOT scp
Comparing strings
Using ==
references of string is compared
Using equals()
string contents will be compared
Using equalsIgnoreCase()
: string contents will be compared ignoring case
Using compareTo()
method compares strings based on the Unicode value of each character. It returns 0 if the strings are equal. It returns a positive value if the first string is lexicographically greater. It returns a negative value if the first string is lexicographically smaller.
String utility functions
public class StringUtilityDemo {
public static void main(String[] args) {
String s1 = "Hello";
String s2 = new String("Hello");
char[] helloArray = { 'H', 'e', 'l', 'l', 'o' };
String s3 = new String(helloArray);
System.out.println("Length of s1: " + s1.length());
System.out.println(s1.charAt(1));
System.out.println(s1.substring(1, 3));
System.out.println("\nReplace 'l' with 'p' in s1: "
+ s1.replace('l', 'p'));
System.out.println("\ns1 equals 'Hello': " + s1.equals("Hello"));
System.out.println("\ns1 equalsIgnoreCase 'hello': " + s1.equalsIgnoreCase("hello"));
System.out.println("\nCompare s1 with 'Hello': " + s1.compareTo("Hello"));
System.out.println("\ns1 contains 'ell': " + s1.contains("ell"));
System.out.println("\nIndex of 'e' in s1: " + s1.indexOf('e'));
System.out.println("\ns1 in upper case: " + s1.toUpperCase());
System.out.println("\ns1 in lower case: " + s1.toLowerCase());
System.out.println("\nTrimmed s4: '" + s4.trim() + "'");
// Demonstrate mutable strings with StringBuilder
StringBuilder sb = new StringBuilder("Hello");
sb.append(" World");
System.out.println("\nStringBuilder append: " + sb.toString());
//Using the intern() method, you can ensure a string is in the SCP.
String s5 = new String("Hello").intern();
System.out.println("s1 == s5: " + (s1 == s5));
String[] words = "Hello World Java".split(" ");
System.out.println("Split 'Hello World Java':");
for (String word : words) {
System.out.println(word);
}
// join
String joinedString = String.join("-", words);
System.out.println("\nJoined with '-': " + joinedString);
// format
String formattedString = String.format("Name: %s, Age: %d", "John", 25);
System.out.println("\nFormatted string: " + formattedString);
// valueOf
int number = 100;
String numberString = String.valueOf(number);
System.out.println("\nString value of 100: " + numberString);
// isEmpty and isBlank
String emptyString = "";
String blankString = " ";
System.out.println("\nIs empty string empty: " + emptyString.isEmpty());
System.out.println("Is blank string blank: " + blankString.isBlank());
}
}
Immutable vs Mutable String
An immutable string object is one whose state/memory map cannot be modified after it is created.
Benefits
Thread-safety: Immutable objects are inherently thread-safe.
Caching: Because their state does not change, immutable objects can be safely cached and reused.
A mutable string object is one whose state/memory map can be changed , For mutable strings, Java provides StringBuilder
and StringBuffer
classes.
StringBuilder: Not synchronized, thus faster but not thread-safe.(newer JAVA5)
StringBuffer: Synchronized, thread-safe but slower.
When creating a string using either of the above classes you have to use the new keyword
For either of this rather than concat() , append() function is provided
public class MutableStringExample {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder("Hello");
sb.append(" World");
System.out.println(sb.toString()); // Outputs: Hello World
}
}
in above example the SAME object is getting changed demonstrating mutability
While using String class and using concat() you can only pass string type data , but same is not true for append
StringBuilder/StringBuffer have member function capacity(), capacity increases dynamically
```java public class StringBuilderVsStringBufferDemo { public static void main(String[] args) { // Demonstrate StringBuilder (Not synchronized, faster, not thread-safe) StringBuilder sb = new StringBuilder("Hello"); System.out.println("Initial StringBuilder: " + sb.toString()); sb.append(" World"); System.out.println("After append: " + sb.toString()); sb.insert(5, " Java"); System.out.println("After insert: " + sb.toString()); sb.reverse(); System.out.println("After reverse: " + sb.toString());
// Demonstrate StringBuffer (Synchronized, thread-safe, slower) StringBuffer sbf = new StringBuffer("Hello"); System.out.println("\nInitial StringBuffer: " + sbf.toString()); sbf.append(" World"); System.out.println("After append: " + sbf.toString());
sbf.insert(5, " Java"); System.out.println("After insert: " + sbf.toString());
sbf.reverse(); System.out.println("After reverse: " + sbf.toString());
StringBuffer sbf2 = new StringBuffer("Thread Safe"); Runnable task = () -> { for (int i = 0; i < 10; i++) { sbf2.append(i); System.out.println("Appending in thread: " + sbf2.toString()); } };
Thread thread1 = new Thread(task); Thread thread2 = new Thread(task); thread1.start(); thread2.start();
// Wait for threads to finish try { thread1.join(); thread2.join(); } catch (InterruptedException e) { e.printStackTrace(); }
System.out.println("\nFinal StringBuffer after threading: "
sbf2.toString());
} } ```
Comparing strings created via StringBuilder/StringBuffer
here unlike for strings , even if we use equals() , references will be compared ! the equals function is not overridden and used as it is in the original Object class Implementation.
So for mutable strings it always recommended to use compareTo()