When should we use intern method of String on String literals
Asked Answered
R

14

200

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?

Reef answered 6/12, 2009 at 11:50 Comment(7)
The Javadoc you linked also states "All literal strings and string-valued constant expressions are interned."Pentothal
dupe of https://mcmap.net/q/22377/-when-to-use-intern-on-string-literalsSanctity
not an exact duplicate..Kermanshah
@Jorn: that's right. So why do we have intern as public method. Shouldn't we have intern as private method, so that nobody could have access to it. Or is there any purpose of this method?Reef
Bozho: Well actually it is, this one's just a lot better refined as a question.Vacillating
You do not need to use intern() on "Rakesh" in statement String s3 = "Rakesh".intern(); as string literals automatically got interned.Si
@RakeshJuyal: The intern method is defined on a string type which can be string literals or variables. How would you intern a variable if the method was private?Moffett
S
249

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

In all the cases besides of s4 variable, a value for which was explicitly created using new operator and where intern method was not used on it's result, it is a single immutable instance that's being returned JVM's string constant pool.

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

Shippy answered 6/12, 2009 at 11:54 Comment(8)
I'm assuming that Java automatically interns String literals for optimization purposes. It can do this safely only because Strings are immutable, correct?Doll
New to Java (I am from the C#.NET world) and I sometimes see in a Java legacy project "".intern() so if I understand it correctly that this is "nonsense" also for empty strings.Hyposthenia
@Miguel Nice explanation , My question is how may object created here in you example . Here is My Assumption : String s1 = "Rakesh"; first OB1 String s4 = new String("Rakesh"); Second OB2 So rest of (s2,s3,s5) reference same object (OB1) created in 'string Pool' So can i say that .intern() method used for prevent to create new object if same string available in string pool If my assumption is wrong so give me direction .Tint
The JavaTechniques link is brokenConservative
examples.javacodegeeks.com/core-java/lang/string/…Snide
I think String s4 = new String("Rakesh"); creates two objects one in heap and one in string constant pool. Hence I think string constant pool know will have duplicate value of "Rakesh"Marozik
@Miguel when string created with new keyword two objects are created one in heap and one in string constant pool then what is the use of interning string object created by new keyword?Raspberry
@Hyposthenia yes, it's nonsense (or obfuscation ;)).Nave
A
22

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.

Alita answered 6/12, 2009 at 11:59 Comment(6)
@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.Reef
@Rakesh: There are not that many String constants in any given class usually, so it is not a problem of space/time with constants.Dowling
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.Alita
+1. I think this is a good example of when interning makes sense. I don't agree on == for strings though.Sackett
You shouldn't <i>usually</i> do == string comparison. I have found only 1 use for direct reference comparison in my career so far (I cant provide the use case, so you'll have to use your imagination). so there are purposes, just not many.Deduce
From Java 7 onwards the "String pool" is Implemented into heap space , so it gets all advantages of storing interns, garbage collection and the size of it is not limited , it can be increased upto heap size.(you will never need that much memory for strings)Kilk
S
19

Prefer String.equals over this==object

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

The first thing String.equals does is this==object. See source code on OpenJDK.

public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    …

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.

Sackett answered 6/12, 2009 at 12:13 Comment(4)
"some interned strings have a tendency to become non-interned." wow, that would be... strange. Can you cite a reference, please?Alita
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.Alita
"So I suggest not to rely on special case of == for interned strings, but always use equals as Gosling intended." Do you have a direct quote or comment from Gosling stating this? If that's the case why did he even bother putting intern() and the use of == in the language?Sauls
intern is not good for direct comparion (==), even though it works if both strings are interned. it is great to lower total memory used : when the same string is used in more than 1 place.Ostiary
F
18

Learn Java String Intern - once for all

Strings in java are immutable objects by design. Therefore, two string objects even with same value will be different objects by default. However, if we wish to save memory, we could indicate to use same memory by a concept called string intern.

