This approach to string handling is one of few things Java got just right. At least compared to mess that are numeric types.
Aside from threading, string manipulation is an annoying topic. Languages can do well to treat strings in this way.
An important thing to keep in mind here. Java strings are 'words'. They are not char *, collection of chars, an array of values - they are conceptual strings, a text, and should be treated as such.
As for performance - experience shows that in typical string processing, straight-forward approach using immutable strings and garbage collection is order of magnitude faster than C++ methods. Real world practice shows that string manipulations tend to discard data almost immediately after use in just about all cases.
Obviously, there is a whole class of in-place algorithms that can offer vastly superior performance, but they also introduce systematic flaws which hamper productivity and increase cost of development far beyond what is reasonable. Typical example is the require size of buffer. There are effectively no use cases left anymore where predetermined size will fit. Point in case: buffer overflows - still unsolved, still here.
In addition, string operations on immutable strings make all operations streaming in nature. Either use existing instance, or process left to right into new one. This makes copies cheap (but still more expensive than in-place).
C or C++ are blown clear out of water by managed languages when it comes to string handling. Adequately large application will, without any effort spent on optimization, outperform equivalent C or C++ application. This was shown long ago for, IIRC, Tex. Specialized mallocs and local allocation optimization as well as a lot of effort is needed to outperform it.
Another string handling concept that tends to creep up from time to time are
ropes. In practice however, these fall into same category as tries or binary insertion sort. Elegant, flexible, but with constant factor cost that makes them slower by a constant factor in just about any real world scenario.
Immutable types are very much in line with functional programming concepts, which is why learning a functional language is always beneficial.
For trivial cases, these differences are irrelevant, with exception of a few very specialized domains.
Edit: HashMap has special optimizations which benefit from immutability. When used with strings (or other immutable objects), it pays to reuse *same* instance for key. This results in lightning fast lookups, which may be counter-intuitive compared to map in C++. Other structures can benefit from this as well, there are also many optimizations hidden in standard library, and it could have something to do with intern() as well (it's been a while).
For extensive lookups, I even went as far as to use a helper set to hold unique instances loaded at runtime, since it offered such huge benefit.