Performance and simplicity tradeoffs between String, StringBuffer, and StringBuilder

后端 未结 5 847
灰色年华
灰色年华 2021-02-09 17:29

Have you ever thought about the implications of this change in the Java Programming Language?

The String class was conceived as an immutable class (and this decision was

5条回答
  •  走了就别回头了
    2021-02-09 17:58

    Nowadays both StringBuffer and Builder are sort of useless (from performance point of view). I explain why:

    StringBuilder was supposed to be faster than StringBuffer but any sane JVM can optimize away the synchronization. So it was quite a huge miss (and small hit) when it was introduced.

    StringBuffer used NOT to copy the char[] when creating the String (in non shared variant); however that was a major source of issues, incl leaking huge char[] for small Strings. In 1.5 they decided that a copy of the char[] must occur every time and that practically made StringBuffer useless (the sync was there to ensure no thread games can trick out the String). That conserves memory, though and ultimately helps the GC (beside the obviously reduced footprint), usually the char[] is the top3 of the objects consuming memory.

    String.concat was and still is the fastest way to concatenate 2 strings (and 2 only... or possibly 3). Keep that in mind, it does not perform an extra copy of the char[].

    Back to the useless part, now any 3rd party code can achieve the same performance as StringBuilder. Even in java1.1 I used to have a class name AsycnStringBuffer which did exactly the same what StringBuilder does now, but still it allocates larger char[] than StringBuilder. Both StrinBuffer/StringBuilder are optimized for small Strings by default you can see the c-tor

      StringBuilder(String str) {
        super(str.length() + 16);
        append(str);
        }
    

    Thus if the 2nd string is longer than 16chars, it gets another copy of the underlying char[]. Pretty uncool.

    That can be a side effect of attempt at fitting both StringBuilder/Buffer and the char[] into the same cache line (on x86) on 32bit OS... but I don't know for sure.

    As for the remark of hours of debugging, etc. Use your judgment, I personally do not recall ever having any issues w/ strings operations, aside impl. rope alike structure for the sql generator of JDO impl.


    Edit: Below I illustrate what java designers didn't do to make String operations faster. Please, note that the class is intended for java.lang package and it can put there only by adding it to the bootstrap classpath. However, even if not put there (the difference is a single line of code!), it'd be still faster than StringBuilder, shocking? The class would have made string1+string2+... a lot better than using StringBuilder, but well...

    package java.lang;
    
    public class FastConcat {
    
        public static String concat(String s1, String s2){
            s1=String.valueOf(s1);//null checks
            s2=String.valueOf(s2);
    
            return s1.concat(s2);
        }
    
        public static String concat(String s1, String s2, String s3){
            s1=String.valueOf(s1);//null checks
            s2=String.valueOf(s2);
            s3=String.valueOf(s3);
            int len = s1.length()+s2.length()+s3.length();
            char[] c = new char[len];
            int idx=0;
            idx = copy(s1, c, idx);
            idx = copy(s2, c, idx);
            idx = copy(s3, c, idx);
            return newString(c);
        }
        public static String concat(String s1, String s2, String s3, String s4){
            s1=String.valueOf(s1);//null checks
            s2=String.valueOf(s2);
            s3=String.valueOf(s3);
            s4=String.valueOf(s4);
    
            int len = s1.length()+s2.length()+s3.length()+s4.length();
            char[] c = new char[len];
            int idx=0;
            idx = copy(s1, c, idx);
            idx = copy(s2, c, idx);
            idx = copy(s3, c, idx);
            idx = copy(s4, c, idx);
            return newString(c);
    
        }
        private static int copy(String s, char[] c, int idx){
            s.getChars(c, idx);
            return idx+s.length();
    
        }
        private static String newString(char[] c){
            return new String(0, c.length, c);
            //return String.copyValueOf(c);//if not in java.lang
        }
    }
    

提交回复
热议问题