The below rules would help you understand the concept in clear terms:

  1. String class maintains an intern-pool which is initially empty. This pool must guarantee to contain string objects with only unique values.
  2. All string literals having same value must be considered same memory-location object because they have otherwise no notion of distinction. Therefore, all such literals with same value will make a single entry in the intern-pool and will refer to same memory location.
  3. Concatenation of two or more literals is also a literal. (Therefore rule #2 will be applicable for them)
  4. Each string created as object (i.e. by any other method except as literal) will have different memory locations and will not make any entry in the intern-pool
  5. Concatenation of literals with non-literals will make a non-literal. Thus, the resultant object will have a new memory location and will NOT make an entry in the intern-pool.
  6. Invoking intern method on a string object, either creates a new object that enters the intern-pool or return an existing object from the pool that has same value. The invocation on any object which is not in the intern-pool, does NOT move the object to the pool. It rather creates another object that enters the pool.

Example:

String s1=new String ("abc");
String s2=new String ("abc");
If (s1==s2)  //would return false  by rule #4
If ("abc" == "a"+"bc" )  //would return true by rules #2 and #3
If ("abc" == s1 )  //would return false  by rules #1,2 and #4
If ("abc" == s1.intern() )  //would return true  by rules #1,2,4 and #6
If ( s1 == s2.intern() )      //wound return false by rules #1,4, and #6

Note: The motivational cases for string intern are not discussed here. However, saving of memory will definitely be one of the primary objectives.

Flavin answered 31/3, 2017 at 22:24 Comment(1)
Thank you for #3, I didnt know :)Aimo
K
11

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

Kermanshah answered 6/12, 2009 at 11:53 Comment(3)
So, the question is when should we use intern,Reef
that was pointed to https://mcmap.net/q/22377/-when-to-use-intern-on-string-literals, and a number of other questions, some of them from yesterday.Kermanshah
Let me know if my understanding for this statement : String literals and constants are interned by default, is correct. new String("foo") --> Here, one String literal "foo" is created in String pool and one in heap, so total 2 objects are created.Karlee
S
4

you should make out two period time which are compile time and runtime time.for example:

//example 1 
"test" == "test" // --> true 
"test" == "te" + "st" // --> true

//example 2 
"test" == "!test".substring(1) // --> false
"test" == "!test".substring(1).intern() // --> true

in the one hand,in the example 1,we find the results are all return true,because in the compile time,the jvm will put the "test" to the pool of literal strings,if the jvm find "test" exists,then it will use the exists one,in example 1,the "test" strings are all point to the same memory address,so the example 1 will return true. in the other hand,in the example 2,the method of substring() execute in the runtime time, in the case of "test" == "!test".substring(1),the pool will create two string object,"test" and "!test",so they are different reference objects,so this case will return false,in the case of "test" == "!test".substring(1).intern(),the method of intern() will put the ""!test".substring(1)" to the pool of literal strings,so in this case,they are same reference objects,so will return true.

Southeastwardly answered 1/9, 2014 at 8:40 Comment(0)
M
3

http://en.wikipedia.org/wiki/String_interning

string interning is a method of storing only one copy of each distinct string value, which must be immutable. Interning strings makes some string processing tasks more time- or space-efficient at the cost of requiring more time when the string is created or interned. The distinct values are stored in a string intern pool.

Monique answered 12/9, 2013 at 18:47 Comment(0)
H
2

Interned Strings avoid duplicate Strings. Interning saves RAM at the expense of more CPU time to detect and replace duplicate Strings. There is only one copy of each String that has been interned, no matter how many references point to it. Since Strings are immutable, if two different methods incidentally use the same String, they can share a copy of the same String. The process of converting duplicated Strings to shared ones is called interning.String.intern() gives you the address of the canonical master String. You can compare interned Strings with simple == (which compares pointers) instead of equals which compares the characters of the String one by one. Because Strings are immutable, the intern process is free to further save space, for example, by not creating a separate String literal for "pot" when it exists as a substring of some other literal such as "hippopotamus".

To see more http://mindprod.com/jgloss/interned.html

Hedberg answered 22/8, 2013 at 4:31 Comment(0)
B
2
String s1 = "Anish";
        String s2 = "Anish";

        String s3 = new String("Anish");

        /*
         * When the intern method is invoked, if the pool already contains a
         * string equal to this String object as determined by the
         * method, then the string from the pool is
         * returned. Otherwise, this String object is added to the
         * pool and a reference to this String object is returned.
         */
        String s4 = new String("Anish").intern();
        if (s1 == s2) {
            System.out.println("s1 and s2 are same");
        }

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

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

OUTPUT

s1 and s2 are same
s1 and s4 are same
Barrow answered 12/11, 2013 at 10:37 Comment(0)
M
2
String p1 = "example";
String p2 = "example";
String p3 = "example".intern();
String p4 = p2.intern();
String p5 = new String(p3);
String p6 = new String("example");
String p7 = p6.intern();

if (p1 == p2)
    System.out.println("p1 and p2 are the same");
if (p1 == p3)
    System.out.println("p1 and p3 are the same");
if (p1 == p4)
    System.out.println("p1 and p4 are the same");
if (p1 == p5)
    System.out.println("p1 and p5 are the same");
if (p1 == p6)
    System.out.println("p1 and p6 are the same");
if (p1 == p6.intern())
    System.out.println("p1 and p6 are the same when intern is used");
if (p1 == p7)
    System.out.println("p1 and p7 are the same");

When two strings are created independently, intern() allows you to compare them and also it helps you in creating a reference in the string pool if the reference didn't exist before.

When you use String s = new String(hi), java creates a new instance of the string, but when you use String s = "hi", java checks if there is an instance of word "hi" in the code or not and if it exists, it just returns the reference.

Since comparing strings is based on reference, intern() helps in you creating a reference and allows you to compare the contents of the strings.

When you use intern() in the code, it clears of the space used by the string referring to the same object and just returns the reference of the already existing same object in memory.

But in case of p5 when you are using:

String p5 = new String(p3);

Only contents of p3 are copied and p5 is created newly. So it is not interned.

So the output will be:

p1 and p2 are the same
p1 and p3 are the same
p1 and p4 are the same
p1 and p6 are the same when intern is used
p1 and p7 are the same
Melchizedek answered 12/7, 2016 at 8:56 Comment(0)
E
1

string intern() method is used to create an exact copy of heap string object in string constant pool. The string objects in the string constant pool are automatically interned but string objects in heap are not. The main use of creating interns is to save the memory space and to perform faster comparison of string objects.

Source : What is string intern in java?

Emersonemery answered 31/3, 2015 at 17:30 Comment(0)
K
1

As you said, that string intern() method will first find from the String pool, if it finds, then it will return the object that points to that, or will add a new String into the pool.

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

    System.out.println(s1 == s2);//true
    System.out.println(s1 == s3);//true
    System.out.println(s1 == s4.intern());//true

The s1 and s2 are two objects pointing to the String pool "Hello", and using "Hello".intern() will find that s1 and s2. So "s1 == s3" returns true, as well as to the s3.intern().

Karissakarita answered 20/4, 2015 at 13:2 Comment(1)
This doesn't really provide much new information. There's already an excepted answer.Janus
B
1
    public static void main(String[] args) {
    // TODO Auto-generated method stub
    String s1 = "test";
    String s2 = new String("test");
    System.out.println(s1==s2);              //false
    System.out.println(s1==s2.intern());    //true --> because this time compiler is checking from string constant pool.
}
Bonnibelle answered 17/2, 2018 at 19:55 Comment(0)
C
1

By using heap object reference if we want to get corresponding string constant pool object reference, then we should go for intern()

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

System.out.println(s1 == s2); // false
System.out.println(s2 == s3); // true

Pictorial View enter image description here

Step 1: Object with data 'Rakesh' get created in heap and string constant pool. Also s1 is always pointing to heap object.

Step 2: By using heap object reference s1, we are trying to get corresponding string constant pool object referenc s2, using intern()

Step 3: Intentionally creating a object with data 'Rakesh' in string constant pool, referenced by name s3

As "==" operator meant for reference comparison.

Getting false for s1==s2

Getting true for s2==s3

Hope this help!!

Califate answered 1/2, 2020 at 18:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.