BogoToBogo
  • Home
  • About
  • Big Data
  • Machine Learning
  • AngularJS
  • Python
  • C++
  • go
  • DevOps
  • Kubernetes
  • Algorithms
  • More...
    • Qt 5
    • Linux
    • FFmpeg
    • Matlab
    • Django 1.8
    • Ruby On Rails
    • HTML5 & CSS

String, StringBuffer, and StringBuilder - 2020

Duke 512




Bookmark and Share





bogotobogo.com site search:




String

Handling characters in supported through three final classes: String, StringBuilder and StringBuffer.

StringBuilder class was added to the API, to provide faster, nonsynchronized StringBuffer capability. The StringBuilder class has exactly the same methods as the old StringBuffer class, but StringBuilder is faster because its methods aren't synchronized. Both classes give us String-like object that handle some of the String class's shortcomings such as immutability.





Immutability

The String class implement immutable character strings, which are read-only once the string has been created and initialized, whereas StringBuilder class implements dynamic character strings. The StringBuffer class is a thread-safe version of the StringBuilder class.

A String object can never be changed. But what is happening when a String object seems to be changing?

Each character in a string is a 16-bit Unicode character. Since Unicode characters are 16-bit, international set of characters is easily represented in Unicode.

Because strings are object, we can create an instance of a String with new keyword.

String s = new String();

This creates a new object of class String, and assigns it to the reference variable s. Let's give it to some value:

s = "Java";

Actually, because String class has lots of constructors, we can do the same in one line:

String s = "Java";

Another String object:

String s2 = s;

So, s and s2 refer the same object.

How about the following line?

s = s.concat(" String"); 

Aren't Strings immutable?

Let's look at the following example.

public class StringTest {
	public static void main(String[] args) {	
		String s = "Java";		// (1)
		String s2 = s;			// (2)
		s = s.concat(" String");	// (3)
		System.out.println("s = " + s);
		System.out.println("s2 = " + s2);
	}
}

Output is:

s = Java String
s2 = Java

On the heap, we have two String objects: "Java" and "Java String". Also we have two reference variables: s refers to "Java String" and s2 refers to "Java" starting from line (2). So, at the line (3), the old String "Java" did not changed to "Java String" instead a new String was created and initialize with "Java String".

How about the output from the following code?

public class StringTest {
	public static void main(String[] args) {	
		String s = "Java";
		String s2 = s;
		s = s.concat(" String");
		System.out.println("s = " + s);
		System.out.println("s2 = " + s2);
		
		s.concat(" is Immutable!");	// What's happening?
		System.out.println("s = " + s);
	}
}

Output is:

s = Java String
s2 = Java
s = Java String

A new String is created but it has not reference variable which can point to the newly create string.

	s.concat(" is Immutable!");	// What's happening?

So, we do have a String object, "Java String is Immutable!". But we do not have the reference which can refer to the object. New String object has been created but we lost it. It's somewhere on the heap. But we do not know how we can get it.

How about this?

String s = "Android";
s.toUpperCase();
System.out.println("s = " + s);   

The output is still:

s = Android

Same result from the following code:

s = "Android";
s.replace('d','D');
System.out.println("s = " + s); 

The output is still:

s = Android

How about this?

s = "Android";
s = s.concat(" is getting better");
System.out.println("s = " + s); 

Output is:

s = Android is getting better

Finally we get a new string!
But we lost our old String object, "Android".

What's the output from the following code?

String s1 = "North ";
String s2 = s1 + "East ";
s1.concat("South ");
s2.concat(s1);
s1 += "West ";
System.out.println(s1 + " " + s2);

Output is

North West  North East 

We have two reference variables, s1 and s2. We had a total of eight String objects created as follows in order: "North", "East" (lost), "North East", "South" (lost), "North South" (lost), "North East North" (lost), "West" (lost), "North West" (at this point, the first object "North" is lost). So, only two of the eight String objects are not lost in this process.




Strings and Memory

As application grows, it's very common for String literals to occupy large amounts of memory, and there are often a lot of redundant String literals on the heap. To make Java more memory efficient, the JVM sets aside a special area of memory called String constant pool.

When the compiler encounters a String literal, it checks the pool to see if an identical String already exists. If there is a match, the reference to the new literal is directed to the existing String, and as a result, no new String literal object is created.

If several reference variables refer to the same String without even knowing it, it would be very bad if any of them could change the String's value.

The reason the String class is marked final is to prevent somebody from overriding the behavior of any of the String method. In that way, we can rest assured that the String objects we are counting on to be immutable, will remain immutable.



String and "new" Keyword

When we do

String s = "Java";

we are create one String object and one reference variable and the String object "Java" will go in the pool and s will refer to it.

But when we do

String s = new String("Java");

