Page Content

Tutorials

What is a String in Java? & Why do we use strings in Java?

String in Java

In Java, strings are fundamental for handling sequences of characters. Unlike many other programming languages where strings are often treated as arrays of characters, in Java, strings are objects of the java.lang.String class. This object-oriented approach provides a rich set of built-in features for string manipulation.

We use strings because they offer a comprehensive set of features for text manipulation. Even though they are objects, Java provides special support, allowing them to be created easily using string literals (e.g., "Hello World!") and concatenated with the + operator.

A key reason for their widespread use is their immutability: once a String object is created, its content cannot be changed. This characteristic allows for efficient memory management and enhances security. The String class provides numerous methods for tasks like comparing content (equals(), compareTo()), finding length (length()), accessing characters (charAt()), and extracting parts (substring()).

Being part of the java.lang package, which is automatically imported into every Java program, String is fundamental to core Java functionalities. For scenarios requiring modifiable character sequences, Java offers StringBuffer and StringBuilder.

Creating Strings

There are two main methods in Java for creating String objects:

  1. Using String Literals: The simplest method is to use double quote marks to surround a string of characters. Every time you use a string literal in your code, the Java compiler automatically generates a String object.
  2. Using the new keyword and Constructors: Use the new keyword and a String constructor to instantiate a String object, just like you would any other object. A number of constructors are available in the String class to initialise the strings including character arrays and other String objects.

String Literals vs. String Objects

Although String objects are produced by both approaches, there is a crucial difference between them. Because strings are “interned,” Java frequently utilises the same object instance for identical string literals in order to conserve memory. However, even if the content of the new keyword is the same as that of an existing string, it always generates a new object in memory.

This difference is critical when using the == operator versus the equals() method for comparison:

  • == operator: Object references (memory locations) are compared using the == operator. It only yields true if both variables point to the same memory object.
  • equals() method: Comparing the strings’ content (character sequence) is possible with the equals() method.

Consider this example:

String s1 = "Vengat"; // Literal string
String s2 = "Vengat"; // Literal string
String x1 = new String("vengat"); // Non-literal string
String x2 = new String("vengat"); // Non-literal string
System.out.println(s1 == s2); // Output: true (literals often share memory)
System.out.println(s1.equals(s2)); // Output: true (content is same)
System.out.println(x1 == x2); // Output: false (different objects)
System.out.println(x1.equals(x2)); // Output: true (content is same)

Output: true true false true

It is possible to determine whether objects share memory by using the System.identityHashCode() method.

String Immutability

A crucial characteristic of String objects in Java is that they are immutable. This means that once a String object is created, its content (the sequence of characters) cannot be changed.

When you perform an action that appears to change a string (such as concatenating or changing it to uppercase), Java actually creates a new String object with the updated sequence, leaving the old unaltered. Better security and effective implementation are made possible by this design decision.

Common String Methods

There are several ways to examine and work with string content using the String class:

  1. length(): Gives back how many characters are in the string.
  2. charAt(int index): Gives back the character at the key. Indexes for strings begin at zero.
  3. indexOf(String str) / lastIndexOf(String str): Using indexOf(String str) / lastIndexOf(String str), one can find the first or last instance of a given character or substring and retrieve its index. -1 if it cannot be located.
  4. substring(int beginIndex) / substring(int beginIndex, int endIndex): A new string that is a substring of the original string is returned by the substring(int beginIndex) / substring(int beginIndex, int endIndex) function. An exclusive index is the endIndex.
  5. equals(Object anObject) / equalsIgnoreCase(String anotherString): This function compares strings for equality regardless of case.
  6. compareTo(String anotherString): This function compares two strings lexicographically (using Unicode values) by using compareTo(String anotherString). if the invoking string is greater than anotherString, returns a positive number; if equal, returns 0.
  7. toUpperCase() / toLowerCase(): These functions change all characters in a new String to uppercase or lowercase.
  8. replace(CharSequence target, CharSequence replacement): The function replace(CharSequence target, CharSequence replacement) yields a new String with replacement for every instance of target.

Mutable Strings

Java offers StringBuffer and StringBuilder as two substitute classes for scenarios requiring modified character sequences because String objects are immutable.

  • StringBuffer: Thread-safe and synchronised is StringBuffer. This makes it appropriate for situations with multiple threads, but it has a performance penalty.
  • StringBuilder: Quicker than StringBuffer, but not thread-safe (non-synchronized). For operations that are single-threaded, it is recommended.

Both classes provide comparable ways to modify:

  1. append(String s): Concatenating content to the end is done with append(String s).
  2. insert(int offset, String s): The function insert(int offset, String s) adds content at a given location.
  3. replace(int startIndex, int endIndex, String str): A section of the string can be replaced using the replace function (int startIndex, int endIndex, String str).
  4. reverse(): Reversing the character sequence is possible with reverse().

Example demonstrating mutability:

StringBuffer strB = new StringBuffer("study");
strB.append("tonight");
System.out.println(strB); // Output: studytonight
String str = "study";
str.concat("tonight");
System.out.println(str); // Output: study (original String unchanged)

Output: studytonight study

Overview of Package

Every Java program imports the java.lang package automatically. Classes and interfaces that are essential to practically all Java programming are included in it.

The following are important classes in java.lang:

  • Object: In Java, all classes either directly or indirectly derive from Object, which is the base of the class hierarchy. Basic functions like equals(), hashCode(), and toString() are defined.
  • System: Offers standard input (System.in), standard output (System.out), and error streams (System.err) as well as access to system resources.
  • String: As mentioned, this is a representation of unchangeable character strings.
  • StringBuffer and StringBuilder: Character sequences that can be changed are provided by StringBuffer and StringBuilder.
  • Primitive Type Wrappers: Classes like Integer, Double, Boolean, Character, Long, Float, Byte, and Short that encapsulate primitive data types into objects. These are helpful for conversions between types or for actions that need objects (like collections). To convert a string to an integer, for instance, use Integer.parseInt("123").

This package provides the fundamental building blocks for creating any application and serves as the foundation for the Java programming language.

Index