5 ms·
> How about just using StringBuffer unless you really (that 0.01% case) need the performance of StringBuilder? Because when writing new code you should opt-in
by kodablah 10y ago
> How about just using StringBuffer unless you really (that 0.01% case) need the performance of StringBuilder?
Because when writing new code you should opt-in to thread safety, not out. Collections are not concurrent by default, there is no `unsynchronized` or `non-volatile` keywords, etc. StringBuilder:StringBuffer::HashMap:ConcurrentHashMap. Also, if the performance benefit requires negligible upfront cost (e.g. providing length to ArrayList if known) you should do it and build it in your muscle memory as the default approach.
The problem is StringBuffer (unlike many other parts of the stdlib) was the only approach available for a long time so people need to change their default way of thinking. Luckily it's been a long time since 1.5 and basically everyone has changed.
- Someone 10y agoI don't think thread-safety is a big concern for string building APIs. I expect 90% or more of all uses of StringBuffer are easily verified to be used from only one thread because they allocate an instance, assign it to a local variable, append to it a few times, and finally get the string that was built exactly once. Actually, I don't see why it would take a very smart compiler to do this kind of escape analysis and automatically and safely replace StringBuffer by StringBuilder where possible. The only large downside I can see of that is that it would require the compiler to know quite a bit of the semantics of the standard library. If you refactor your code and pass the StringBuffer to (small) helper functions, doing this would be more work, but it would not get essentially harder.
- hyperpape 10y agoYou're right about thread safety. And when you do want it, you probably want more guarantees than StringBuffer gives you (ability to synchronize multiple inserts, for instance). With regard to the sufficiently smart compiler: it seems like you'd need every method the StringBuffer is passed to be final to do that kind of analysis. In the case where you're writing: public void foo(List<String> strings) { StringBuffer x = new StringBuffer(); for (String s: strings) { x.append(s); } } You could conceivably do the analysis at compile time. But the whole idea behind the JIT is that you don't need to. If the code is hot, it'll get compiled, and you'll probably be fine thanks to removing all the synchronization, while if it's not hot no one cares.
- Someone 10y agoYou're right, I forgot that all methods are implicitly virtual by default in Java.
- vardump 10y agoNot quite same as "virtual" in C++ though. Java methods can still be inlined at runtime. I wish C++ had a runtime that could do same, inline smaller virtual methods, function pointers and shared library (.dll/.dylib/.so) calls at runtime. It could also do other transformations, like optimize those branches away it can prove to be always true or false. It could flatten most abstractions, removing redundant parameter checks and call frame setups/teardowns. It could also do CPU (instruction set) specific optimizations. I think C++ runtime that does this partial JITting is possible, but not easy. However, the benefits are interesting. While getting there won't be easy, you can achieve faster than native performance. Something like this has already been actually done. Some examples below. QuaC: http://digitalassets.lib.berkeley.edu/techreports/ucb/text/CSD-94-792.pdf http://digitalassets.lib.berkeley.edu/techreports/ucb/text/C... DynamoRio: DynamoRio had some early success JITting native binaries resulting faster than native performance. Unfortunately current versions are slower than native. https://github.com/DynamoRIO/dynamorio https://github.com/DynamoRIO/dynamorio). https://dspace.mit.edu/bitstream/handle/1721.1/87441/54863587-MIT.pdf?sequence=2 https://dspace.mit.edu/bitstream/handle/1721.1/87441/5486358...
- kbenson 10y agoAs a non-java programmer, I'm wondering why you would want to opt-in to a safety system instead of out of it? My instinct would be to say that you should be safe be default, and if you find you need performance, then you verify it won't cause problems in your case and opt out of the default safety mechanism. Why is defaulting to non-safe ever the right choice?
- kodablah 10y agoBecause of practicality. Think of it this way, "why would you want to opt-in to better performance instead of out of it?" The main reason behind sensible defaults is that they suit most for the best benefit. Whatever language you are familiar with, I can undoubtedly show you safer yet less convenient (and less frequently needed) ways to do things to which you could pose your same question.
- kbenson 10y ago> Think of it this way, "why would you want to opt-in to better performance instead of out of it?" Because it's unsafe some portion of the time? I don't think it's controversial to say safety should be the default, unless it imposes undue constraints. We have plenty of experience with the alternative. See C. > The main reason behind sensible defaults is that they suit most for the best benefit. Are we not talking about some small percentage of performance loss in string concatenation in exchange for a program that doesn't crash in the case it's used in a particular manner with threads? Am I misunderstanding this? > Whatever language you are familiar with, I can undoubtedly show you safer yet less convenient (and less frequently needed) ways to do things to which you could pose your same question. Yes. And when you point out where the same API exists for two constructs with different names, that achieve the same end, with small performance differences between them, and one is safe and one can possible cause the program to crash in some edge cases, I will side with the safer way as a default. It's not like we as an industry or hobby need help writing buggy software. We've accomplished that just fine for decades.
- kodablah 10y ago