Czytałem o tym, jak w miarę możliwości kompilator java będzie kompilował ciągi połączone z operatorem "+" w instancje StringBuilder, i jak to czyni lepiej korzystać z prostego operatora "+", ponieważ są one compile to the same code. (Z wyjątkiem sytuacji, gdy budujesz ciąg w pętli while, w tym przypadku najlepiej jest użyć StringBuilder.)StringBuilder vs. .concat vs. "+" Różni się względna wydajność operatora w zaćmieniu niż w linii poleceń?
Przeczytałem również, że metoda .concat w łańcuchach jest najgorsza choice all the time (tak bardzo że został zrobiony w błąd przez Findbugs!).
Postanowiłem przetestować to sam, pisząc małą klasę Java w czasie zaćmienia. Moje wyniki zaskoczyły mnie nieco. Odkryłem, że różne metody były względnie szybsze lub wolniejsze, jeśli zastosowałem je i uruchomiłem w zaćmieniu, a nie w linii poleceń.
Pierwsze moje wyniki były eclipse:
the total millis to concatenate with + was: 12154
the total millis to concatenate with .concat was: 8840
the total millis to concatenate with StringBuilder was: 11350
the total millis to concatenate with StringBuilder with a specified size was: 5611
Więc w Eclipse StringBuilder z wielkością określoną był najszybszy, a następnie .concat (dziwne), a następnie StringBuilder i "+" konkatenacji były prawie takie same.
Moje wyniki w wierszu poleceń, jednak były:
the total millis to concatenate with + was: 4139
the total millis to concatenate with .concat was: 8590
the total millis to concatenate with StringBuilder was: 10888
the total millis to concatenate with StringBuilder with a specified size was: 6033
Więc kiedy skompilowane i wybiegł z commnad linii operator „+” był wyraźnie najszybszy, a następnie przez konstruktora String z rozmiaru, a następnie concat, a ostatnio był normalny StringBuilder!
To nie ma dla mnie sensu. Oczywiście wszystkie odpowiedzi na stackoverflow czytałem mówiąc, że operatory + kompilacji do normalnych starych instancji StringBuilder muszą być nieaktualne.
Czy ktoś wie, co się tutaj naprawdę dzieje?
Używam jdk1.7.0_07, i o ile mogę powiedzieć zarówno zaćmienie i mojej linii poleceń odnoszą się dokładnie do tego samego. Jedyną różnicą, jaką znam, jest to, że Eclipse używa "javaw", ale z tego, co przeczytałem, nie powinno to mieć znaczenia.
Oto moja klasa testowa, jeśli chcesz sprawdzić, czy nie robię niczego złego, ale jestem prawie pewien, że jest solidny.
public class Test {
static final int LOOPS = 100000000;
static final String FIRST_STRING = "This is such";
static final String SECOND_STRING = " an awesomely cool ";
static final String THIRD_STRING = "to write string.";
/**
* @param args
*/
public static void main(String[] args) {
Test.plusOperator();
Test.dotConcat();
Test.stringBuilder();
Test.stringBuilderSizeSpecified();
}
public static void plusOperator() {
String localOne = FIRST_STRING;
String localTwo = SECOND_STRING;
String localThree = THIRD_STRING;
Calendar startTime = Calendar.getInstance();
for (int x = 0; x < LOOPS; x++) {
String toPrint = localOne + localTwo + localThree;
}
Calendar endTime = Calendar.getInstance();
System.out.println("the total millis to concatenate with + was: " +
(endTime.getTimeInMillis() - startTime.getTimeInMillis()));
}
public static void stringBuilder() {
String localOne = FIRST_STRING;
String localTwo = SECOND_STRING;
String localThree = THIRD_STRING;
Calendar startTime = Calendar.getInstance();
for (int x = 0; x < LOOPS; x++) {
StringBuilder toBuild = new StringBuilder()
.append(localOne)
.append(localTwo)
.append(localThree);
}
Calendar endTime = Calendar.getInstance();
System.out.println("the total millis to concatenate with StringBuilder was: " +
(endTime.getTimeInMillis() - startTime.getTimeInMillis()));
}
public static void stringBuilderSizeSpecified() {
String localOne = FIRST_STRING;
String localTwo = SECOND_STRING;
String localThree = THIRD_STRING;
Calendar startTime = Calendar.getInstance();
for (int x = 0; x < LOOPS; x++) {
StringBuilder toBuild = new StringBuilder(50)
.append(localOne)
.append(localTwo)
.append(localThree);
}
Calendar endTime = Calendar.getInstance();
System.out.println("the total millis to concatenate with StringBuilder with a specified size was: " +
(endTime.getTimeInMillis() - startTime.getTimeInMillis()));
}
public static void dotConcat() {
String localOne = FIRST_STRING;
String localTwo = SECOND_STRING;
String localThree = THIRD_STRING;
Calendar startTime = Calendar.getInstance();
for (int x = 0; x < LOOPS; x++) {
String toPrint = localOne.concat(localTwo).concat(localThree);
}
Calendar endTime = Calendar.getInstance();
System.out.println("the total millis to concatenate with .concat was: " +
(endTime.getTimeInMillis() - startTime.getTimeInMillis()));
}
}
Przydałoby się poznać szczegóły używanej maszyny JVM. –
Twoja metodologia testów porównawczych jest wyjątkowo podejrzana. Nie pozwala to na rozgrzanie się JIT; używa 'Calendar' zamiast wyznaczonej różnicy czasu bezwzględnego' System.nanoTime() '... –
Uruchomiłem to wiele razy różnymi metodami wywoływanymi w różnych zamówieniach. Może to zrobić około 100 milisekund, ale mówimy tu o tysiącach różnicy milisekund, więc nie widzę, aby różnica między System.nanoTime() lub JIT rozgrzewała się. – CorayThan