String Object in Java

Photo by Tormius on Unsplash

String Object in Java

Β·

5 min read

In Java, strings are objects that represent sequences of characters.

  • In context ofStringclass , 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 used

  • Mutation 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

  1. String Literal: Stored in the String Constant Pool (SCP).

     String s1 = "Hello";
    
  2. Using thenewkeyword: Creates a new String object in the heap.

     String s2 = new String("Hello");
    
  3. Usingchararray:

     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()

Β