it-swarm-tr.com

Java'da ayrılmış öğeler dizesi oluşturmanın en iyi yolu nedir?

Java uygulamasında çalışırken, geçenlerde kaç öğenin olacağını bilmeden başka bir web hizmetine geçmek için virgülle ayrılmış bir değerler listesi oluşturmam gerekiyordu. Başımın üstünden bulabildiğim en iyi şey şunun gibi oldu:

public String appendWithDelimiter( String original, String addition, String delimiter ) {
    if ( original.equals( "" ) ) {
        return addition;
    } else {
        return original + delimiter + addition;
    }
}

String parameterString = "";
if ( condition ) parameterString = appendWithDelimiter( parameterString, "elementName", "," );
if ( anotherCondition ) parameterString = appendWithDelimiter( parameterString, "anotherElementName", "," );

Bunun özellikle verimli olmadığını anladım, çünkü her yerde yaratılan ipler var, ama optimizasyondan daha fazla netlik için gidiyordum.

Ruby'de bunun yerine böyle bir şey yapabilirim, ki bu çok daha zarif:

parameterArray = [];
parameterArray << "elementName" if condition;
parameterArray << "anotherElementName" if anotherCondition;
parameterString = parameterArray.join(",");

Ancak Java bir join komutundan yoksun olduğundan, eşdeğer bir şey bulamadım.

Peki, bunu Java'da yapmanın en iyi yolu nedir?

292
Sean McMains

Ön Java 8:

Apache'nin commons lang'i burada senin arkadaşın - Ruby'de başvurduğunuza çok benzeyen bir birleştirme yöntemi sağlar:

StringUtils.join(Java.lang.Iterable,char)


Java 8:

Java 8, StringJoiner ve String.join() aracılığıyla kutudan birleştirme işlemini sağlar. Aşağıdaki snippet'ler onları nasıl kullanabileceğinizi gösterir:

StringJoiner

StringJoiner joiner = new StringJoiner(",");
joiner.add("01").add("02").add("03");
String joinedString = joiner.toString(); // "01,02,03"

String.join(CharSequence delimiter, CharSequence... elements))

String joinedString = String.join(" - ", "04", "05", "06"); // "04 - 05 - 06"

String.join(CharSequence delimiter, Iterable<? extends CharSequence> elements)

List<String> strings = new LinkedList<>();
strings.add("Java");strings.add("is");
strings.add("cool");
String message = String.join(" ", strings);
//message returned is: "Java is cool"
503
Martin Gladdish

Java.util.Lists üzerinde çalışan küçük bir birleştirme tarzı yardımcı programı yazabilirsiniz.

public static String join(List<String> list, String delim) {

    StringBuilder sb = new StringBuilder();

    String loopDelim = "";

    for(String s : list) {

        sb.append(loopDelim);
        sb.append(s);            

        loopDelim = delim;
    }

    return sb.toString();
}

Sonra böyle kullanın:

    List<String> list = new ArrayList<String>();

    if( condition )        list.add("elementName");
    if( anotherCondition ) list.add("anotherElementName");

    join(list, ",");
52
Rob Dickerson

Android durumunda, commons'dan StringUtils sınıfı kullanılamaz, bu yüzden kullandım

Android.text.TextUtils.join(CharSequence delimiter, Iterable tokens)

http://developer.Android.com/reference/Android/text/TextUtils.html

47
Kevin

