StringBuilder unexpected result

Sergej Smoljanov

Ranch Hand

Posts: 467

10

posted 2 years ago

1

i expect after metod (line 15) insert result of StringBuilder object is "thethe system!the system! system!the system!"
but result "thethethethethethethethet system!the system!"
if i change code to this
all work as expected.
and
i get expected result. What is problem with first code?
how did metod insert() work in first list of code?

You pass the same mutable instance of StringBuilder to the insert-method. So while the insert-method is executed, the content of the StringBuilder (and thus what you are trying to insert) changes during the exection of the insert-method, because both (the object you invoked the method and the 2nd parameter of the insert-method) refer to the same object. If you change the 2nd parameter of the insert-method to another object (e.g. a String, like in your 2nd code listing or another StringBuilder like in this code listing) you have the expected result.

When you zoom in to the actual problem, you can start with this example:

Values for offset followed by what's printed

0 or 3: abcabc

1: aaaabc

2: ababac

If you really want going to the bone, it's this method you have to take a close look to:

The line marked with #1 is the one responsible for what you see. But bottom line of this story: you invoke the method on the object that you are also passing as a parameter. And that gives the not so expected (strange) behavior.

I have to say that I found that surprising too. Here's my simplest version of your code:

So I looked at the relevant API documentation, which turned out to be the method public StringBuilder insert(int dstOffset, CharSequence s, int start, int end). Since both StringBuilder and String implement CharSequence, this should describe what happens for both types of object. So what makes them different? The documentation describes very carefully how it works:

The character at index k in this sequence becomes equal to:

the character at index k in this sequence, if k is less than dstOffset
the character at index k+start-dstOffset in the argument s, if k is greater than or equal to dstOffset but is less than dstOffset+end-start
the character at index k-(end-start) in this sequence, if k is greater than or equal to dstOffset+end-start

So the first three characters in the result are "123" according to the first of those three rules. Then the second rule kicks in and starts inserting characters. The first three are copied from the CharSequence and they are "123" in both cases. The fourth is also copied from the CharSequence but here's where the difference arises. When you're inserting the StringBuilder, that character is copied from the fourth character of the StringBuilder, which is now "1" because we just inserted "1" into the fourth position. Whereas when you're inserting the String copied from the StringBuilder, that character is copied from the fourth character of the String, which is still "4".

Therefore, what you're seeing is strange but correct, according to a close reading of the documentation. At least in my opinion it is.