Aku hanya menemukan beberapa query sql membangun seperti ini di proyek saya:
return (new StringBuilder("select id1, " + " id2 " + " from " + " table")).toString();
Apakah ini StringBuilder
mencapai tujuannya, saya.e mengurangi penggunaan memori?
Saya meragukan itu, karena di konstruktor '+' (String concat operator) digunakan. Itu akan mengambil jumlah yang sama dari memori menggunakan String seperti kode di bawah ini? s saya mengerti, hal itu berbeda ketika menggunakan StringBuilder.append()
.
return "select id1, " + " id2 " + " from " + " table";
Apakah kedua pernyataan sama dalam penggunaan memori atau tidak? Segera mengklarifikasi.
Terima kasih sebelumnya!
Edit:
BTW, hal ini tidak saya kode. Ditemukan dalam sebuah proyek lama. Juga, permintaan ini tidak begitu kecil sebagai salah satu dalam contoh saya. :)
tujuan menggunakan StringBuilder, saya.e mengurangi memori. Itu dicapai?
Tidak, tidak sama sekali. Kode yang tidak menggunakan StringBuilder
dengan benar. (Saya pikir anda've salah kutip itu, meskipun sesungguhnya tidak ada't tanda kutip id2
dan meja
?)
Perhatikan bahwa tujuan (biasanya) adalah untuk mengurangi memori churn daripada jumlah memori yang digunakan, untuk membuat hidup sedikit lebih mudah pada garbage collector.
yang Akan mengambil memori yang sama untuk menggunakan String seperti di bawah ini?
Tidak, itu'll menyebabkan lebih memori churn dari sekedar lurus concat anda kutip. (Sampai/kecuali JVM optimizer melihat bahwa eksplisit StringBuilder
dalam kode yang tidak perlu dan mengoptimalkan itu, jika itu bisa.)
Jika penulis kode yang ingin menggunakan StringBuilder
(ada argumen, tetapi juga terhadap; lihat catatan di akhir jawaban ini), lebih baik untuk melakukannya dengan benar (di sini saya'm dengan asumsi tidak ada't benar-benar tanda kutip id2
dan meja
):
StringBuilder sb = new StringBuilder(some_appropriate_size);
sb.append("select id1, ");
sb.append(id2);
sb.append(" from ");
sb.append(table);
return sb.toString();
Perhatikan bahwa I've terdaftar some_appropriate_size
di StringBuilder
konstruktor, sehingga dimulai dengan kapasitas yang cukup untuk isi penuh kita're akan menambahkan. Ukuran default digunakan jika anda don't menentukan satu ini 16 karakter, yang biasanya terlalu kecil dan hasil yang di StringBuilder
harus melakukan realokasi untuk membuat dirinya lebih besar (IIRC, di Sun/Oracle JDK, menggandakan dirinya sendiri [atau lebih, jika ia tahu hal itu membutuhkan lebih banyak untuk keluarga tertentu menambahkan
] setiap kali berjalan keluar dari kamar).
Anda mungkin pernah mendengar bahwa rangkaian string akan menggunakan StringBuilder
di bawah selimut jika disusun dengan Sun/Oracle compiler. Ini benar, itu akan menggunakan salah satu StringBuilder
untuk keseluruhan ekspresi. Tapi itu akan menggunakan default constructor, yang berarti dalam sebagian besar kasus, itu akan harus melakukan realokasi. It's mudah untuk membaca, meskipun. Catatan bahwa ini adalah tidak benar seri dari penggabungan. Jadi misalnya, ini menggunakan satu StringBuilder
:
return "prefix " + variable1 + " middle " + variable2 + " end";
Itu kira-kira berarti:
StringBuilder tmp = new StringBuilder(); // Using default 16 character size
tmp.append("prefix ");
tmp.append(variable1);
tmp.append(" middle ");
tmp.append(variable2);
tmp.append(" end");
return tmp.toString();
Sehingga's baik-baik saja, meskipun default constructor dan selanjutnya realokasi(s) isn't ideal, kemungkinan itu's cukup baik — dan rangkaian adalah banyak lebih mudah dibaca.
Tapi yang's hanya untuk satu ekspresi. Beberapa `StringBuilder ini digunakan untuk ini:
String s;
s = "prefix ";
s += variable1;
s += " middle ";
s += variable2;
s += " end";
return s;
Itu berakhir menjadi sesuatu seperti ini:
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;
...yang cukup jelek.
It's penting untuk diingat, meskipun, bahwa dalam semua tapi sangat sedikit kasus itu doesn't peduli dan akan dengan mudah dibaca (yang meningkatkan pemeliharaan) lebih disukai pembatasan tertentu masalah kinerja.
Ketika anda sudah memiliki semua "buah" anda ingin menambahkan, tidak ada gunanya menggunakan StringBuilder
sama sekali. Menggunakan StringBuilder
dan rangkaian string dalam panggilan yang sama seperti per sampel kode ini bahkan lebih buruk.
Ini akan menjadi lebih baik:
return "select id1, " + " id2 " + " from " + " table";
Dalam hal ini, rangkaian string yang sebenarnya terjadi di waktu compile anyway, jadi itu's setara bahkan lebih sederhana:
return "select id1, id2 from table";
Menggunakan new StringBuilder().append("select id1, ").append(" id2 ")....toString()
akan benar-benar menghambat kinerja dalam hal ini, karena itu pasukan gabungan yang akan dilakukan di waktu pelaksanaan, bukan di compile waktu. Oops.
Jika kode yang sebenarnya adalah membangun sebuah query SQL dengan memasukkan nilai * dalam query, maka yang's lain terpisah* masalah, yang adalah bahwa anda harus menggunakan parameter kueri, menentukan nilai-nilai dalam parameter daripada di SQL.
Saya memiliki sebuah artikel tentang String
/ StringBuffer
yang saya tulis beberapa saat yang lalu - sebelum StringBuilder
datang. Prinsip-prinsip ini diterapkan untuk StringBuilder
dengan cara yang sama sekalipun.
[[ Ada beberapa jawaban yang baik di sini, tetapi saya menemukan bahwa mereka masih kurang sedikit informasi. ]]
return (new StringBuilder("select id1, " + " id2 " + " from " + " table"))
.toString();
Jadi seperti yang anda tunjukkan, contoh yang anda berikan adalah sederhana tapi let's menganalisis itu pula. Apa yang terjadi di sini adalah compiler benar-benar tidak +
bekerja di sini karena "pilih id1, " + " id2 " + " dari " + " table"
semua konstanta. Jadi ini berubah menjadi:
return new StringBuilder("select id1, id2 from table").toString();
Dalam hal ini, jelas, tidak ada gunanya menggunakan StringBuilder
. Anda mungkin juga melakukan:
// the compiler combines these constant strings
return "select id1, " + " id2 " + " from " + " table";
Namun, bahkan jika anda menambahkan setiap bidang atau non-konstanta maka compiler akan menggunakan internal StringBuilder
- ada's tidak perlu bagi anda untuk menentukan satu:
// an internal StringBuilder is used here
return "select id1, " + fieldName + " from " + tableName;
Di bawah selimut, ini berubah menjadi kode yang kira-kira setara dengan:
StringBuilder sb = new StringBuilder("select id1, ");
sb.append(fieldName).append(" from ").append(tableName);
return sb.toString();
Benar-benar satu-satunya waktu yang anda butuhkan untuk menggunakan StringBuilder
directly adalah ketika anda memiliki kode kondisional. Sebagai contoh, kode yang terlihat seperti berikut ini putus asa untuk StringBuilder
:
// 1 StringBuilder used in this line
String query = "select id1, " + fieldName + " from " + tableName;
if (where != null) {
// another StringBuilder used here
query += ' ' + where;
}
The +
di baris pertama menggunakan satu StringBuilder
misalnya. Maka +=
menggunakan StringBuilder
misalnya. Hal ini lebih efisien untuk melakukan:
// choose a good starting size to lower chances of reallocation
StringBuilder sb = new StringBuilder(64);
sb.append("select id1, ").append(fieldName).append(" from ").append(tableName);
// conditional code
if (where != null) {
sb.append(' ').append(where);
}
return sb.toString();
Lain kali saya menggunakan StringBuilder
adalah ketika saya'm bangunan string dari sejumlah metode panggilan. Maka saya dapat membuat metode yang mengambil StringBuilder
argumen:
private void addWhere(StringBuilder sb) {
if (where != null) {
sb.append(' ').append(where);
}
}
Ketika anda menggunakan StringBuilder
, anda harus menonton untuk setiap penggunaan +
pada waktu yang sama:
sb.append("select " + fieldName);
Bahwa +
akan menyebabkan internal yang lain StringBuilder
yang akan dibuat. Ini tentunya harus menjadi:
sb.append("select ").append(fieldName);
Terakhir, sebagai @T. J. rowder poin, anda harus selalu membuat menebak ukuran StringBuilder
. Ini akan menghemat jumlah char[]
benda-benda yang diciptakan ketika tumbuh ukuran buffer internal.
Kamu benar dalam menebak bahwa tujuan menggunakan string pembangun tidak tercapai, setidaknya tidak sampai batas penuh.
Namun, ketika compiler melihat ekspresi "pilih id1, " + " id2 " + " dari " + " table"
ia memancarkan kode yang benar-benar menciptakan StringBuilder
di balik layar dan menambahkan untuk itu, agar hasil akhirnya tidak terlalu buruk afterall.
Tapi tentu saja ada yang melihat bahwa kode terikat untuk berpikir bahwa itu adalah jenis terbelakang.
Dalam kode anda telah diposting di sana akan ada keuntungan, seperti anda menyalahgunakan StringBuilder. Anda membangun String yang sama dalam kedua kasus. Menggunakan StringBuilder anda dapat menghindari +
operasi pada String menggunakan menambahkan
metode.
Anda harus menggunakan cara ini:
return new StringBuilder("select id1, ").append(" id2 ").append(" from ").append(" table").toString();
Di Jawa, tipe String adalah sebuah inmutable urutan karakter, sehingga ketika anda menambahkan dua String VM menciptakan nilai String baru dengan kedua operan yang disambung.
StringBuilder menyediakan mutable urutan karakter yang dapat anda gunakan untuk concat nilai-nilai yang berbeda atau variabel tanpa membuat objek String baru, dan kadang-kadang bisa lebih efisien daripada bekerja dengan string
Ini menyediakan beberapa fitur yang berguna, seperti mengubah isi dari char urutan dilewatkan sebagai parameter dalam metode lain, yang dapat anda't dilakukan dengan String.
private void addWhereClause(StringBuilder sql, String column, String value) {
//WARNING: only as an example, never append directly a value to a SQL String, or you'll be exposed to SQL Injection
sql.append(" where ").append(column).append(" = ").append(value);
}
Info lebih lanjut di http://docs.oracle.com/javase/tutorial/java/data/buffers.html