Java setara dengan C # String.Format () dan String.Join ()

111

Saya tahu ini sedikit pertanyaan pemula, tetapi apakah ada yang setara dengan operasi string C # di Java?

Secara khusus, saya sedang berbicara tentang String.Formatdan String.Join.

Omar Kooheji
sumber
Jadi ada String.format tapi saya harus Roll my own join.
Omar Kooheji
1
Untuk join (), saya suka jawaban ini: stackoverflow.com/a/6116469/562139
scorpiodawg

Jawaban:

92

Objek Java String memiliki formatmetode (mulai 1.5), tetapi tidak ada joinmetode.

Untuk mendapatkan sekumpulan metode utilitas String berguna yang belum disertakan, Anda dapat menggunakan org.apache.commons.lang.StringUtils .

Berikan Wagner
sumber
13
koleksi google: google-collections.googlecode.com memiliki Joiner juga.
Ron
10
FYI atas komentar Ron, google-collections diubah namanya menjadi Guava beberapa waktu lalu.
Kevin Bourrillion
3
Anda harus memperbarui jawaban ini untuk mencerminkan bahwa Java 8 memperkenalkan String.join()metode.
Duncan Jones
46

String.format . Untuk bergabung, Anda perlu menulis sendiri:

 static String join(Collection<?> s, String delimiter) {
     StringBuilder builder = new StringBuilder();
     Iterator<?> iter = s.iterator();
     while (iter.hasNext()) {
         builder.append(iter.next());
         if (!iter.hasNext()) {
           break;                  
         }
         builder.append(delimiter);
     }
     return builder.toString();
 }

Di atas berasal dari http://snippets.dzone.com/posts/show/91

Allain Lalonde
sumber
6
Lebih tepatnya: StringBuffer untuk jdk1.4 dan yang lebih lama, StringBuilder untuk jdk1.5 dan setelahnya, karena yang terakhir tidak disinkronkan, karenanya sedikit lebih cepat.
VonC
2
Alih-alih dua pemanggilan iter.hasNext () Saya biasanya menambahkan delimeter dan kemudian "return buf.substring (0, buf.length () - delimeter.length ())".
Vilmantas Baranauskas
2
Anda dapat menyederhanakannya sedikit dengan keluar lebih awal untuk menghindari pembatas: while (true) (add_iter; if (! Iter.hasNext ()) break; add_delim;}
13ren
29

Pada Java 8, join()sekarang tersedia sebagai dua metode kelas pada kelas String. Dalam kedua kasus, argumen pertama adalah pembatas.

Anda dapat memberikan individu CharSequencesebagai argumen tambahan :

String joined = String.join(", ", "Antimony", "Arsenic", "Aluminum", "Selenium");
// "Antimony, Arsenic, Alumninum, Selenium"

Atau Anda bisa lulusIterable<? extends CharSequence> :

List<String> strings = new LinkedList<String>();
strings.add("EX");
strings.add("TER");
strings.add("MIN");
strings.add("ATE");

String joined = String.join("-", strings);
// "EX-TER-MIN-ATE"

Java 8 juga menambahkan kelas baru StringJoiner, yang dapat Anda gunakan seperti ini:

StringJoiner joiner = new StringJoiner("&");
joiner.add("x=9");
joiner.add("y=5667.7");
joiner.add("z=-33.0");

String joined = joiner.toString();
// "x=9&y=5667.7&z=-33.0"
qntm
sumber
12

Anda juga dapat menggunakan argumen variabel untuk string sebagai berikut:

  String join (String delim, String ... data) {
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < data.length; i++) {
      sb.append(data[i]);
      if (i >= data.length-1) {break;}
      sb.append(delim);
    }
    return sb.toString();
  }
sgsweb.dll
sumber
4

Untuk bergabung, saya yakin ini mungkin terlihat sedikit lebih mudah:

public String join (Collection<String> c) {
    StringBuilder sb=new StringBuilder();
    for(String s: c)
        sb.append(s);
    return sb.toString();
}

Saya tidak bisa menggunakan sintaks Java 5 sebanyak yang saya inginkan (Percaya atau tidak, saya telah menggunakan 1.0.x akhir-akhir ini) jadi saya mungkin agak berkarat, tapi saya yakin konsepnya benar .

edit tambahan: Penambahan string bisa lambat, tetapi jika Anda bekerja pada kode GUI atau beberapa rutinitas yang berjalan singkat, tidak masalah jika Anda mengambil .005 detik atau .006, jadi jika Anda memiliki koleksi yang disebut "joinMe" yang ingin Anda tambahkan ke string "target" yang ada, tidak akan mengerikan jika hanya sebaris ini:

for(String s : joinMe)
    target += s;

