Generally, I understand/agree with using a const String&, but because you are passing const String&, the StringRef or CharPointerType provide all of the const methods you need (length & ).
Also, I did preface this saying certain scenarios need this. The case that I have run into in JUCE and my previous platform is trying to push lots of numeric data into a Table at very high frame rates. The first optimization is to remove the component structure of the table (build a native data grid), which is the big hitter, but as you dig deeper, the constant allocations become an issue at high rates. Again, this is a very specific use case, and what you have done is excellent, and I am in no way saying something is wrong, just looking at incremental improvements.
Another option I have played with is re-doing JUCE String to use a different implementation more like the std::string implementation. With a SSO (small string optimization) in place, there are no allocations for these small strings since they can sit on the stack. I have had issues getting this in place though, as I am still learning parts of JUCE where the changes propagate to (removing ref count ripples around). The unit tests are helping though.