C # String.Format () ve String.Join () Java eşdeğerleri


Yanıtlar:


92

Java String nesnesinin bir formatyöntemi vardır (1.5 itibariyle), ancak joinyöntemi yoktur .

Halihazırda dahil edilmemiş bir dizi faydalı String yardımcı programı yöntemi elde etmek için org.apache.commons.lang.StringUtils'i kullanabilirsiniz .


13
google collections: google-collections.googlecode.com'da ayrıca bir Marangoz vardır.
Ron

10
Bilginize, Ron'un yorumuna göre, google koleksiyonları bir süre önce Guava olarak yeniden adlandırıldı.
Kevin Bourrillion

3
Java 8'in bir String.join()yöntem sunduğunu yansıtmak için bu yanıtı güncellemelisiniz .
Duncan Jones

46

String.format . Katılmak için kendi yazman gereken:

 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();
 }

Yukarıdakiler http://snippets.dzone.com/posts/show/91 adresinden gelir.


6
Daha kesin olarak: jdk1.4 ve aşağısı için StringBuffer, jdk1.5 ve sonrası için StringBuilder, ikincisi senkronize olmadığından, dolayısıyla biraz daha hızlı.
VonC

2
Iter.hasNext () iki çağrı yerine genellikle ayırıcı eklerim ve ardından "return buf.substring (0, buf.length () - delimeter.length ())".
Vilmantas Baranauskas

2
Sınırlayıcıdan kaçınmak için erken çıkarak onu biraz düzene sokabilirsiniz: while (true) (add_iter; if (! İter.hasNext ()) break; add_delim;}
13ren


29

Java 8'den itibaren, join() artık String sınıfında iki sınıf yöntemi olarak mevcuttur. Her iki durumda da ilk argüman sınırlayıcıdır.

Tek tek CharSequenceURL'leri ek bağımsız değişkenler olarak iletebilirsiniz :

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

Veya birIterable<? 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 ayrıca StringJoinerşu şekilde kullanabileceğiniz yeni bir sınıf ekler :

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"


12

Aşağıdaki gibi dizeler için değişken argümanlar da kullanabilirsiniz:

  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();
  }

4

Katılmaya gelince, bunun biraz daha az karmaşık görünebileceğine inanıyorum:

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

Java 5 sözdizimini istediğim kadar kullanamıyorum (İster inanın ister inanmayın, son zamanlarda 1.0.x kullanıyorum) bu yüzden biraz paslanmış olabilirim, ancak konseptin doğru olduğundan eminim .

Düzenleme eki: Dize eklemeleri yavaş olabilir, ancak GUI kodu veya kısa süreli bir rutin üzerinde çalışıyorsanız, .005 saniye veya .006 almanız gerçekten önemli değil, yani "joinMe" adlı bir koleksiyonunuz varsa mevcut bir "hedef" dizesine eklemek istemeniz, bunu satır içinde yapmak korkunç olmaz:

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

Oldukça verimsizdir (ve kötü bir alışkanlıktır), ancak binlerce dizge olmadığı veya bu çok büyük bir döngü içinde olmadığı veya kodunuz gerçekten performans açısından kritik olmadığı sürece algılayamayacağınız hiçbir şey olamaz.

Daha da önemlisi, hatırlaması kolay, kısa, hızlı ve çok okunabilir. Performans, tasarım seçimlerinde her zaman otomatik kazanan değildir.


For döngüsü doğrudur, ancak bunu bir Collection <String> yapmanız gerekir. Aksi takdirde, "for (Nesne o: c)" demeniz gerekir, çünkü c'deki her şeyin bir String olduğunu garanti edemezsiniz.
Michael Myers

İyi nokta, Generics konusunda daha da paslandım. İçinde düzenleyeceğim.
Bill K

Satır içi: dize + dize + dizeyi birleştirirken, derleyici aslında değerleri eklemek için StringBuilder kullanır. Merak ediyorum, for-loop yönteminde orada ikinci olanınız var mı, derleyicinin de aynısını yapıp yapmayacağını merak ediyorum.
Spencer Kormos

@Spencer K: Bir StringBuilder kullanıyor, ancak her yineleme için yeni bir tane yaratıyor (neredeyse en verimli yöntem değil, ama o zaman derleyicinin nasıl bilmesi gerekiyor?). JIT derleyicisinin bunu çalışma zamanında optimize edip edemeyeceğini bilmiyorum.
Michael Myers

2
Bekle. + = Konuşuyor musunuz? Evet, bu berbat. Şu anda cevabımdaki döngü ve ekleme, StringBuilder kullanıyor ve ben de bundan bahsediyorum. + = Çok gelişmesine rağmen, onu bir döngü içinde kullanmak istemiyorsunuz - o kadar da hatalı değil ama bok gibi performans gösterebiliyor (Bug genellikle performans sorunları için kullanılan bir terim değil - en azından değil 20 yıllık programlamamda). Ayrıca JIT bunu büyük ölçüde geliştirebilir - ama ben buna güvenmem.
Bill K

4