Google’ın Guava kütüphanesi (com.google.common.base.Joiner Bu tür görevlerin çözülmesine yardımcı olan sınıf.

Örnekler:

"My pets are: " + Joiner.on(", ").join(Arrays.asList("rabbit", "parrot", "dog")); 
// returns "My pets are: rabbit, parrot, dog"

Joiner.on(" AND ").join(Arrays.asList("field1=1" , "field2=2", "field3=3"));
// returns "field1=1 AND field2=2 AND field3=3"

Joiner.on(",").skipNulls().join(Arrays.asList("London", "Moscow", null, "New York", null, "Paris"));
// returns "London,Moscow,New York,Paris"

Joiner.on(", ").useForNull("Team held a draw").join(Arrays.asList("FC Barcelona", "FC Bayern", null, null, "Chelsea FC", "AC Milan"));
// returns "FC Barcelona, FC Bayern, Team held a draw, Team held a draw, Chelsea FC, AC Milan"

İşte bir Guava'nın dize programları hakkında makale .

31
Alex K

Java 8'de kullanabilirsiniz String.join() :

List<String> list = Arrays.asList("foo", "bar", "baz");
String joined = String.join(" and ", list); // "foo and bar and baz"

Ayrıca bir Akış API örneği için bu cevaba bu cevaba bakın.

25
micha

Genelleştirebilirsiniz, ancak dediğiniz gibi Java'ya katılmak yok.

B daha iyi sonuç verebilir.

public static String join(Iterable<? extends CharSequence> s, String delimiter) {
    Iterator<? extends CharSequence> iter = s.iterator();
    if (!iter.hasNext()) return "";
    StringBuilder buffer = new StringBuilder(iter.next());
    while (iter.hasNext()) buffer.append(delimiter).append(iter.next());
    return buffer.toString();
}
20
Vinko Vrsalovic

Java.lang.StringBuilder 'a dayanan bir yaklaşım kullanın! ("Değişken bir karakter dizisi.")

Bahsettiğiniz gibi, tüm bu dizgileri bir araya getirip dizeler oluşturuyorlar. StringBuilder bunu yapmaz.

Neden StringBuilder yerine StringBuffer ? StringBuilder javadoc'dan:

Mümkün olan yerlerde, bu sınıfın çoğu uygulamada daha hızlı olacağı için StringBuffer tercihinde kullanılması önerilir.

15
Stu Thompson

Java 8 içinde bunu şöyle yapabilirsiniz:

list.stream().map(Object::toString)
                        .collect(Collectors.joining(delimiter));

listede boş değerler varsa kullanabilirsiniz:

list.stream().map(String::valueOf)
                .collect(Collectors.joining(delimiter))
14
gladiator

Google Koleksiyonlar'i kullanırdım. Nice Katılma tesisi var.
http://google-collections.googlecode.com/svn/trunk/javadoc/index.html?com/google/common/base/Join.html

Ama eğer kendim yazmak istersem,

package util;

import Java.util.ArrayList;
import Java.util.Iterable;
import Java.util.Collections;
import Java.util.Iterator;

public class Utils {
    // accept a collection of objects, since all objects have toString()
    public static String join(String delimiter, Iterable<? extends Object> objs) {
        if (objs.isEmpty()) {
            return "";
        }
        Iterator<? extends Object> iter = objs.iterator();
        StringBuilder buffer = new StringBuilder();
        buffer.append(iter.next());
        while (iter.hasNext()) {
            buffer.append(delimiter).append(iter.next());
        }
        return buffer.toString();
    }

    // for convenience
    public static String join(String delimiter, Object... objs) {
        ArrayList<Object> list = new ArrayList<Object>();
        Collections.addAll(list, objs);
        return join(delimiter, list);
    }
}

Bir nesne koleksiyonuyla daha iyi çalıştığını düşünüyorum, çünkü nesnelerinize katılmadan önce dizeleri dönüştürmeniz gerekmez.

10
Eric Normand

Apache commons StringUtils sınıfı bir join yöntemine sahiptir.

8
Alejandro

Java 8

stringCollection.stream().collect(Collectors.joining(", "));
5
gstackoverflow

Ve en az bir tane (Apache Commons vs Guava'yı sadece dizeleri birleştirmek adına proje bağımlılıklarına dahil etmek istemiyorsanız)

/**
 *
 * @param delim : String that should be kept in between the parts
 * @param parts : parts that needs to be joined
 * @return  a String that's formed by joining the parts
 */
private static final String join(String delim, String... parts) {
    StringBuilder builder = new StringBuilder();
    for (int i = 0; i < parts.length - 1; i++) {
        builder.append(parts[i]).append(delim);
    }
    if(parts.length > 0){
        builder.append(parts[parts.length - 1]);
    }
    return builder.toString();
}
3
Thamme Gowda

StringBuilder ve sınıf Separator kullanın

StringBuilder buf = new StringBuilder();
Separator sep = new Separator(", ");
for (String each : list) {
    buf.append(sep).append(each);
}

Ayırıcı bir sınırlayıcıyı kaydırır. Sınırlayıcı, boş dizgeyi döndüren ilk çağrı olmadıkça, Separator'un toString yöntemiyle döndürülür!

Separator sınıfı için kaynak kodu

public class Separator {

    private boolean skipFirst;
    private final String value;

    public Separator() {
        this(", ");
    }

    public Separator(String value) {
        this.value = value;
        this.skipFirst = true;
    }

    public void reset() {
        skipFirst = true;
    }

    public String toString() {
        String sep = skipFirst ? "" : value;
        skipFirst = false;
        return sep;
    }

}
3
akuhn

Bunun için Java's StringBuilder yazın kullanabilirsiniz. Ayrıca StringBuffer var, fakat genellikle gereksiz olan ekstra iş güvenliği mantığı içeriyor.

3
Kent Boogaart

Eclipse Collections kullanıyorsanız, makeString() veya appendString() öğesini kullanabilirsiniz.

makeString(), toString() işlevine benzer şekilde String gösterimini döndürür.

Üç şekli var

  • makeString(start, separator, end)
  • makeString(separator) varsayılanları boş dizgelere başlar ve biter
  • makeString() ayırıcıyı varsayılan olarak ", " (virgül ve boşluk) olarak ayarlar

Kod örneği:

MutableList<Integer> list = FastList.newListWith(1, 2, 3);
assertEquals("[1/2/3]", list.makeString("[", "/", "]"));
assertEquals("1/2/3", list.makeString("/"));
assertEquals("1, 2, 3", list.makeString());
assertEquals(list.toString(), list.makeString("[", ", ", "]"));

appendString()makeString() işlevine benzer, ancak bir Appendable ekler (StringBuilder gibi) ve void. Ek üç argümanla Eklenti ile aynı üç forma sahiptir.

MutableList<Integer> list = FastList.newListWith(1, 2, 3);
Appendable appendable = new StringBuilder();
list.appendString(appendable, "[", "/", "]");
assertEquals("[1/2/3]", appendable.toString());

Koleksiyonunuzu bir Eclipse Koleksiyonlar türüne dönüştüremiyorsanız, ilgili adaptörle uyarlamanız yeterlidir.

List<Object> list = ...;
ListAdapter.adapt(list).makeString(",");

Not: Eclipse koleksiyonları için bir söz vericiyim.

2
Craig P. Motlin

Spring MVC kullanıyorsanız, aşağıdaki adımları deneyebilirsiniz.

import org.springframework.util.StringUtils;

List<String> groupIds = new List<String>;   
groupIds.add("a");    
groupIds.add("b");    
groupIds.add("c");

String csv = StringUtils.arrayToCommaDelimitedString(groupIds.toArray());

a,b,c ile sonuçlanacak

2
Ankit Lalan

Neden kendi join () yönteminizi yazmıyorsunuz? Strings ve sınırlayıcı String dizelerinin parametre koleksiyonu olarak görülebilir. Metot içinde koleksiyon üzerinde yineleyin ve sonucunuzu bir StringBuffer içinde toplayın.

2
Dave Costa

Java 5 değişken arg ile, tüm dizelerinizi açıkça bir koleksiyona veya diziye doldurmanız gerekmez:

import junit.framework.Assert;
import org.junit.Test;

public class StringUtil
{
    public static String join(String delim, String... strings)
    {
        StringBuilder builder = new StringBuilder();

        if (strings != null)
        {
            for (String str : strings)
            {
                if (builder.length() > 0)
                {
                    builder.append(delim).append(" ");
                }
                builder.append(str);
            }
        }           
        return builder.toString();
    }
    @Test
    public void joinTest()
    {
        Assert.assertEquals("", StringUtil.join(",", null));
        Assert.assertEquals("", StringUtil.join(",", ""));
        Assert.assertEquals("", StringUtil.join(",", new String[0]));
        Assert.assertEquals("test", StringUtil.join(",", "test"));
        Assert.assertEquals("foo, bar", StringUtil.join(",", "foo", "bar"));
        Assert.assertEquals("foo, bar, x", StringUtil.join(",", "foo", "bar", "x"));
    }
}
1
Mark B

Java 8 Yerel Türü

List<Integer> example;
example.add(1);
example.add(2);
example.add(3);
...
example.stream().collect(Collectors.joining(","));

Java 8 Özel Nesne:

List<Person> person;
...
person.stream().map(Person::getAge).collect(Collectors.joining(","));
1
Luis Aguilar

Bahar bağlamında olanlar için onların StringUtils sınıfı da faydalıdır:

Gibi birçok yararlı kısayol vardır:

  • collectionToCommaDelimitedString (Koleksiyon coll)
  • collectionToDelimitedString (Koleksiyon coll, String ayırma)
  • arrayToDelimitedString (Object [] arr, String sınırlaması)

ve bircok digerleri.

Zaten Java 8 kullanmıyorsanız ve zaten Spring bağlamındaysanız, bu yararlı olabilir.

Bunun gibi daha kolay olan Koleksiyon desteği için Apache Commons'a (çok iyi olmasına rağmen) tercih ederim:

// Encoding Set<String> to String delimited 
String asString = org.springframework.util.StringUtils.collectionToDelimitedString(codes, ";");

// Decoding String delimited to Set
Set<String> collection = org.springframework.util.StringUtils.commaDelimitedListToSet(asString);
1
рüффп

Muhtemelen, sonucunuzu oluşturmak için StringBuilder yöntemiyle bir append kullanmalısınız, ancak aksi halde bu, Java'ın sunduğu kadar iyi bir çözümdür.

1
newdayrising

Neden Java Ruby'de yaptığınız şeyi yapmıyorsunuz, bu sınırlayıcıyı ayrılmış dizgeyi ancak tüm parçaları diziye ekledikten sonra yaratıyor?

ArrayList<String> parms = new ArrayList<String>();
if (someCondition) parms.add("someString");
if (anotherCondition) parms.add("someOtherString");
// ...
String sep = ""; StringBuffer b = new StringBuffer();
for (String p: parms) {
    b.append(sep);
    b.append(p);
    sep = "yourDelimiter";
}

Bunu döngü için ayrı bir yardımcı yöntemde taşımak isteyebilir, ayrıca StringBuffer yerine StringBuilder ...

Düzenle: Eklerin sırası düzeltildi.

1
agnul

Yani temelde böyle bir şey:

public static String appendWithDelimiter(String original, String addition, String delimiter) {

if (original.equals("")) {
    return addition;
} else {
    StringBuilder sb = new StringBuilder(original.length() + addition.length() + delimiter.length());
        sb.append(original);
        sb.append(delimiter);
        sb.append(addition);
        return sb.toString();
    }
}
0
killdash10

Bunun gerçekten daha iyi olup olmadığını bilmiyorum, ama en azından biraz daha verimli olabilecek StringBuilder kullanıyor.

Aşağıda, herhangi bir parametre sınırlaması yapmadan ÖNCE parametrelerin listesini oluşturabiliyorsanız, daha genel bir yaklaşımdır.

// Answers real question
public String appendWithDelimiters(String delimiter, String original, String addition) {
    StringBuilder sb = new StringBuilder(original);
    if(sb.length()!=0) {
        sb.append(delimiter).append(addition);
    } else {
        sb.append(addition);
    }
    return sb.toString();
}


// A more generic case.
// ... means a list of indeterminate length of Strings.
public String appendWithDelimitersGeneric(String delimiter, String... strings) {
    StringBuilder sb = new StringBuilder();
    for (String string : strings) {
        if(sb.length()!=0) {
            sb.append(delimiter).append(string);
        } else {
            sb.append(string);
        }
    }

    return sb.toString();
}

public void testAppendWithDelimiters() {
    String string = appendWithDelimitersGeneric(",", "string1", "string2", "string3");
}
0
Mikezx6r

Yaklaşımınız çok kötü değil, ancak + işaretini kullanmak yerine bir StringBuffer kullanmalısınız. +, Her bir işlem için yeni bir String örneği oluşturulmasının büyük dezavantajına sahiptir. İpin ne kadar uzun olursa, havai o kadar büyük olur. Bu yüzden bir StringBuffer kullanmak en hızlı yol olmalıdır:

public StringBuffer appendWithDelimiter( StringBuffer original, String addition, String delimiter ) {
        if ( original == null ) {
                StringBuffer buffer = new StringBuffer();
                buffer.append(addition);
                return buffer;
        } else {
                buffer.append(delimiter);
                buffer.append(addition);
                return original;
        }
}

Dizenizi oluşturma işlemini tamamladıktan sonra, döndürülen StringBuffer'da sadeceString () işlevini çağırın.

0
Yaba
//Note: if you have access to Java5+, 
//use StringBuilder in preference to StringBuffer.  
//All that has to be replaced is the class name.  
//StringBuffer will work in Java 1.4, though.

appendWithDelimiter( StringBuffer buffer, String addition, 
    String delimiter ) {
    if ( buffer.length() == 0) {
        buffer.append(addition);
    } else {
        buffer.append(delimiter);
        buffer.append(addition);
    }
}


StringBuffer parameterBuffer = new StringBuffer();
if ( condition ) { 
    appendWithDelimiter(parameterBuffer, "elementName", "," );
}
if ( anotherCondition ) {
    appendWithDelimiter(parameterBuffer, "anotherElementName", "," );
}

//Finally, to return a string representation, call toString() when returning.
return parameterBuffer.toString(); 
0
MetroidFan2002

Dollar kullanmak, yazmak kadar basittir:

String joined = $(aCollection).join(",");

Not: Dizi ve diğer veri tipleri için de çalışır.

Uygulama

Dahili olarak çok temiz bir numara kullanır:

@Override
public String join(String separator) {
    Separator sep = new Separator(separator);
    StringBuilder sb = new StringBuilder();

    for (T item : iterable) {
        sb.append(sep).append(item);
    }

    return sb.toString();
}

Separator sınıfı, yalnızca ilk çağrıldığında boş Dize'yi döndürür, ardından ayırıcıyı döndürür:

class Separator {

    private final String separator;
    private boolean wasCalled;

    public Separator(String separator) {
        this.separator = separator;
        this.wasCalled = false;
    }

    @Override
    public String toString() {
        if (!wasCalled) {
            wasCalled = true;
            return "";
        } else {
            return separator;
        }
    }
}
0
dfa

Cevabı düzeltmek Rob Dickerson.

Kullanımı daha kolay:

public static String join(String delimiter, String... values)
{
    StringBuilder stringBuilder = new StringBuilder();

    for (String value : values)
    {
        stringBuilder.append(value);
        stringBuilder.append(delimiter);
    }

    String result = stringBuilder.toString();

    return result.isEmpty() ? result : result.substring(0, result.length() - 1);
}
0
maXp

Dize bitiştirme kullanmak yerine, kodunuz iş parçacıklı değilse StringBuilder, öyleyse StringBuffer kullanmalısınız.

0
Aaron

Bu yüzden aradığınızı düşündüğünüzü hissetmek için yapabileceğiniz birkaç şey:

1) Liste sınıfını genişlet - ve buna birleştirme yöntemi ekleyin. Join yöntemi, sınırlayıcıyı birleştirme ve ekleme işini yapar (bu birleştirme yöntemine param olabilir)

2) Java 7, Java öğesine genişletme yöntemleri ekliyor olacak gibi görünüyor - bu, bir sınıfa yalnızca belirli bir yöntemi eklemenizi sağlar: böylece bu birleştirme yöntemini yazabilirsiniz. ve Listeye veya hatta Koleksiyona bir uzatma yöntemi olarak ekleyin.

