-1

I wanted to change a code which was like

if("T".equalsIgnoreCase(bo.getSubjectType()))  //method-1

to

if(String.valueOf('T').equalsIgnoreCase(bo.getSubjectType()))  //method-2

So for that reason I wrote a sample code

String s1 = "T";
String s2 = "T";
char c1 = 'T';
char c2 = 'T';
System.out.println(String.valueOf(c1) == String.valueOf(c2));   //  false
System.out.println(s1 == s2);   //  true

Which pretty much says String.valueOf(arg) produces a String literal and places it in constant pool. So my question is whether there would be any contrast in performance when we try to manipulate a String in non-constant pool and that in a constant pool - basically which one would be better approach method-1 or method-2?

Arun Sudhakaran
  • 2,167
  • 4
  • 27
  • 52
  • 2
    I don't see the relevance of the sample code here, or string pools, or whatever. 1 is clearly better. – Andy Turner Jan 24 '19 at 09:20
  • 2
    "Which pretty much says String.valueOf(arg) produces a String literal and places it in constant pool" I don't understand how you reached this conclusion. If it went into the constant pool, `String.valueOf(c1) == String.valueOf(c2)` would be true. – Andy Turner Jan 24 '19 at 09:22
  • `String.valueOf(c1) == String.valueOf(c2)` says false which means two string literals with same value are having different address location and so it must be in constant pool where constants are allowed – Arun Sudhakaran Jan 24 '19 at 09:25
  • 1
    "it must be in constant pool" That is simply wrong. – Andy Turner Jan 24 '19 at 09:26
  • 1
    "If it went into the constant pool, String.valueOf(c1) == String.valueOf(c2) would be true." For example, `String.valueOf(c1).intern() == String.valueOf(c2).intern()` [*would* be true](https://ideone.com/zniGGM), because `intern()` puts it into the constant pool. – Andy Turner Jan 24 '19 at 09:35
  • 1
    And something tells me that `bo.getSubjectType()` should return an enum. Just saying. – Marco Jan 24 '19 at 09:39
  • @Andy Turner my assumption was like if we create a string using new operator like `String s1 = new String("T");` it will go into constant pool - Is that right or wrong? – Arun Sudhakaran Jan 24 '19 at 09:40
  • 1
    @ArunSudhakaran It's wrong. Only literals go into the constant pool automatically - so there will be a String with value `"T"` in the pool, because of the `"T"` parameter (and thus `new String("T")` is redundant over simply `"T"`). Otherwise, strings are only added when you invoke `intern()` - and you pretty much never need to use this. – Andy Turner Jan 24 '19 at 09:43
  • @ArunSudhakaran "Only literals" This isn't quite right actually - constant-valued expressions of string type are put in the pool. This includes literals, but also something like `"T" + 0`. – Andy Turner Jan 24 '19 at 09:48
  • 1
    I think that Andy deserves his answer to be accepted. – J-Alex Jan 25 '19 at 09:12

2 Answers2

5
if(String.valueOf('T').equalsIgnoreCase(bo.getSubjectType()))

There is no advantage whatsoever to writing it like this.

String.valueOf('T') will always return a new string, equal to "T", because the result of String.valueOf(char) (or any valueOf overload, for that matter) is not cached. There is no reason to keep on creating the same string over and over.

Plus, it's more verbose.

Just stick with method 1.

Andy Turner
  • 137,514
  • 11
  • 162
  • 243
2

Method 2 is hard-readable and has no improvements at all.

String created using new operator operator, it always creates a new object in heap memory. String created using String literal may return an existing object from the String pool, if it already exists.

It will not return a String from the pool and creates a String using new operator (Oracle JDK 10 source):

 /**
 * Returns the string representation of the {@code char}
 * argument.
 *
 * @param   c   a {@code char}.
 * @return  a string of length {@code 1} containing
 *          as its single character the argument {@code c}.
 */
public static String valueOf(char c) {
    if (COMPACT_STRINGS && StringLatin1.canEncode(c)) {
        return new String(StringLatin1.toBytes(c), LATIN1);
    }
    return new String(StringUTF16.toBytes(c), UTF16);
}

If you want to define a String constant and that always will be loaded from the pool, just create a:

public static final String T = "T";

From JLS about string literals and pools:

class Test {
   public static void main(String[] args) {
   String hello = "Hello", lo = "lo";
   System.out.print((hello == "Hello") + " ");
   System.out.print((Other.hello == hello) + " ");
   System.out.print((other.Other.hello == hello) + " ");
   System.out.print((hello == ("Hel"+"lo")) + " ");
   System.out.print((hello == ("Hel"+lo)) + " ");
   System.out.println(hello == ("Hel"+lo).intern());
 }
}
class Other { static String hello = "Hello"; }

and the compilation unit:

package other; 
public class Other { 
    public static String hello = "Hello"; 
}

produces the output:

true true true true false true

This example illustrates six points:

• Literal strings within the same class (§8 (Classes)) in the same package (§7 (Packages)) represent references to the same String object (§4.3.1).

• Literal strings within different classes in the same package represent references to the same String object.

• Literal strings within different classes in different packages likewise represent references to the same String object.

• Strings computed by constant expressions (§15.28) are computed at compile time and then treated as if they were literals.

• Strings computed by concatenation at run time are newly created and therefore distinct.

• The result of explicitly interning a computed string is the same string as any pre-existing literal string with the same contents.

Community
  • 1
  • 1
J-Alex
  • 6,881
  • 10
  • 46
  • 64