İşte oldukça basit bir cevap. Daha +=az kod olduğu için kullanın ve optimize edicinin onu StringBuildersizin için bir dönüştürmesine izin verin . Bu yöntemi kullanarak, döngünüzde herhangi bir "sondur" denetimi yapmanız gerekmez (performans iyileştirmesi) ve sonunda herhangi bir sınırlayıcıyı kaldırma konusunda endişelenmeniz gerekmez.

        Iterator<String> iter = args.iterator();
        output += iter.hasNext() ? iter.next() : "";
        while (iter.hasNext()) {
            output += "," + iter.next();
        }

1
3. parti kütüphaneleri içermeyen çok zarif bir çözüm!
Denis Itskovich

2

Basit bir birleştirme işlevi eklemek için tüm bir Apache kitaplığını içe aktarmak istemedim, işte benim hack'im.

    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();
        }
    }

@MrSnowflake Standart dize oluşturucunun bir "removeCharAt (int index)" yöntemi var mı? Çalışmakta olan sürümde
görünmüyor

@NSjonas - evet cevabıma yaptığı düzenleme yanlış. removeCharAtYok ve tüm işlevi artık bir String döndüren ... Bu düzeltecek.
Martin Konecny

buna rağmen ... bu mevcut çözüm, "boş bir Listeyi geçerseniz sınır dışı bir dizin istisnası"
atacak

sınır 1 karakterden fazlaysa doğru uzunluğu kesmek için bir düzenleme yaptı. Ayrıca, gerçekten ihtiyaç duyduğunuz ilk karakteri değil, son karakteri
kırptığınız

Geri bildirim için teşekkürler. Güncellenmiş.
Martin Konecny

1

Birkaç dizgeyi bir araya getirmek (birleştirmek) istiyorsanız, bir StringBuilder kullanmalısınız. Kullanmaktan çok daha iyi

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

StringBuilder senkronizasyon kullanmadığından, StringBuffer'a göre küçük bir performans kazanımı da vardır.

Bunun gibi genel amaçlı bir yardımcı program yöntemi için, (sonunda) birçok durumda birçok kez çağrılacaktır, bu nedenle onu verimli hale getirmeli ve çok sayıda geçici nesne ayırmamalısınız. Pek çok farklı Java uygulamasının profilini çıkardık ve neredeyse her zaman dize birleştirme ve dize / karakter [] ayırmalarının önemli miktarda zaman / bellek kullandığını gördük.

Yeniden kullanılabilir koleksiyon -> string yöntemimiz önce gerekli sonucun boyutunu hesaplar ve ardından bu başlangıç ​​boyutuna sahip bir StringBuilder oluşturur; bu, dizeleri eklerken kullanılan dahili karakterin [] gereksiz iki katına çıkarılmasını / kopyalanmasını önler.


re: pre-hesaplama boyutu: İşe yaradığında, harika. Her zaman mümkün değildir. Her seferinde arabellek boyutunu ikiye katlamanın (veya herhangi bir sabit faktörle çarpmanın) n log n performansı gibi bir şey verdiğini okuduğumu hatırlıyorum, bu gerçekten o kadar da kötü değil. Genel durumda, alternatif, birleştirmeyi planladığınız tüm dizelerin bir listesini yapmaktır. Bir ArrayList kullanırsanız, tekrar kopyalamanız gerekir (dizinizin uzunluğunu önceden bilmiyorsanız) ve LinkedList kullanırsanız, düğüm nesneleriyle daha fazla ram ve çöp toplama kullanır. Bazen kazanamazsınız. Deneyin!
Ian

Yukarıdaki örnekler / sorgular, sıralı bir koleksiyon veya bir dizi Dizge dizisi olduğunu varsaydı. Ayrıca, boyutu önceden hesaplayarak, dahili karakter [] dizisi büyümesinin genellikle neden olduğu fazladan kullanılmayan karakterlerden
kaçınmış olursunuz

1

Kendime yazdım:

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();
}

ancak CollectionJSP tarafından desteklenmiyor, bu yüzden etiket işlevi için şunu yazdım:

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();
}

ve .tlddosyaya koy :

<?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>

ve JSP dosyalarında şu şekilde kullanın:

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



0

String.Join için çok fazla karmaşık uygulama görüyorum. Java 1.8'iniz yoksa ve yeni bir kitaplık almak istemiyorsanız, aşağıdaki uygulama yeterli olacaktır.

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();
}

-1
ArrayList<Double> j=new ArrayList<>; 
j.add(1);
j.add(.92);
j.add(3); 
String ntop=j.toString(); //ntop= "[1, 0.92, 3]" 

Temel olarak String ntop, tüm koleksiyonun değerini virgül ayırıcılar ve parantezlerle saklar.


1
Bunun sorunun hangi kısmını yanıtladığından emin değilim? Dizenin bitlerini diziye azar azar eklemeyi planlamadığınız sürece ve [1,0.92,3] genel bir dizge .join kadar çok yönlü olmadığı sürece bu bir String.format değildir.
Omar Kooheji

-8

İki dizeyi birleştirmek için sadece "+" dize birleştirme operatörünü kullanırdım. s1 += s2;


Çünkü bu kötü ve yavaş.
MrSnowflake
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.