Cel wykorzystania StringBuilder, czyli redukcja pamięci. Czy to się udało?
Nie, wcale. Ten kod nie jest używany StringBuilder
poprawnie. (Myślę jednak, że źle to zacytowałeś; na pewno nie ma wokół cudzysłowu id2
i table
?)
Zauważ, że celem (zwykle) jest zmniejszenie utraty pamięci, a nie całkowitej ilości używanej pamięci, aby nieco ułatwić życie odśmiecaczowi pamięci.
Czy zajmie to pamięć równą użyciu String, jak poniżej?
Nie, spowoduje to więcej zmian w pamięci niż tylko proste konkatowanie, które zacytowałeś. (Dopóki / chyba że optymalizator JVM zobaczy, że jawny plikStringBuilder
w kodzie są niepotrzebne i zoptymalizuje je, jeśli to możliwe).
Jeśli autor tego kodu chce użyć StringBuilder
(są argumenty za, ale także przeciw; patrz uwaga na końcu tej odpowiedzi), lepiej zrobić to poprawnie (tutaj zakładam, że w rzeczywistości nie ma cudzysłowów id2
i table
):
StringBuilder sb = new StringBuilder(some_appropriate_size);
sb.append("select id1, ");
sb.append(id2);
sb.append(" from ");
sb.append(table);
return sb.toString();
Zauważ, że wymieniłem some_appropriate_size
w StringBuilder
konstruktorze, więc zaczyna się z wystarczającą pojemnością dla pełnej zawartości, którą zamierzamy dołączyć. Domyślny rozmiar używany, jeśli nie podasz żadnego, to 16 znaków , co jest zwykle zbyt małe i powoduje StringBuilder
konieczność dokonywania ponownych przydziałów, aby się powiększyć (IIRC, w Sun / Oracle JDK, podwaja się [lub więcej, jeśli wie, że potrzebuje więcej, aby zaspokoić określone potrzeby append
] za każdym razem, gdy zabraknie mu miejsca).
Być może słyszeliście, że ciąg konkatenacji będzie używać StringBuilder
pod kołdrą jeśli skompilowany z kompilatora Sun / Oracle. To prawda, użyje jednego StringBuilder
dla ogólnego wyrażenia. Ale użyje domyślnego konstruktora, co oznacza, że w większości przypadków będzie musiał dokonać ponownej alokacji. Ale jest łatwiejszy do odczytania. Zauważ, że nie dotyczy to serii konkatenacji. Na przykład ten używa jednego StringBuilder
:
return "prefix " + variable1 + " middle " + variable2 + " end";
To z grubsza przekłada się na:
StringBuilder tmp = new StringBuilder();
tmp.append("prefix ");
tmp.append(variable1);
tmp.append(" middle ");
tmp.append(variable2);
tmp.append(" end");
return tmp.toString();
Więc to jest w porządku, chociaż domyślny konstruktor i późniejsza realokacja nie są idealne, szanse są wystarczająco dobre - a konkatenacja jest o wiele bardziej czytelna.
Ale to tylko dla jednego wyrażenia. W StringBuilder
tym celu używa się wielu s:
String s;
s = "prefix ";
s += variable1;
s += " middle ";
s += variable2;
s += " end";
return s;
To kończy się czymś takim:
String s;
StringBuilder tmp;
s = "prefix ";
tmp = new StringBuilder();
tmp.append(s);
tmp.append(variable1);
s = tmp.toString();
tmp = new StringBuilder();
tmp.append(s);
tmp.append(" middle ");
s = tmp.toString();
tmp = new StringBuilder();
tmp.append(s);
tmp.append(variable2);
s = tmp.toString();
tmp = new StringBuilder();
tmp.append(s);
tmp.append(" end");
s = tmp.toString();
return s;
... co jest dość brzydkie.
Należy jednak pamiętać, że we wszystkich, z wyjątkiem nielicznych przypadków , nie ma to znaczenia i preferowana jest czytelność (która zwiększa łatwość konserwacji), poza konkretnym problemem z wydajnością.
PreparedStatement
lub czegoś podobnego: docs.oracle.com/javase/tutorial/jdbc/basics/prepared.html