When to use intern() on String literals
Asked Answered
S

4

41

I see a lot of legacy code like this:

class A {
    public static final String CONSTANT = "value".intern();
    ...
}

I don't see any reason for the intern(), as in the Javadoc one can read: "All literal strings and string-valued constant expressions are interned." Is there some intent of this, maybe in past revisions of the language?

Saintly answered 2/12, 2009 at 15:21 Comment(2)
Did anyone other than pjp actually read this question before answering it?Friday
possible duplicate of Are all compile-time constants inlined?Heyday
U
71

This is a technique to ensure that CONSTANT is not actually a constant.

When the Java compiler sees a reference to a final static primitive or String, it inserts the actual value of that constant into the class that uses it. If you then change the constant value in the defining class but don't recompile the using class, it will continue to use the old value.

By calling intern() on the "constant" string, it is no longer considered a static constant by the compiler, so the using class will actually access the defining class' member on each use.


JLS citations:

Uncertainty answered 2/12, 2009 at 15:43 Comment(5)
I just confirmed this experimentally, but is there a JLS citation?Rotogravure
This is similar to #378319Astrakhan
I guess people shouldn't go changing the value of constants which are visible to other classes.Astrakhan
that's a nice trick to know. but it looks quite weird. any better trick to do the same thing?Amethist
alternative A: call toString() on the string. this could be faster than intern()? alternative B: a utility method: String str(String s){ return s; } the method should be commented for its purpose - breaking compile time constant, so readers understand what's going on when they see: static final String ABC = str("xxx");Amethist
A
16

The use of intern() with the constant string literal is a waste of time as the literal will already be interned as specified by section 3.10.5. String Literals of The Java® Language Specification.

Quoting from Java SE 8 Edition:

Moreover, a string literal always refers to the same instance of class String. This is because string literals - or, more generally, strings that are the values of constant expressions (§15.28) - are "interned" so as to share unique instances, using the method String.intern.

I guess the coder didn't appreciate this fact.

Edit:

As kdgregory has pointed out there is an impact on how this constant may be inlined.

1- https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.10.5

Astrakhan answered 2/12, 2009 at 15:31 Comment(1)
The JLS talks about outcomes, but it's not clear whether this folding happens at compile-time, or whether it's just that there must be no observable difference between compile-time folding and concatenate-and-then-intern at run-time. Byte code inspection would answer whether two string concatenated literals become one in the class file.Overnice
T
8

A while ago I intern()ed all of the Strings coming from class files (for a classfile parser). Intern()ing made the program use less memory (won't in this case as others have pointed out) but it did slow the program down significantly (I think it took 4 seconds to parse all of rt.jar and that change put it over 8 seconds). Looking into it at the time (was JDK 1.4 I think) the intern() code is pretty ugly and slower that in probably needs to be.

If I were to consider calling intern() in my code I would first profile it without intern() and then profile it with intern() for both memory and speed and see which one is "worse" for the change.

Tributary answered 2/12, 2009 at 15:43 Comment(4)
wow... and the down votes for accurate info were for what? Is the information provided wrong?Tributary
indeed pjp was pretty generous with downvotes on this questionHuddleston
I don't care about the down votes... just the reason for them :-)Tributary
and also it puts significant load on the permgen space. So that might be a consideration as well.Enteric
A
0

I have used intern() for "locking". For instance, let's say I have a "repository" of "trade records". While I edit and update a trade I want to lock the trade; I might instead lock on the tradeId.intern() so that I don't have to worry about clones of a trade floating around. I am not sure if everybody likes this usage.

This assumes that the id field is unlikely to accidentally collide with the id field of another domain object - a tradeId doesn't happen to collide with account_number for instance, where one might also be doing

synchronized(account.getAccountNumber().intern()) {...}

see example

Abdella answered 10/1, 2012 at 19:39 Comment(5)
Isn't scala's Symbols basically doing String.intern() ?Abdella
The problem is that it will add the "trade" into the intern storage and never remove it, leading to potentially a lot of wasted memory (unless you use it quite often).Subir
I think String,intern() pool is garbage-collectible in modern JVMs. But yes one would usually rely on some persistent distributed means of locking.Abdella
true. See this article.Subir
…and then, at some other place, a similarly ingenious developer decided to use the same trick for a different property, car license plate, social security number, or whatever of type string which might coincidentally have values of the same contents. Leads to locking on the same key for entirely different things (performance degradation) or even things connected in some way (call for deadlocks).Trehalose

© 2022 - 2024 — McMap. All rights reserved.