public class StringTest {

    public StringTest(){ }

    private boolean gc = true;

    private static final int trials = 26;
    private static final int runs = 10000;
    private static final int warmup = 100000;

    private String a = "a";
    private String b = "b";
    private String c = "c";

    public long runStringBuilderAppend(){
        long start = System.currentTimeMillis();
        try {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < runs; i++){
                sb.append(a).append(b).append(c);
            }
            sb.toString();
            sb = null;
        } finally {
            if (gc) System.gc();
            return (System.currentTimeMillis() - start); 
        }
    }

    public long runMStringAppend(){
        long start = System.currentTimeMillis();
        try {
            MString sb = new MString();
            for (int i = 0; i < runs; i++){
                sb.append(a,b,c);
            }
            sb.toString();
            sb = null;
        } finally {
            if (gc) System.gc();
            return (System.currentTimeMillis() - start); 
        }
    }

    public long runStringBuilderPlus(){
        long start = System.currentTimeMillis();
        try {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < runs; i++){
                sb.append(a + b + c);
            }
            sb.toString();
            sb = null;
        } finally {
            if (gc) System.gc();
            return (System.currentTimeMillis() - start); 
        }
    }

    public long runStringBuilderPlusPlus(){
        long start = System.currentTimeMillis();
        try {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < runs; i++){
                sb.append(new StringBuilder().append(a).append(b).append(c).toString());
            }
            sb.toString();
            sb = null;
        } finally {
            if (gc) System.gc();
            return (System.currentTimeMillis() - start);
        }
    }

    public long runStringBuilderPlusCTC(){
        long start = System.currentTimeMillis();
        try {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < runs; i++){
                sb.append("a" + "b" + "c");
            }
            sb.toString();
            sb = null;
        } finally {
            if (gc) System.gc();
            return (System.currentTimeMillis() - start); 
        }
    }

    public long runStringPlus(){
        long start = System.currentTimeMillis();
        try {
            String s = "";
            for (int i = 0; i < runs; i++){
                s += a + b + c;
            }
            s = null;
        } finally {
            if (gc) System.gc();
            return (System.currentTimeMillis() - start); 
        }
    }

    public long runStringPlusWithStringBuilder(){
        long start = System.currentTimeMillis();
        try {
            String s = "";
            for (int i = 0; i < runs; i++){
                s += new StringBuilder().append(a).append(b).append(c).toString();
            }
            s = null;
        } finally {
            if (gc) System.gc();
            return (System.currentTimeMillis() - start);
        }
    }

    public long runStringPlusCTC(){
        long start = System.currentTimeMillis();
        try {
            String s = "";
            for (int i = 0; i < runs; i++){
                s += "a" + "b" + "c";
            }
            s = null;
        } finally {
            if (gc) System.gc();
            return (System.currentTimeMillis() - start); 
        }
    }

    public static void main(String[] s){
        StringTest st = new StringTest();
        System.gc();

        System.out.println("string plus\tstring CTC\tstring plus w/ sb\tstr bld +\tstr bld ++\tstr bld + CTC\tstr bld app\tMString append"); 
        for (int i = 0 ; i < trials; i++){
            System.out.println(
                st.runStringPlus() +"\t"+
                st.runStringPlusCTC() +"\t"+
                st.runStringPlusWithStringBuilder() + "\t" +
                st.runStringBuilderPlus() +"\t"+
                st.runStringBuilderPlusPlus() +"\t"+
                st.runStringBuilderPlusCTC() +"\t"+
                st.runStringBuilderAppend() + "\t" +
                st.runMStringAppend());
        }
    }

    class MString {

        private StringBuilder builder = new StringBuilder();

        public MString append(String s){
            builder.append(s);
            return this;
        }

        public MString append(String... strs) {
            for (String s : strs){
                append(s);
            }
            return this;
        }

        public MString appendLine(String... strs) {
            append(strs);
            return append("\n");
        }

        public String toString() {
            return builder.toString();
        }
    }
}