Java will create a new String object in normal (which is not pool) memory because we are using new keyword. The reference variable s will refer to it. The literal "Java" will be placed in the pool.



String Class Method
  1. char charAt(int index)
    This method returns the character located at the String's specified index.
    String s = "Michelangelo";
    System.out.println(s.charAt(4));		// output is 'e'
    

    The following code checks if a string consists of unique string:
    (1) using 256 integer array, (2) using an integer as a flag utilizing the bit pattern in it (assuming a string is has lower case only from a to z).

    package com.bogotobogo;
    
    public class UniqueString {
    	public static void main(String[] args){
    		String[] str = {"Garbage", "Collection", "String"};
    		for(String s: str) {
    			IsUnique(s);
    			IsUniqueBits(s);
    		}
    	}
    	
    	public static void IsUnique(String str) {
    		boolean flag[] = new boolean[256];
    		int index = 0;
    		for (int i = 0; i < str.length(); i++) {
    			index = str.charAt(i);
    			if(flag[index] == true) {
    				System.out.println(str + " is not unique");
    				return;
    			}
    			flag[index] = true;
    		}
    		System.out.println(str + " is unique");
    	}
    	
    	public static void IsUniqueBits(String str) {
    		int flag = 0;
    		str.toLowerCase();
    		for(int i = 0; i < str.length(); i++) {
    			int bitPosition = str.charAt(i)-'0';
    			if( (flag & (1 << bitPosition)) > 0 ) {
    				System.out.println(str + " is not unique");
    				return;			
    			}
    			flag |= 1 << bitPosition;
    		}
    		System.out.println(str + " is unique");
    	}
    }
    

    Output:

    Garbage is not unique
    Garbage is not unique
    Collection is not unique
    Collection is not unique
    String is unique
    String is unique
    
  2. String concat(String s)
    This method returns a String with the value of the String passed in to the method appended to the end of the String used to invoke the method.
    String s = "Dali: ";
    System.out.println(s.concat("Persistence of Memory")); 
    	// output is "Dali: Persistence of Memory"
    
  3. boolean equalsIgnoreCase(String s)
    This method returns a boolean value depending on whether the value of the String in the argument is the same as the value of the String used to invoke the method. This method will return true even when characters in the String objects being compared have different cases.
    String s = "Klimt";
    System.out.println(s.equalsIgnoreCase("klimt"));	// "true"
    System.out.println(s.equalsIgnoreCase("klit"));		// "false"
    
  4. int length()
    This method returns the length of the String used to invoke the method.
    String s = "Van Gogh";
    System.out.println(s.length());	// output is "8"
    
  5. String replace(char old, char new)
    This method returns a String whose value is that of the String used to invoke the method, updated so that any occurence of the char in the first argument is replaced by the char in the second argument.
    String s = "Rembrandt";
    System.out.println(s.replace('r','R'));	// output is "RembRandt"
    
  6. String substring(int begin)
    String substring(int begin, int end)
    This method is used to return a part of the String used to invoke the method.
    String s = "Velasquez";
    System.out.println(s.substring(1));	// output is "elasquez"
    System.out.println(s.substring(1,4));	// output is "ela"
    
  7. String toLowerCase()
    This method returns a String whose value is the String used to invoke the method, but with any uppercase characters converted to lowercase.
    String s = "Rousseau";
    System.out.println(s.toLowerCase());	// output is "rousseau"
    
  8. String toString()
    This method returns the value of the String used to invoke the method. Why do we need such method? All objects in Java must have a toString() method, which typically returns a String that in some meaningful way of describing the object in question. In the case of a String object, what is more meaningful way than the String's value?
    String s = "Renoir";
    System.out.println(s.toString());	// output is "Renoir"
    
  9. String toUpperCase()
    This method returns a String whose value is the String used to invoke the method, but with lowercase characters converted to uppercase.
    String s = "goya";
    System.out.println(s.toUpperCase());	// output is "GOYA"
    
  10. String trim()
    This method returns a String whose value is the String used to invoke the method, but with any leading or trailing blank spaces removed.
    String s = "   Rubens   ";
    System.out.println(s.trim() + ": Debarquement de Marie de Medicis");
    // output is "Rubens: Debarquement de Marie de Medicis"
    




  11. StringBuffer

    Main difference between String and StringBuffer is String is immutable while StringBuffer is mutable. This means we can modify a StringBuffer object once you created it without creating any new object. This mutable property makes StringBuffer an ideal choice for dealing with Strings in Java. We can convert a StringBuffer into String by its toString() method.





    StringBuilder

    StringBuffer is very good with mutable String but it has one disadvantage: All its public methods are synchronized which makes it thread-safe but same time slow. StringBuilder in Java is a copy of StringBuffer but without synchronization. Try to use StringBuilder whenever possible it performs better in most of cases than StringBuffer class. We can also use "+" for concatenating two string because "+" operation is internal implemented using either StringBuffer or StringBuilder in Java.



    The code below is an example of concatinating strings using the three methods of String handling.

    package com.bogotobogo;
    
    public class Concat {
    	public static void main(String[] args) {
    		String [] sIn = {"An ", "Array ", "of ", "Java ", "strings"};
    		System.out.println("String: " + concatString(sIn));
    		System.out.println("StringBuffer: " + concatStringBuffer(sIn));
    		System.out.println("StringBuilder: " + concatStringBuilder(sIn));
    	}
    	
    	public static String concatString(String[] in)
    	{
    		String sentence = "";
    		for(String s: in)
    			sentence = sentence.concat(s);
    		return sentence;
    	}
    	
    	public static String concatStringBuffer(String[] in)
    	{
    		StringBuffer sentence = new StringBuffer();
    		for(String s: in)
    			sentence.append(s);
    		return sentence.toString();
    	}
    	
    	public static String concatStringBuilder(String[] in)
    	{
    		StringBuilder sentence = new StringBuilder();
    		for(String s: in)
    			sentence.append(s);
    		return sentence.toString();
    	}
    }
    
    

    All of them are giving us the same output: "An Array of Java strings". However, there are some differences among them. Next section will discuss those differences.





    Sring, StringBuffer, and StringBuilder

    1. String is immutable while StringBuffer and StringBuilder is mutable object.
    2. StringBuffer is synchronized while StringBuilder is not which makes StringBuilder faster than StringBuffer.
    3. Concatenation operator "+" is internal implemented using either StringBuffer or StringBuilder.
    4. Use String if immutability is required, use Stringbuffer if mutable and thread-safety are rerquired and use StringBuilder if mutable is reuired but not thread-safety.
    5. It's very rare for a String manimuplating requires thread-safety. So, in most cases, we should use StringBuilder rather than using StringBuffer.