Ini cukup tidak efisien (dan kebiasaan buruk), tetapi tidak apa pun yang dapat Anda lihat kecuali ada ribuan string atau ini ada di dalam lingkaran besar atau kode Anda benar-benar penting untuk performa.

Lebih penting lagi, mudah diingat, singkat, cepat dan sangat mudah dibaca. Performa tidak selalu menjadi pemenang otomatis dalam pilihan desain.

Bill K
sumber
Perulangan-ke benar, tetapi Anda juga harus membuatnya menjadi Collection <String>. Jika tidak, Anda harus mengatakan "untuk (Objek o: c)", karena Anda tidak dapat menjamin bahwa semua yang ada di c adalah String.
Michael Myers
Poin bagus, saya bahkan lebih berkarat dengan Generik. Saya akan mengeditnya.
Bill K
Saat menggabungkan inline: string + string + string, compiler sebenarnya menggunakan StringBuilder untuk menambahkan nilai. Saya ingin tahu apakah dalam metode for-loop Anda memiliki yang kedua di sana, apakah kompiler akan melakukan hal yang sama.
Spencer Kormos
@ Spencer K: Ini memang menggunakan StringBuilder, tetapi membuat yang baru untuk setiap iterasi (bukan metode yang paling efisien, tapi bagaimana kompiler seharusnya mengetahuinya?). Saya tidak tahu apakah compiler JIT dapat mengoptimalkannya pada saat runtime.
Michael Myers
2
Oh tunggu. Apakah Anda berbicara + =? Ya, itu menyebalkan. Loop dan menambahkan saat ini dalam jawaban saya menggunakan StringBuilder dan itulah yang saya bicarakan. Meskipun + = telah meningkat pesat, Anda benar-benar tidak ingin menggunakannya di dalam loop - tidak terlalu banyak yang buggy tetapi dapat berfungsi seperti omong kosong (Bug bukan istilah yang umumnya digunakan untuk masalah kinerja - setidaknya tidak dalam 20 tahun pemrograman saya). Juga JIT dapat meningkatkan ini dengan sangat - tetapi saya tidak akan mengandalkan itu.
Bill K
4

Inilah jawaban yang cukup sederhana. Gunakan +=karena ini lebih sedikit kode dan biarkan pengoptimal mengubahnya menjadi StringBuilderuntuk Anda. Dengan menggunakan metode ini, Anda tidak perlu melakukan pemeriksaan "terakhir" di loop Anda (peningkatan kinerja) dan Anda tidak perlu khawatir tentang menghapus pembatas apa pun di akhir.

        Iterator<String> iter = args.iterator();
        output += iter.hasNext() ? iter.next() : "";
        while (iter.hasNext()) {
            output += "," + iter.next();
        }
Jess
sumber
1
Solusi yang sangat elegan, tidak melibatkan perpustakaan pihak ketiga!
Denis Itskovich
2

Saya tidak ingin mengimpor seluruh pustaka Apache untuk menambahkan fungsi gabungan sederhana, jadi inilah retasan saya.

    public String join(String delim, List<String> destinations) {
        StringBuilder sb = new StringBuilder();
        int delimLength = delim.length();

        for (String s: destinations) {
            sb.append(s);
            sb.append(delim);
        }

        // we have appended the delimiter to the end 
        // in the previous for-loop. Let's now remove it.
        if (sb.length() >= delimLength) {
            return sb.substring(0, sb.length() - delimLength);
        } else {
            return sb.toString();
        }
    }
Martin Konecny
sumber
@MrSnowflake Apakah pembuat string standar memiliki metode "removeCharAt (int index)" Ini tidak muncul pada versi yang saya jalankan
NSjonas
@NSjonas - ya suntingannya atas jawaban saya salah. Tidak removeCharAtada, dan seluruh fungsi tidak lagi mengembalikan String ... Akan memperbaiki ini.
Martin Konecny
sementara Anda melakukannya ... solusi saat ini akan menampilkan "indeks di luar batas pengecualian jika Anda meneruskan dalam Daftar kosong"
NSjonas
melakukan edit untuk memangkas panjang yang tepat jika pembatas lebih dari 1 karakter. Juga memperbaiki masalah di mana Anda memangkas karakter terakhir dan bukan yang pertama seperti yang benar-benar Anda perlukan
NSjonas
Terima kasih atas umpan baliknya. Diperbarui.
Martin Konecny
1

Jika Anda ingin menggabungkan (menggabungkan) beberapa string menjadi satu, Anda harus menggunakan StringBuilder. Ini jauh lebih baik daripada menggunakan

for(String s : joinMe)
    target += s;

Ada juga sedikit kinerja menang atas StringBuffer, karena StringBuilder tidak menggunakan sinkronisasi.

