Selama pekerjaan saya dengan database, saya perhatikan bahwa saya menulis string kueri dan dalam string ini saya harus meletakkan beberapa batasan di klausa di mana dari daftar / larik / koleksi. Akan terlihat seperti ini:
select * from customer
where customer.id in (34, 26, ..., 2);
Anda dapat menyederhanakan ini dengan menguranginya menjadi pertanyaan bahwa Anda memiliki kumpulan string dan ingin membuat daftar string ini dengan dipisahkan koma hanya dalam satu string.
Pendekatan yang saya gunakan sejauh ini adalah seperti itu:
String result = "";
boolean first = true;
for(String string : collectionOfStrings) {
if(first) {
result+=string;
first=false;
} else {
result+=","+string;
}
}
Tapi ini seperti yang bisa Anda lihat sangat jelek. Anda tidak dapat melihat apa yang terjadi di sana pada tampilan pertama, terutama ketika string yang dibangun (seperti setiap kueri SQL) menjadi semakin rumit.
Apa cara Anda (yang lebih) elegan?
Jawaban:
Catatan: Jawaban ini bagus saat ditulis 11 tahun yang lalu, tetapi sekarang ada opsi yang jauh lebih baik untuk melakukannya dengan lebih rapi dalam satu baris, baik hanya menggunakan kelas bawaan Java atau menggunakan pustaka utilitas. Lihat jawaban lain di bawah.
Karena string tidak dapat diubah, Anda mungkin ingin menggunakan kelas StringBuilder jika Anda akan mengubah String dalam kode.
Kelas StringBuilder dapat dilihat sebagai objek String yang bisa berubah yang mengalokasikan lebih banyak memori saat kontennya diubah.
Saran asli dalam pertanyaan dapat ditulis dengan lebih jelas dan efisien, dengan menggunakan tanda koma yang berlebihan :
sumber
Gunakan Google Jambu API 's
join
metode:sumber
Joiner
; google-collections.googlecode.com/svn/trunk/javadoc/com/google/…Saya baru saja melihat kode yang melakukan ini hari ini. Ini adalah variasi dari jawaban AviewAnew.
The StringUtils (<- 2.x commons.lang, atau link yang 3.x commons.lang ) kita digunakan adalah dari Apache Commons .
sumber
Cara saya menulis loop itu adalah:
Jangan khawatir tentang kinerja sep. Tugas sangat cepat. Hotspot cenderung mengelupas iterasi pertama dari sebuah loop (karena sering kali harus berurusan dengan keanehan seperti pemeriksaan sebaris null dan mono / bimorfik).
Jika Anda menggunakannya banyak (lebih dari sekali), masukkan ke dalam metode bersama.
Ada pertanyaan lain tentang stackoverflow yang berhubungan dengan cara memasukkan daftar id ke dalam pernyataan SQL.
sumber
Sejak Java 8, Anda dapat menggunakan:
String String.join(CharSequence delimiter, CharSequence... elements)
String String.join(CharSequence delimiter, Iterable<? extends CharSequence> elements)
Jika Anda ingin mengambil non-
String
s dan menggabungkannya ke aString
, Anda dapat menggunakanCollectors.joining(CharSequence delimiter)
, misalnya:String joined = anyCollection.stream().map(Object::toString).collect(Collectors.joining(","));
sumber
cats.stream().map(cat -> cat.getName()).collect(Collectors.joining(","));
untuk variabel tunggal dari koleksi Anda.stream
. Untuk int [] atau long [] atau array lain di mana nilainya dapat dengan mudah ditransmisikanString
, saya akan mencari solusi non-streaming. Sebenarnya saya sedang mencari.Saya menemukan idiom iterator elegan, karena memiliki tes untuk lebih banyak elemen (tes kosong / kosong dihilangkan untuk singkatnya):
sumber
Ada banyak solusi manual untuk ini, tetapi saya ingin mengulangi dan memperbarui jawaban Julie di atas. Gunakan koleksi google Joiner class .
Ini menangani var args, iterable dan array dan dengan benar menangani pemisah lebih dari satu karakter (tidak seperti jawaban gimmel). Ini juga akan menangani nilai null dalam daftar Anda jika Anda membutuhkannya.
sumber
Ini adalah versi yang sangat umum yang saya buat dari kombinasi saran sebelumnya:
sumber
tersedia di api Java8.
alternatif untuk (tanpa perlu menambahkan ketergantungan google guava):
sumber
Kamu bisa mencoba
sumber
Ini akan menjadi solusi terpendek sejauh ini, kecuali menggunakan Guava atau Apache Commons
Baik dengan daftar elemen 0,1 dan n. Tetapi Anda harus memeriksa daftar null. Saya menggunakan ini di GWT, jadi saya baik-baik saja tanpa StringBuilder di sana. Dan untuk daftar pendek dengan hanya beberapa elemen tidak apa-apa juga di tempat lain;)
sumber
Jika seseorang tersandung ini di waktu yang lebih baru, saya telah menambahkan variasi sederhana menggunakan Java 8
reduce()
. Ini juga mencakup beberapa solusi yang telah disebutkan oleh orang lain:sumber
Di Android Anda harus menggunakan ini:
sumber
Saya pikir itu bukan ide yang baik mengkontruksi sql yang menggabungkan nilai klausa di mana seperti yang Anda lakukan:
Dimana
valueX
berasal dari daftar String.Pertama, jika Anda membandingkan String, mereka harus dikutip, dan ini tidak sepele jika String dapat memiliki kutipan di dalamnya.
Kedua, jika nilai berasal dari pengguna, atau sistem lain, maka serangan injeksi SQL dimungkinkan.
Ini jauh lebih bertele-tele tetapi yang harus Anda lakukan adalah membuat String seperti ini:
dan kemudian mengikat variabel dengan
Statement.setString(nParameter,parameterValue)
.sumber
Hanya metode lain untuk mengatasi masalah ini. Bukan yang paling singkat, tetapi efisien dan menyelesaikan pekerjaan.
sumber
Ada beberapa pustaka Java pihak ketiga yang menyediakan metode penggabungan string, tetapi Anda mungkin tidak ingin mulai menggunakan pustaka hanya untuk sesuatu yang sederhana seperti itu. Saya hanya akan membuat metode pembantu seperti ini, yang menurut saya sedikit lebih baik daripada versi Anda, Ini menggunakan StringBuffer, yang akan lebih efisien jika Anda perlu menggabungkan banyak string, dan berfungsi pada koleksi jenis apa pun.
Saran lain dengan menggunakan Collection.toString () lebih pendek, tetapi itu bergantung pada Collection.toString () yang mengembalikan string dalam format yang sangat spesifik, yang secara pribadi tidak ingin saya andalkan.
sumber
Jika Anda menggunakan Spring, Anda dapat melakukan:
(paket org.springframework.util)
sumber
Saya tidak yakin seberapa "canggih" ini, tapi pasti sedikit lebih pendek. Ini akan bekerja dengan berbagai jenis koleksi, misalnya Set <Integer>, List <String>, dll.
Latihan untuk pembaca : ubah metode ini agar dapat menangani koleksi null / kosong dengan benar :)
sumber
Yang membuat kode jelek adalah penanganan khusus untuk kasus pertama. Sebagian besar baris dalam cuplikan kecil ini ditujukan, bukan untuk melakukan tugas rutin kode, tetapi menangani kasus khusus tersebut. Dan itulah yang alternatif seperti pemecahan gimel, dengan memindahkan penanganan khusus di luar loop. Ada satu kasus khusus (yah, Anda dapat melihat awal dan akhir sebagai kasus khusus - tetapi hanya satu dari kasus tersebut yang perlu ditangani secara khusus), jadi penanganannya di dalam loop tidak perlu menjadi rumit.
sumber
Saya baru saja memeriksa tes untuk dolar perpustakaan saya :
itu membuat pembungkus yang lancar di sekitar daftar / array / string / dll hanya menggunakan satu impor statis :
$
.NB :
menggunakan rentang daftar sebelumnya dapat ditulis ulang sebagai
$(1, 5).join(",")
sumber
Hal yang menyenangkan tentang ekspresi IN adalah jika Anda memiliki nilai berulang, itu tidak mengubah hasilnya. Jadi, cukup duplikat item pertama dan proses seluruh daftar. Ini mengasumsikan bahwa setidaknya ada satu item dalam daftar. Jika tidak ada item, saya sarankan untuk memeriksanya terlebih dahulu dan kemudian tidak menjalankan SQL sama sekali.
Ini akan melakukan trik, jelas dalam apa yang dilakukannya dan tidak bergantung pada pustaka eksternal apa pun:
sumber
Sementara saya pikir taruhan terbaik Anda adalah menggunakan Joiner dari Guava, jika saya mengkodekannya dengan tangan, saya menemukan pendekatan ini lebih elegan daripada bendera 'pertama' atau memotong koma terakhir.
sumber
jika Anda memiliki array yang dapat Anda lakukan:
sumber
Pilihan lain, berdasarkan apa yang saya lihat di sini (dengan sedikit modifikasi).
sumber
Bergabung 'metode' tersedia di Array dan kelas yang memperluas
AbstractCollections
tetapi tidak menggantitoString()
metode (seperti hampir semua koleksi dijava.util
).Misalnya:
Itu cara yang cukup aneh karena hanya berfungsi untuk angka seperti data SQL.
sumber
StringUtils dari springframeowrk: spring-core
sumber
Anda mungkin bisa menggunakan LINQ (ke SQL), dan Anda mungkin bisa menggunakan sampel Dynamic Query LINQ dari MS. http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx
sumber
sumber
sumber
Token daftar = ArrayList baru (hasil); final StringBuilder builder = new StringBuilder ();
builder.toString ();
sumber