Within the Java programming language, a string is essentially an object that serves as a representation of a sequence of character values. In Java, a string is essentially operated as an array of characters. For instance:
char[] ch={'t','p','o','i','n','t'};
String s=new String(ch);
is same as:
String s="Hello World";
The Java String class offers numerous methods for manipulating strings, including compare, concat, equals, split, length, replace, compareTo, intern, substring, and more.
The class java.lang.String incorporates the Serializable, Comparable, and CharSequence interfaces.
CharSequence Interface
The CharSequence interface is employed for representing character sequences in Java. The String, StringBuffer, and StringBuilder classes all make use of this interface. This implies that strings can be created in Java through the utilization of these three classes.
In Java, the String data type is immutable, indicating that its value cannot be altered once it is created. Modifying a String will result in the creation of a new instance. To work with mutable strings in Java, the StringBuffer and StringBuilder classes can be utilized.
The topic of immutable strings will be covered later. For now, let's delve into the concept of strings in Java and explore the process of creating a String object.
What is String in Java?
In most cases, a String refers to a series of characters. However, in Java, a string is an instance that embodies a series of characters. The java.lang.String class is utilized for string object creation.
How to create a string object?
String objects can be created in two ways:
- Through a string literal
- Using the new keyword
1) String Literal
A Java String literal is formed by enclosing characters within double quotation marks. For instance:
String s="welcome";
When you define a string literal, the Java Virtual Machine (JVM) first examines the "string constant pool". If the string is already present in the pool, it retrieves a reference to that existing instance. However, if the string is not found in the pool, a new instance of the string is generated and added to the pool. An illustration of this process is:
String s1="Welcome";
String s2="Welcome";//It doesn't create a new instance
In the scenario outlined, a single object gets instantiated. Initially, the JVM searches the string constant pool for an object containing the "Welcome" value; failing to find a match, it proceeds to create a new object. Subsequently, upon encountering a string with the "Welcome" value already present in the pool, the JVM refrains from creating a fresh object and instead provides a reference to the existing instance.
Example
//Java Program to create string using string literal
public class Main {
public static void main(String[] args) {
String s1="Welcome";
String s2="Welcome";//It doesn't create a new instance
System.out.println(s1+" "+s2);
}
}
Output:
Welcome Welcome
Note: String objects are stored in a special memory area known as the "string constant pool".
Why Java uses the concept of String literal?
In order to enhance the memory efficiency of Java, it is beneficial to avoid creating new objects if they already exist in the string constant pool.
2) By new keyword
String s=new String("Welcome");//creates two objects and one reference variable
When this transpires, a new string object will be generated by the JVM in the regular heap memory, while the string "Welcome" will be stored in the string constant pool. The variable s will point to the object in the heap (non-pool).
Example
//Java Program to create string using new keyword
public class Main {
public static void main(String[] args) {
String s1=new String("Welcome");
String s2=new String("Welcome");
System.out.println(s1+" "+s2);
}
}
Output:
Welcome Welcome
Java String class
The String class is one of the most fundamental types in Java, designed to represent immutable sequences of characters. Here's a closer look at its characteristics and the interfaces it implements:
- Immutability: Once instantiated, a String object cannot be modified. This immutable design is a deliberate choice to ensure thread safety, consistency, and efficiency, especially regarding the String pool mechanism.
- String Pool: Java maintains a pool of string literals to help save memory. When a new string literal is created, Java checks the Pool for a matching string. If found, the new variable references the pooled string. If not, the new string is added to the Pool.
- Implemented Interfaces: The String class implements several interfaces, including: Serializable: Allows string objects to be serialized into byte streams, facilitating their transmission or storage. Comparable<String>: Enables lexical comparison between two strings, supporting natural ordering within collections. CharSequence: Provides a unified read-only interface for different kinds of char sequences, allowing String objects to be manipulated and accessed generically.
- Serializable: Allows string objects to be serialized into byte streams, facilitating their transmission or storage.
- Comparable<String>: Enables lexical comparison between two strings, supporting natural ordering within collections.
- CharSequence: Provides a unified read-only interface for different kinds of char sequences, allowing String objects to be manipulated and accessed generically.
CharSequence Interface
Java's CharSequence interface provides a unified, read-only view of character sequences and is a component of the java.lang package. It facilitates consistent access and manipulation across various types of character sequences, including String, StringBuilder, StringBuffer, and CharBuffer. Through this interface, key functionalities for handling character data are defined, enabling actions like measuring sequence length, accessing particular characters, generating character subsequences, and transforming into a String format. By providing a common blueprint for character sequences, CharSequence enables flexible and implementation-independent text processing across the Java platform.
- String
- StringBuffer
- StringBuilder
String
The String class in Java serves as a container for sequences of characters. When a String object is created, its content becomes unchangeable, establishing its immutable characteristic. This unchangeability guarantees the safety of String objects in multi-threaded environments and contributes to their efficient performance, especially when dealing with static textual data. Java utilizes a method known as string interning to improve memory usage by optimizing the handling and retrieval of frequently used string constants.
Syntax:
Direct assignment using string literals:
String str = "Hello, World!";
Using the String constructor:
String str = new String("Hello, World!");
Filename: StringExample.java
public class StringExample {
public static void main(String[] args) {
// Creating a String
String greeting = "Hello";
// Concatenating strings
String sentence = greeting + ", World!";
// Using a method from the String class
int length = sentence.length();
System.out.println(sentence); // Output: Hello, World!
System.out.println("Length: " + length); // Output: Length: 13
}
}
Output:
Hello, World!
Length: 13
StringBuffer
StringBuffer is utilized to manage a changeable series of characters while maintaining thread safety, which is beneficial for applications where multiple threads are involved in altering a character sequence. It offers functionalities for manipulating strings such as inserting, deleting, and appending characters. By eliminating the need to create new objects for each modification, this approach improves efficiency especially in cases where frequent modifications to the string content are necessary.
Syntax
StringBuffer sb = new StringBuffer();
Filename: StringBufferExample.java
public class StringBufferExample {
public static void main(String[] args) {
// Creating a StringBuffer
StringBuffer sb = new StringBuffer("Hello");
// Appending to the StringBuffer
sb.append(", World!");
// Inserting into the StringBuffer
sb.insert(5, " Java");
// Deleting from the StringBuffer
sb.delete(5, 10);
System.out.println(sb); // Output: Hello, World!
}
}
Output:
Hello, World!
StringBuilder
The mutable character sequence in StringBuilder is akin to that in StringBuffer. However, the key difference is that StringBuilder is unsynchronized, making it unsuitable for operations requiring thread safety. This lack of synchronization actually boosts StringBuilder's performance in scenarios involving single-threaded or specific-thread environments. Consequently, StringBuilder is preferred for string manipulation in situations where concurrent thread access safety is not a concern.
Syntax
StringBuilder sb = new StringBuilder();
Filename: StringBuilderExample.java
public class StringBuilderExample {
public static void main(String[] args) {
// Creating a StringBuilder
StringBuilder sb = new StringBuilder("Hello");
// Appending to the StringBuilder
sb.append(", World!");
// Inserting into the StringBuilder
sb.insert(5, " Java");
// Deleting from the StringBuilder
sb.delete(5, 10);
System.out.println(sb); // Output: Hello, World!
}
}
Output:
Hello, World!
Immutable String in Java
In Java, strings are immutable, indicating that once a String object is established, its value cannot be altered. Any attempt to modify a String actually results in the generation of a new String object, leaving the original string unaltered. This immutability feature of strings in Java carries various consequences concerning performance, security, and functionality.
Filename: ImmutableStringExample.java
public class ImmutableStringExample {
public static void main(String[] args) {
// Original string
String originalString = "Java";
System.out.println("Original string: " + originalString);
// Attempt to modify the original string
String modifiedString = originalString.concat(" Programming");
// Showing that the original string remains unchanged
System.out.println("After modification, original string: " + originalString);
// The result of the modification attempt is stored in a new string
System.out.println("Modified string: " + modifiedString);
// Demonstrating further that the original string is immutable
originalString.toUpperCase(); // This operation does not change the original string
System.out.println("After calling toUpperCase on original string: " + originalString);
// Correct way to use the result of a string operation
String upperCaseString = originalString.toUpperCase(); // Stores the result in a new string
System.out.println("Original string in uppercase: " + upperCaseString);
}
}
Output:
Original string: Java
After modification, original string: Java
Modified string: Java Programming
After calling toUpperCase on original string: Java
Original string in uppercase: JAVA
Memory Allotment of String
The memory allocation for strings in Java presents an intriguing aspect because of Java's management of string immutability and the string pool system. Having a grasp of how strings are stored can be beneficial for enhancing memory efficiency in Java programs, particularly those that extensively involve string operations.
String Literal Storage: In Java, when you declare a string using string literals, the string pool is the initial point of reference. If the string already exists, the new variable will reference the existing string. However, if the string is not found in the pool, the new string will be added to the pool, and the variable will then point to this newly added string.
Syntax:
String s1 = "Hello"; // String literal
String s2 = "Hello"; // Points to the same "Hello" in the Pool as s1
The new operator is used to create strings that are not automatically added to the String Pool. Instead, these strings are stored in the heap memory separate from the Pool. This implies that every time the new operator is used, a new object is generated, even if it holds identical string information.
Syntax:
String s3 = new String("Hello"); // A new string object is created in the heap
During an internship, we have the option to add a string to the Pool manually or make sure it is using the Pool by invoking the intern method on a string object. When the Pool already has a matching string, the string from the Pool is retrieved. If there isn't a matching string, it will be added to the Pool.
Syntax:
String s4 = new String("Hello").intern(); // Ensures use of the string pool
Filename: StringMemoryAllotment.java
public class StringMemoryAllotment {
public static void main(String[] args) {
// String literals - stored in the string pool
String str1 = "Java";
String str2 = "Java";
// Checking if str1 and str2 point to the same object
System.out.println("str1 == str2: " + (str1 == str2)); // true, because both refer to the same string literal in the pool
// Strings created with 'new' - stored in heap memory outside the string pool
String str3 = new String("Java");
String str4 = new String("Java");
// Checking if str3 and str4 point to the same object
System.out.println("str3 == str4: " + (str3 == str4)); // false, because 'new' creates a new object each time
// Interning str3
String str5 = str3.intern();
// Checking if str1 and str5 point to the same object
System.out.println("str1 == str5: " + (str1 == str5)); // true, str5 is interned, so it refers to the string in the pool
// Demonstrating the effect of interning on memory allocation
String str6 = new String("Java").intern();
// Checking if str6 is the same as str1
System.out.println("str1 == str6: " + (str1 == str6)); // true, str6 is interned and points to the pooled instance
}
}
Output:
str1 == str2: true
str3 == str4: false
str1 == str5: true
str1 == str6: true
Construct String from a subset of the char array
In Java, it is possible to construct a String from a segment of a char array using a dedicated constructor within the String class. This constructor necessitates three arguments: the char array to utilize, a starting index denoting the beginning of the specified subset, and the number of characters to include in the subset. Below is the syntax along with an illustration:
Syntax:
String(char[] value)
String(char[] value, int offset, int count)
- value: The char array.
- offset: The initial offset into the array.
- count: The number of characters to use from the array.
Filename: CharArrayToString.java
public class CharArrayToString {
public static void main(String[] args) {
// Define a char array
char[] charArray = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'};
// Construct a string from a subset of the char array
// Here, we start at index 6 (the space character) and use the next 5 characters
String resultString = new String(charArray, 6, 5);
// Output the result
System.out.println(resultString);
}
}
Output:
Let's explore another instance of a Java String that is generated utilizing a char array.
StringExample.java
public class StringExample{
public static void main(String args[]){
String s1="java";//creating string by Java string literal
char ch[]={'s','t','r','i','n','g','s'};
String s2=new String(ch);//converting char array to string
String s3=new String("example");//creating Java string by new keyword
System.out.println(s1);
System.out.println(s2);
System.out.println(s3);
}}
Output:
java
strings
example
The code snippet above is responsible for transforming a character array into a String object. It then showcases these String objects, denoted as s1, s2, and s3, on the console by utilizing the println method.
Java String MCQ
- Which method can be used to compare two strings lexicographically in Java?
- compareTo
- equals
- compare
- equalsIgnoreCase
The compareTo function is used to compare two strings based on their lexicographical order. It returns a negative number if the first string comes before the second one, zero if the strings are the same, and a positive number if the first string comes after the second string.
- What will the code snippet below output?
String s = "Java";
s.concat("Point");
System.out.println(s);
- Java
- C# Tutorial
- C# Tutorial
- Point
Explanation: Strings in Java are immutable. The concat method creates a new string but does not change the original string. Therefore, the original string s remains "Java".
- How can you create a new string object from a character array in Java?
- new String(chars)
- String.valueOf(chars)
- String.copyValueOf(chars)
- All of the above
Explanation: All of the listed methods can create a new string from a character array. new String(chars), String.valueOf(chars), and String.copyValueOf(chars) are different ways to achieve this.
- Which method is used to convert all characters in a string to lowercase in Java?
- toLowerCase
- toLower
- toLowerCase(Locale locale)
- a and c
The function toLowerCase changes all characters in the string to lowercase based on the default locale, while the toLowerCase(Locale locale) function converts all characters to lowercase based on the specified locale.
- What will be the output of the code snippet below?
String str = " Hello World ";
System.out.println(str.trim());
- " Hello World "
- "Hello World"
- "Hello World "
- " Hello World"
Explanation: The trim method removes leading and trailing whitespace from the string, so the output is "Hello World."
- Why are String objects immutable?
- How to create an immutable class?
- What is string constant pool?
- What code is written by the compiler if you concatenate any string by + (string concatenation operator)?
- What is the difference between StringBuffer and StringBuilder class?
- Concept of String
- Immutable String
- String Comparison
- String Concatenation
- Concept of Substring
- String class methods and its usage
- StringBuffer class
- StringBuilder class
- Creating Immutable class
- toString method
- StringTokenizer class