Çözüm 1 muhtemelen şu andaki tek gerçekçi sonuçtur, ancak Java 7 henüz çıkmadı çünkü :) Ama iyi çalışması gerekiyor.

Bunların her ikisini de kullanmak için, tüm öğelerinizi her zamanki gibi Listeye veya Koleksiyona ekler ve ardından onlara katılmak için yeni özel yöntemi çağırırsınız.

0
user13276

Bunu olması gerekenden biraz daha karmaşık hale getiriyorsun. Örneği sonuna başlayalım:

String parameterString = "";
if ( condition ) parameterString = appendWithDelimiter( parameterString, "elementName", "," );
if ( anotherCondition ) parameterString = appendWithDelimiter( parameterString, "anotherElementName", "," );

Bir String yerine bir StringBuilder kullanarak yapılan küçük değişikliklerle, bu olur:

StringBuilder parameterString = new StringBuilder();
if (condition) parameterString.append("elementName").append(",");
if (anotherCondition) parameterString.append("anotherElementName").append(",");
...

İşiniz bittiğinde (birkaç koşulu da kontrol etmeniz gerektiğini varsayalım), yalnızca virgül virgülünü böyle bir komutla kaldırdığınızdan emin olun:

if (parameterString.length() > 0) 
    parameterString.deleteCharAt(parameterString.length() - 1);

