And "all" of this would be solved by having a proper way of doing array slicing - for things like substring's previous worst case (something like a single character being referenced in a substring holding up a gigabyte+-sized string) Java's garbage collector could recognize that the array was only referenced through slices of part of the array, copy that section into another array (updating references to it), and free the large one.
Also, Java's lack of a way to specify that a class is immutable (and that all children classes thereof must also be) is frustrating. Because optimizations like this can and should apply to more than just strings!