Untuk metode utilitas tujuan umum seperti ini, metode ini (pada akhirnya) akan dipanggil berkali-kali dalam banyak situasi, jadi Anda harus membuatnya efisien dan tidak mengalokasikan banyak objek sementara. Kami telah membuat profil banyak, banyak aplikasi Java yang berbeda dan hampir selalu menemukan bahwa penggabungan string dan alokasi string / char [] membutuhkan banyak waktu / memori.

Metode collection -> string kami yang dapat digunakan kembali pertama-tama menghitung ukuran hasil yang diperlukan dan kemudian membuat StringBuilder dengan ukuran awal tersebut; ini menghindari penggandaan / penyalinan karakter internal [] yang tidak perlu yang digunakan saat menambahkan string.

djb
sumber
re: ukuran yang dihitung sebelumnya: Jika berhasil, itu bagus. Itu tidak selalu memungkinkan. Saya ingat pernah membaca di suatu tempat bahwa menggandakan ukuran buffer setiap kali (atau benar-benar mengalikan dengan faktor tetap) memberikan sesuatu seperti kinerja n log n, yang sebenarnya tidak terlalu buruk. Dalam kasus umum, alternatifnya adalah membuat daftar semua string yang Anda rencanakan untuk digabungkan. Jika Anda menggunakan ArrayList, Anda harus menyalin lagi (kecuali Anda mengetahui panjang urutan Anda sebelumnya) dan jika Anda menggunakan LinkedList, maka itu menggunakan lebih banyak ram dan pengumpulan sampah dengan objek node. Terkadang Anda tidak bisa menang. Cobalah!
Ian
Contoh / pertanyaan di atas mengasumsikan beberapa kumpulan atau larik String yang dipesan untuk digabungkan. Selain itu, dengan menghitung ukuran sebelumnya, Anda menghindari karakter tambahan yang tidak digunakan yang biasanya dihasilkan oleh pertumbuhan array char [] internal.
djb
1

Saya menulis sendiri:

public static String join(Collection<String> col, String delim) {
    StringBuilder sb = new StringBuilder();
    Iterator<String> iter = col.iterator();
    if (iter.hasNext())
        sb.append(iter.next().toString());
    while (iter.hasNext()) {
        sb.append(delim);
        sb.append(iter.next().toString());
    }
    return sb.toString();
}

tetapi Collectiontidak didukung oleh JSP, jadi untuk fungsi tag saya menulis:

public static String join(List<?> list, String delim) {
    int len = list.size();
    if (len == 0)
        return "";
    StringBuilder sb = new StringBuilder(list.get(0).toString());
    for (int i = 1; i < len; i++) {
        sb.append(delim);
        sb.append(list.get(i).toString());
    }
    return sb.toString();
}

dan masukkan ke .tldfile:

<?xml version="1.0" encoding="UTF-8"?>
<taglib version="2.1" xmlns="http://java.sun.com/xml/ns/javaee"
    <function>
        <name>join</name>
        <function-class>com.core.util.ReportUtil</function-class>
        <function-signature>java.lang.String join(java.util.List, java.lang.String)</function-signature>
    </function>
</taglib>

dan gunakan dalam file JSP sebagai:

<%@taglib prefix="funnyFmt" uri="tag:com.core.util,2013:funnyFmt"%>
${funnyFmt:join(books, ", ")}
gavenkoa.dll
sumber
0

Saya melihat banyak implementasi String.Join yang terlalu kompleks di sini. Jika Anda tidak memiliki Java 1.8, dan Anda tidak ingin mengimpor pustaka baru, implementasi di bawah ini sudah cukup.

public String join(Collection<String> col, String delim) {
    StringBuilder sb = new StringBuilder();
    for ( String s : col ) {
        if ( sb.length() != 0 ) sb.append(delim);
        sb.append(s);
    }
    return sb.toString();
}
Brandon Dutton
sumber
-1
ArrayList<Double> j=new ArrayList<>; 
j.add(1);
j.add(.92);
j.add(3); 
String ntop=j.toString(); //ntop= "[1, 0.92, 3]" 

Jadi pada dasarnya, String ntop menyimpan nilai seluruh koleksi dengan pemisah koma dan tanda kurung.

Edward Karak
sumber
1
Saya tidak yakin bagian mana dari pertanyaan yang dijawab ini? Ini bukan format String kecuali Anda berencana menambahkan bit dari string sedikit demi sedikit ke array, dan [1,0.92,3] tidak serba guna seperti string generik .join.
Omar Kooheji
-8

Saya hanya akan menggunakan operator penggabungan string "+" untuk menggabungkan dua string. s1 += s2;

Amir Bashir
sumber
Karena itu latihan yang buruk dan lambat.
MrSnowflake