Sonunda, istediğiniz dizeyi alın

parameterString.toString();

Ayrıca, herhangi bir şey için ayarlanabilecek genel bir sınırlayıcı dizeyle eklemek için ikinci çağrıda "," ifadesini de değiştirebilirsiniz. Eklemeniz gereken bildiğiniz şeylerin bir listesi varsa (koşulsuz olarak), bu kodu dizelerin listesini alan bir yöntemin içine koyabilirsiniz.

0
cjw2600

İzb'den versiyonun hafif iyileştirme [hızı]:

public static String join(String[] strings, char del)
{
    StringBuilder sb = new StringBuilder();
    int len = strings.length;

    if(len > 1) 
    {
       len -= 1;
    }else
    {
       return strings[0];
    }

    for (int i = 0; i < len; i++)
    {
       sb.append(strings[i]).append(del);
    }

    sb.append(strings[i]);

    return sb.toString();
}
0
java al

Kişisel olarak, günlüğe kaydetme amacıyla aşağıdaki basit çözümü kullanıyorum:

List lst = Arrays.asList("ab", "bc", "cd");
String str = lst.toString().replaceAll("[\\[\\]]", "");
0
Philipp Grigoryev

Böyle bir şeyi deneyebilirsiniz:

StringBuilder sb = new StringBuilder();
if (condition) { sb.append("elementName").append(","); }
if (anotherCondition) { sb.append("anotherElementName").append(","); }
String parameterString = sb.toString();
0
martinatime