java.lang.String tips and tricks: Best Java Coding Practices

3881
Mar 20, 2016

java.lang.String class seems to be very similar to primitives in Java, but this is not the case. String class implements Fly weight design pattern to give better performance. Here are some tips and tricks which can be applied while using String objects in the code in Java

1. Compare two string by equals() instead ==


Use equals() because this method internally checks == plus content equality check.

public class Test {
public static void main(String[] args) {
String s1 = "string";
String s2 = "string";
String s3 = new String("string");
String s4 = s3;
String s5 = "str"+"ing";

System.out.println("s1==s2 :"+(s1==s2));
System.out.println("s1==s3 :"+(s1==s3));
System.out.println("s1.equals(s3) :"+s1.equals(s3));
System.out.println("s3==s4 :"+(s3==s4));
System.out.println("s3.equals(s4) :"+s3.equals(s4));
System.out.println("s1==s5 :"+(s1==s5));
System.out.println("s1.equals(s5) :"+s1.equals(s5));

}
}


and here is the comparison output

s1==s2 :true
s1==s3 :false
s1.equals(s3) :true
s3==s4 :true
s3.equals(s4) :true
s1==s5 :true
s1.equals(s5) :true



here s1 and s3 are equal by their content but not by their references. == can be used to compare two strings if both strings are literal constants. String class uses Fly weight design pattern which maintains a pools. If a new string literal is created, then it first search it into the pool, if it has then it will be used otherwise it will be created, added to the pool and then return its reference.That means in above code, s1 and s2 will have same reference in the pool, while s3 will create a new object in pool, and has distinct reference.

Did you notice comparison of s1 and s5 ? s1==s5 is true this is because "str" and "ing" both are literal and combined string "string" is placed into the pool.



2. Use StringBuilder for String concatenations instead of + operator


If you have more string concatenation operations, then prefer using StringBuilder object over + operator Here is simple performance comparison if we are concatenating string 10 times.

public class Test {
public static void main(String[] args) {

String finalString = "";
long startTime = System.nanoTime();
for(int i=0;i<10;i++) {
finalString = finalString + i;
}
long endTime = System.nanoTime();
System.out.println(String.format("String opetation with + operator took [%d] nano seconds",(endTime-startTime)));

StringBuilder builder = new StringBuilder();
startTime = System.nanoTime();
for(int i=0;i<10;i++) {
builder.append(i);
}
endTime = System.nanoTime();
System.out.println(String.format("String opetation with StringBuilder took [%d] nano seconds",(endTime-startTime)));

}
}


and the result is

String opetation with + operator took [308289] nano seconds
String opetation with StringBuilder took [15902] nano seconds

from the result it is clear that using StringBuilder is more than 19 times faster than concatenating the string with + operator.


3. Call .equals on known string constants rather than unknown variable



public class Test {
public static final String CONSTANT = "someConstant";

public static void main(String[] args) {
String string = new Test().getString();
// always compare like this, this will never throw NPE
System.out.println("CONSTANT.equals(string):"+CONSTANT.equals(string));
System.out.println("Comparision like string.equals(CONSTANT) may throw NullPointerException");
// next statement will throw NPE
System.out.println("string.equals(CONSTANT):"+string.equals(CONSTANT));

}

private String getString() {
return null;
}
}


and here is the result

CONSTANT.equals(string):false
Comparision like string.equals(CONSTANT) may throw NullPointerException
Exception in thread "main" java.lang.NullPointerException
at Test.main(Test.java:10)




4. Use switch( ) instead of multiple if else-if


Java 1.7 introduces the switch statement for Strings. If there is scenario to compare multiple strings then use switch over multiple if - else-if statements. Here is a comparison of performance of these two approaches

public class Test {
public static final String CONSTANT = "someConstant";

public static void main(String[] args) {
Test test = new Test();
long startTime = System.nanoTime();
test.convertStringToIntegerWithSwitch("FOUR");
long endTime = System.nanoTime();
System.out.println(String.format("String comparison with Switch took [%d] nano seconds.",(endTime-startTime)));

startTime = System.nanoTime();
test.convertStringToIntegerWithIf("FOUR");
endTime = System.nanoTime();
System.out.println(String.format("String comparison with If took [%d] nano seconds.",(endTime-startTime)));
}

private int convertStringToIntegerWithSwitch(String stringNumber) {
switch(stringNumber) {
case "ZERO" :
return 0;
case "ONE":
return 1;
case "TWO":
return 2;
case "THREE":
return 3;
default :
return -1;
}
}

private int convertStringToIntegerWithIf(String stringNumber) {
if("ZERO".equals(stringNumber)) {
return 0;
} else if("ONE".equals(stringNumber)) {
return 1;
} else if("TWO".equals(stringNumber)) {
return 2;
} else if("THREE".equals(stringNumber)) {
return 3;
} else {
return -1;
}
}
}

and the result is

String comparison with Switch took [12311] nano seconds.
String comparison with If took [26161] nano seconds.


That means using switch we can improve the performance, from the above result it is clear that comparison with if-else takes double time than time taken by switch. This example has only 4 comparison, if there are more than 4 if-else then switch will give more better result than if-else


5. Use String.valueOf() instead of toString()



If obj needs to be converted to string then the result of obj.toString() and String.valueOf(obj) will be same but String.valueOf() is null safe, means it will never throw NullPointerException.

Test test = null;
// Below statement will not throw NPE
System.out.println(String.valueOf(test));
// Next statement will throw NPE
System.out.println(test.toString())

means if we are sure the object will never be null then we should always use toString() otherwise String.valueOf() is preferable.


6. Create Strings as literals instead of creating String objects using 'new'



Always create string constants like String constant = "constantValue" because String implements Fly Weight design pattern, which maintains a pool, if "constantValue" string is already present in the pool then it will return the reference from pool, otherwise it will create a new object, put it into pool and then return the reference of this object. If somewhere else in the code if we again create String constant1 = "constantValue" then it won't create a new String object and will return reference of previously created object from pool.

While if String constant = new String("constantValue") is used to create a string, then it will not search the string "constantValue" in the pool instead it will create a new object every time and put it into pool and return new reference, means if we have new String("constantValue") ten places in the code, it will create 10 new object every time.


7. Use String.format() to format the the strings



String.format() has very good feature if we want to have a single formatted string with multiple values. for example

public class Test {
public static void main(String[] args) {
int obtainedMarks = 86;
int maxMarks = 120;
double percent = obtainedMarks*100.0/ maxMarks;

System.out.println(String.format("I secured [%d] marks out of [%d] which is %.2f%%",obtainedMarks,maxMarks,percent));
}
}
will print: I secured [86] marks out of [120] which is 71.67%

In this example we formatted the output in very simple manner e.g. we converted the percent to 2 decimal places.


8. Use org.apache.commons.lang3.StringUtils Utility class for various String related operations


org.apache.commons.lang3.StringUtils utility class lots of utility methods that we generally perform on string objects. these methods are easy to use and can same developers time to write various utility methods. for more details visit http://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/StringUtils.html

comments powered by Disqus

© Copyright 2017