Ph.D. / Golden Gate Ave, San Francisco / Seoul National Univ / Carnegie Mellon / UC Berkeley / DevOps / Deep Learning / Visualization

YouTubeMy YouTube channel

Sponsor Open Source development activities and free contents for everyone.

Thank you.

- K Hong







Java Tutorials



Java Tutorial Home

Basics - Compiling and Launching

Inner Classes

Constructor

Enums

Static & Finally

Default and Protected

Polymorphism

Exception Handling

Exception Handling II

String Class

Threads

Threads II - State Transition

Threads III - Synchronization

Object Class

File I/O

Serialization

ArrayList

Autoboxing

Java Graphics Interface I - Basics

Java Graphics Interface II - Labels, Text Fields, Layouts

Java Graphics Interface III - paintComponent

TCP Sockets Server/Client

Scala - Functional Java Programming

Apache CXF install

Tomcat 7 Ubuntu 14 Install on Amazon EC2 instance

What is Apache Maven?

Maven life cycle

Eclipse Maven 3 plugin on Ubuntu 14.04

Apache Maven 3 - Setting up and creating a project

Apache Maven 3 - Compile, build, and install a Maven project

Apache Maven 3 - Dependencies

Apache Maven 3 - Web Application

Apache Maven 3 - Plugins (compiler)

Apache Maven 3 - Plugins (Jetty)

Eclipse CDT / JNI (Java Native Interface) / MinGW



Spring Framework

Hello World App with Spring 4 & Maven 3 - Part I




Sponsor Open Source development activities and free contents for everyone.

Thank you.

- K Hong







Spring Boot



Spring Boot : Hello world with Mavan 3

Spring Boot : Hello world with Gradle 2

Spring Boot (Gradle 2) : Hello world with Authentication

Spring Boot : Deploying War file to Tomcat 8's webapps

How to Setup Apache as Reverse Proxy for Tomcat Server using mod proxy

Maven : mvn command cheat sheet

Spring-Boot REST API with CORS App Maven war file deploy to Tomcat

Spring-Boot / Spring Security with AngularJS - Part I (Introduction)

Spring-Boot / Spring Security with AngularJS - Part II (Dynamic resource load from Angular)

Spring-Boot / Spring Security with AngularJS : Part III (Form-based Authentication)





JUnit & Maven Tutorial



JUnit 4 Introduction (Hello World)

JUnit 4 Test with Eclipse Luna (Hello World)

JUnit 4 Test with Maven (Hello World)











Contact

BogoToBogo
contactus@bogotobogo.com

Follow Bogotobogo

About Us

contactus@bogotobogo.com

YouTubeMy YouTube channel
Pacific Ave, San Francisco, CA 94115

Pacific Ave, San Francisco, CA 94115

Copyright © 2024, bogotobogo
Design: Web Master