Showing posts with label String. Show all posts
Showing posts with label String. Show all posts

Friday, August 26, 2011

String.intern()

String it is fundamental part of any modern programing language and just sa important as a number. That why can propose that Java programers must have strong knowledge about String, but, unfortunately not all programers.

Today I started read news and saw an interesting string, that very confused me.

protected final static String fVersionSymbol = "version".intern();

Next I found more strings declared like that. What is intern()? You know, exists two different way to compare objects in Java. You can use operator ==, or you can use method equals(). Operator == compare link is two link on one object, and equals() compare is two object contains the same data.

One of the first lessons, what you get when you start learn about String in Java is that for compare two strings you should use equals() and no ==. If compare new String("Hello")==new String("Hello") you get in result false, because this is two different object with the same data. if you use equals(), you get true. Unfortunately equals() can be more slowest than ==, because it does string compare by characters.

Operator == check identity, all what it must do is compare two index and obviously it will much faster than equals(). That if you want compare the same string manu times, you can get a significant performance advantage through the use of checking the identity of objects instead of comparing characters.

intern() main algorithm:

  1. Create a hash set strings 
  2. Check, that string (like characters sequence), with which we working, already in hash set 
  3. If yes, use string from hash set
  4. Otherwise, add this string in hash set and after use it 

Using this algorithm you guaranteed, that if two strings are identical sequences characters, they are one instance of a class. It's mean that you can easy compare strings using == instead of equals(), get a significant performance advantage when repetitive comparison.

Fortunately Java already includes implementation of this algorithm. This method intern() in class java.lang.String. Expresion new String("Hello").intern() == new String("Hello").intern() return true, otherwise with out intern() return false.

Method intern() simply before creating a String object check exist or not exist this object in String pool and return this object. Otherwise create new object in the pool.

All strings in Java already interned. That why "Hel" + "lo" == "Hello" return true.

Sunday, August 21, 2011

StringBuilder vs StringBuffer


StringBuilder was introduced in JDK 1.5. What's the difference between StringBuilder and StringBuffer? According to javadoc, StringBuilder is designed as a replacement for StringBuffer in single-threaded usage. Their key differences in simple term:
  • StringBuffer is designed to be thread-safe and all public methods in StringBuffer are synchronized. StringBuilder does not handle thread-safety issue and none of its methods is synchronized.
  • StringBuilder has better performance than StringBuffer under most circumstances.
Criteria to choose among String, StringBuffer and StringBuilder
  1. If your text is not going to change use a string Class because a String object is immutable.
  2. If your text can change and will only be accessed from a single thread, use a StringBuilder because StringBuilder is unsynchronized.
  3. If your text can changes, and will be accessed from multiple threads, use a StringBuffer because StringBuffer is synchronous.

Introduction

Concatenation of String is very easy in Java - all you need is a '+'. It can't get any easier than that, right? Unfortunately there are a few pitfalls. One thing you should remember from your first Java lessons is a small albeit important detail: String objects are immutable. Once constructed they cannot be changed anymore.
Whenever you "change" the value of a String you create a new object and make that variable reference this new object. Appending a String to another existing one is the same kind of deal: a new String containing the stuff from both is created and the old one is dropped.
You might wonder why String are immutable in first place. There are two very compelling reasons for it:
  1. Immutable basic types makes things easier. If you pass a String to a function you can be sure that its value won't change.
  2. Security. With mutable String one could bypass security checks by changing the value right after the check. (Same thing as the first point, really.)

The performance impact of String.concat()

Each time you append something via '+' (String.concat()) a new String is created, the old stuff is copied, the new stuff is appended, and the old String is thrown away. The bigger the String gets the longer it takes - there is more to copy and more garbage is produced.
Creating a String with a length of 65536 (character by character) already takes about 22 seconds on an AMD64 X2 4200+. The following diagram illustrates the exponentially growing amount of required time:
String.concat() - exponential growth
Figure 1: StringBuilder vs StringBuffer vs String.concat
StringBuilder and StringBuffer are also shown, but at this scale they are right onto the x-axis. As you can see String.concat() is slow. Amazingly slow in fact. It's so bad that the guys over at FindBugs added a detector for String.concat inside loops to their static code analysis tool.

When to use '+'

Using the '+' operator for concatenation isn't bad per se though. It's very readable and it doesn't necessarily affect performance. Let's take a look at the kind of situations where you should use '+'.
a) Multi-line String:
String text=
    "line 1\n"+
    "line 2\n"+
    "line 3";
Since Java doesn't feature a proper multi-line String construct like other languages, this kind of pattern is often used. If you really have to you can embed massive blocks of text this way and there are no downsides at all. The compiler creates a single String out of this mess and no concatenation happens at runtime.
b) Short messages and the like:
System.out.println("x:"+x+" y:"+y);
The compiler transforms this to:
System.out.println((new StringBuilder()).append("x:").append(x).append(" y:").append(y).toString());
Looks pretty silly, doesn't it? Well, it's great that you don't have to write that kind of code yourself. ;)
If you're interested in byte code generation: Accordingly to Arno Unkrig (the amazing dude behind Janino) the optimal strategy is to use String.concat() for 2 or 3 operands, and StringBuilder for 4 or more operands (if available - otherwise StringBuffer). Sun's compiler always uses StringBuilder/StringBuffer though. Well, the difference is pretty negligible.

When to use StringBuilder and StringBuffer

This one is easy to remember: use 'em whenever you assemble a String in a loop. If it's a short piece of example code, a test program, or something completely unimportant you won't necessarily need that though. Just keep in mind that '+' isn't always a good idea.

StringBuilder and StringBuffer compared

StringBuilder is rather new - it was introduced with 1.5. Unlike StringBuffer it isn't synchronized, which makes it a tad faster:
StringBuilder compared with StringBuffer
Figure 2: StringBuilder vs StringBuffer
As you can see the graphs are sort of straight with a few bumps here and there caused by re-allocation. Also StringBuilder is indeed quite a bit faster. Use that one if you can.