tags:

views:

326

answers:

4

According to String#intern(), intern method is supposed to return the String from the String pool if the String is found in String pool, otherwise a new string object will be added in String pool and the reference of this String is returned.

So i tried this:

String s1 = "Rakesh";
String s2 = "Rakesh";
String s3 = "Rakesh".intern();

if ( s1 == s2 ){
    System.out.println("s1 and s2 are same");  // 1.
}

if ( s1 == s3 ){
    System.out.println("s1 and s3 are same" );  // 2.
}

I was expecting that s1 and s3 are same will be printed as s3 is interned, and s1 and s2 are same will not be printed. But the result is: both lines are printed. So that means, by default String constants are interned. But if it is so, then why do we need the intern method? In other words when should we use this method?

+1  A: 

String literals and constants are intenred by default. That is, "foo" == "foo" (declared by the String literals), but new String("foo") != new String("foo").

Bozho
So, the question is when should we use `intern`,
Rakesh Juyal
that was pointed to http://stackoverflow.com/questions/1833581/when-to-use-intern, and a number of other questions, some of them from yesterday.
Bozho
+6  A: 

Java automatically interns String literals. This means that in many cases, the == operator appears to work for Strings in the same way that it does for ints or other primitive values.

Since interning is automatic for String literals, the intern() method is to be used on Strings constructed with new String()

Using your example:

String s1 = "Rakesh";
String s2 = "Rakesh";
String s3 = "Rakesh".intern();
String s4 = new String("Rakesh");
String s5 = new String("Rakesh").intern();

if ( s1 == s2 ){
    System.out.println("s1 and s2 are same");  // 1.
}

if ( s1 == s3 ){
    System.out.println("s1 and s3 are same" );  // 2.
}

if ( s1 == s4 ){
    System.out.println("s1 and s4 are same" );  // 3.
}

if ( s1 == s5 ){
    System.out.println("s1 and s5 are same" );  // 4.
}

will return:

s1 and s2 are same
s1 and s3 are same
s1 and s5 are same

Refer to JavaTechniques "String Equality and Interning" for more information.

Miguel Fonseca
+1 for `String s5 = new String("Rakesh").intern();`
Rakesh Juyal
+2  A: 

On a recent project, some huge data structures were set up with data that was read in from a database (and hence not String constants/literals) but with a huge amount of duplication. It was a banking application, and things like the names of a modest set (maybe 100 or 200) corporations appeared all over the place. The data structures were already large, and if all those corp names had been unique objects they would have overflowed memory. Instead, all the data structures had references to the same 100 or 200 String objects, thus saving lots of space.

Another small advantage of interned Strings is that == can be used (successfully!) to compare Strings if all involved strings are guaranteed to be interned. Apart from the leaner syntax, this is also a performance enhancement. But as others have pointed out, doing this harbors a great risk of introducing programming errors, so this should be done only as a desparate measure of last resort.

The downside is that interning a String takes more time than simply throwing it on the heap, and that the space for interned Strings may be limited, depending on the Java implementation. It's best done when you're dealing with a known reasonable number of Strings with many duplications.

Carl Smotricz
@`The downside is that interning a String takes more time than simply throwing it on the heap, and that the space for interned Strings may be limited` even if you don't use intern method for String constant it will be interned automatically.
Rakesh Juyal
@Rakesh: There are not that many String constants in any given class usually, so it is not a problem of space/time with constants.
David Rodríguez - dribeas
Yes, Rakesh's comment doesn't apply because interning Strings is only (explicitly) done with Strings that are "generated" somehow, be it by internal manipulation or by retrieving from a database or such. With constants we don't have a choice.
Carl Smotricz
+1. I think this is a good example of when interning makes sense. I don't agree on `==` for strings though.
Alexander Pogrebnyak
@Carl. I've expanded my answer to show evils of `==`
Alexander Pogrebnyak
And I've updated my answer to warn the unwary :)
Carl Smotricz
A: 

I want to add my 2 cents on using == with interned strings.

The first thing String.equals does is this==object.

So although there is some miniscule performance gain ( you are not calling a method), from the maintainer point of view using == is a nightmare, because some interned strings have a tendency to become non-interned.

So I suggest not to rely on special case of == for interned strings, but always use equals as Gosling intended.

EDIT: interned becoming non-interned:

V1.0
public class MyClass
{
  private String reference_val;

  ...

  private boolean hasReferenceVal ( final String[] strings )
  {
    for ( String s : strings )
    {
      if ( s == reference_val )
      {
        return true;
      }
    }

    return false;
  }

  private void makeCall ( )
  {
     final String[] interned_strings =  { ... init with interned values ... };

     if ( hasReference( interned_strings ) )
     {
        ...
     }
  }
}

In version 2.0 maintainer decided to make hasReferenceVal public, without going into much detail that it expects an array of interned strings.

V2.0
public class MyClass
{
  private String reference_val;

  ...

  public boolean hasReferenceVal ( final String[] strings )
  {
    for ( String s : strings )
    {
      if ( s == reference_val )
      {
        return true;
      }
    }

    return false;
  }

  private void makeCall ( )
  {
     final String[] interned_strings =  { ... init with interned values ... };

     if ( hasReference( interned_strings ) )
     {
        ...
     }
  }
}

Now you have a bug, that may be very hard to find, because in majority of cases array contains literal values, and sometimes a non-literal string is used. If equals were used instead of == then hasReferenceVal would have still continue to work. Once again, performance gain is miniscule, but maintenance cost is high.

Alexander Pogrebnyak
"some interned strings have a tendency to become non-interned." wow, that would be... strange. Can you cite a reference, please?
Carl Smotricz
OK, I thought you were referring to Strings actually wandering out of the intern pool and onto the heap thanks to magic in the JVM. What you're saying is that == makes certain classes of programmer errors more likely.
Carl Smotricz