Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How many String objects would be created when concatenating multiple Strings?

I was asked in an interview about the number of objects that will be created on the given problem:

String str1 = "First";
String str2 = "Second";
String str3 = "Third";
String str4 = str1 + str2 + str3;

I answered that there would be 6 objects created in the string pool.

3 would be for each of the three variables.
1 would be for str1 + str2 (let's say str).
1 would be for str2 + str3.
1 would be for the str + str3 (str = str1 + str2).

Is the answer I gave correct? If not, what is the correct answer?

like image 762
bhpsh Avatar asked Aug 23 '19 17:08

bhpsh


People also ask

How many objects can a string create?

The answer is: 2 String objects are created.

How can you concatenate multiple strings?

You concatenate strings by using the + operator. For string literals and string constants, concatenation occurs at compile time; no run-time concatenation occurs. For string variables, concatenation occurs only at run time.

How do you concatenate 3 strings in Python?

Concatenation means joining strings together end-to-end to create a new string. To concatenate strings, we use the + operator. Keep in mind that when we work with numbers, + will be an operator for addition, but when used with strings it is a joining operator.

Does concatenation create a new string?

Since the String object is immutable, each call for concatenation will result in a new String object being created.


Video Answer


3 Answers

Any answer to your question will depend on the JVM implementation and the Java version currently being used. I think it's an unreasonable question to ask in an interview.

Java 8

On my machine, with Java 1.8.0_201, your snippet results in this bytecode

L0
 LINENUMBER 13 L0
 LDC "First"
 ASTORE 1
L1
 LINENUMBER 14 L1
 LDC "Second"
 ASTORE 2
L2
 LINENUMBER 15 L2
 LDC "Third"
 ASTORE 3
L3
 LINENUMBER 16 L3
 NEW java/lang/StringBuilder
 DUP
 INVOKESPECIAL java/lang/StringBuilder.<init> ()V
 ALOAD 1
 INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
 ALOAD 2
 INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
 ALOAD 3
 INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
 INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;
 ASTORE 4

which proves that 5 objects are being created (3 String literals*, 1 StringBuilder, 1 dynamically produced String instance by StringBuilder#toString).

Java 12

On my machine, with Java 12.0.2, the bytecode is

// identical to the bytecode above
L3
 LINENUMBER 16 L3
 ALOAD 1
 ALOAD 2
 ALOAD 3
 INVOKEDYNAMIC makeConcatWithConstants(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; [
  // handle kind 0x6 : INVOKESTATIC
  java/lang/invoke/StringConcatFactory.makeConcatWithConstants(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;
  // arguments:
  "\u0001\u0001\u0001"
 ]
 ASTORE 4

which magically changes "the correct answer" to 4 objects since there is no intermediate StringBuilder involved.


*Let's dig a bit deeper.

12.5. Creation of New Class Instances

A new class instance may be implicitly created in the following situations:

  • Loading of a class or interface that contains a string literal (§3.10.5) may create a new String object to represent the literal. (This will not occur if a string denoting the same sequence of Unicode code points has previously been interned.)

In other words, when you start an application, there are already objects in the String pool. You barely know what they are and where they come from (unless you scan all loaded classes for all literals they contain).

The java.lang.String class will be undoubtedly loaded as an essential JVM class, meaning all its literals will be created and placed into the pool.

Let's take a randomly selected snippet from the source code of String, pick a couple of literals from it, put a breakpoint at the very beginning of our programme, and examine if the pool contains these literals.

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence,
               Constable, ConstantDesc {
    ...
    public String repeat(int count) {
        // ... 
        if (Integer.MAX_VALUE / count < len) {
            throw new OutOfMemoryError("Repeating " + len + " bytes String " + count +
                    " times will produce a String exceeding maximum size.");
        }
    }
    ...
}

They are there indeed.

As an interesting find, this IDEA's filtering has a side effect: the substrings I was looking for have been added to the pool as well. The pool size increased by one ("bytes String" was added) after I applied this.contains("bytes String").

Where does this leave us?

We have no idea whether "First" was created and interned before we call String str1 = "First";, so we can't state firmly that the line creates a new instance.

like image 100
Andrew Tobilko Avatar answered Oct 13 '22 17:10

Andrew Tobilko


With the given information, the question cannot be definitely answered. As is stated in the JLS, §15.18.1:

... To increase the performance of repeated string concatenation, a Java compiler may use the StringBuffer class or a similar technique to reduce the number of intermediate String objects that are created by evaluation of an expression.

This means that the answer depends at least on the concrete Java compiler used.

I think the best we can do is give an interval as answer:

  • a smart compiler may be able to infer that str1 to str3 are never used and fold the concatenation during compilation, such that only one String-object is created (the one referenced by str4)
  • The maximum sensible number of Strings created should be 5: one each for str1 to str3, one for tmp = str1 + str2 and one for str4 = tmp + str3.

So... my answer would be "something between one to five String-objects". As to the total number of objects created just for this operation... I do not know. This may also depend how exactly e.g. StringBuffer is implemented.

As an aside: I wonder what the reason behind asking such questions is. Normally, one does not need to care about those details.

like image 19
Turing85 Avatar answered Oct 13 '22 17:10

Turing85


Java 8 will likely create 5 objects:

  • 3 for the 3 literals
  • 1 StringBuilder
  • 1 for the concatenated String

With Java 9 things changed though and String concatenation does not use StringBuilder anymore.

like image 9
Puce Avatar answered Oct 13 '22 18:10

Puce