Java: <String> Listesini bir Dizeye dönüştür


595

JavaScript var Array.join()

js>["Bill","Bob","Steve"].join(" and ")
Bill and Bob and Steve

Java'nın böyle bir şeyi var mı? Ben StringBuilder ile kendimi bir şey Arnavut kaldırımı biliyorum:

static public String join(List<String> list, String conjunction)
{
   StringBuilder sb = new StringBuilder();
   boolean first = true;
   for (String item : list)
   {
      if (first)
         first = false;
      else
         sb.append(conjunction);
      sb.append(item);
   }
   return sb.toString();
}

... ancak böyle bir şey zaten JDK'nın bir parçasıysa bunu yapmanın bir anlamı yok.


1
Ayrıca listeler
Casebash

18
Kesinlikle ilgili değil ama android, TextUtils sınıfının bir parçası olarak yerleşik bir birleştirme işlevine sahiptir: developer.android.com/reference/android/text/… , java.lang.Iterable)
Xavi

16
Java 8'in bir String.join()yöntemi vardır. Java 8 (veya daha yenisi) kullanıyorsanız, bu cevaba bir göz atın stackoverflow.com/a/22577565/1115554
micha

Yanıtlar:


763

Java 8 ile bunu herhangi bir üçüncü taraf kütüphanesi olmadan yapabilirsiniz.

Bir Dizeler Koleksiyonuna katılmak istiyorsanız, yeni String.join () yöntemini kullanabilirsiniz:

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

Dize dışında bir türe sahip bir Koleksiyonunuz varsa, Katılan Toplayıcı ile Akış API'sını kullanabilirsiniz :

List<Person> list = Arrays.asList(
  new Person("John", "Smith"),
  new Person("Anna", "Martinez"),
  new Person("Paul", "Watson ")
);

String joinedFirstNames = list.stream()
  .map(Person::getFirstName)
  .collect(Collectors.joining(", ")); // "John, Anna, Paul"

StringJoinerSınıfı da yararlı olabilir.


7
Ne yazık ki, String.join yalnızca CharSequences'ı kabul eder ve Nesnelerin umduğu gibi değil. Nullsafe olup olmadığından bile emin değilim
Marc

@MarcassertThat(String.join(", ", Lists.newArrayList("1", null)), is("1, null"));
Sanghyun Lee

StringJoiner, özellikle [a, b, c]diş telleri dahil olmak üzere bir şeye katılmak istiyorsa yararlıdır .
koppor

@Marc String.join de kabul eder Iterable<CharSequence>; Arayüz ilişkisi:Iterable -> Collection -> List
aff

306

Apache Commons tüm referanslar ince (ve çoğu insan kullanmak budur) ama bence Guava eşdeğer Joiner , bir daha hoş bir API vardır.

İle basit birleştirme davası yapabilirsiniz

Joiner.on(" and ").join(names)

aynı zamanda boş değerlerle de kolayca başa çıkabilir:

Joiner.on(" and ").skipNulls().join(names);

veya

Joiner.on(" and ").useForNull("[unknown]").join(names);

ve (commons-lang yerine kullanmak için endişelendiğim kadarıyla), Haritalar ile ilgilenme yeteneği:

Map<String, Integer> ages = .....;
String foo = Joiner.on(", ").withKeyValueSeparator(" is ").join(ages);
// Outputs:
// Bill is 25, Joe is 30, Betty is 35

hangi hata ayıklama vb için son derece yararlıdır.


10
fiş için teşekkürler! Marangozumuz ayrıca, Apache kütüphanesinin eksik göründüğü ara Dizeler oluşturmadan doğrudan bir Appendable'a (StringBuilder veya herhangi bir Yazar gibi) ekleme seçeneği sunar.
Kevin Bourrillion

2
Bu harika, ancak lütfen .useForLastSeparator()benzer bir yöntem veya benzer bir yöntem ekleyebilir misiniz ? Bu şekilde, yalnızca son iki öğe arasında "ve" gibi bir şey elde edebilirsiniz (geri kalanı için "," ile).
Jeff Evans

2
Evet, iplik güvenli. Bir birleştiriciye kaydedilen tek durum separator(ki final). Bir Apache Commons eşdeğerini kullandığım Guava'da gördüğüm her şey, daha az kenar hatası ve iş parçacığı güvenliği sorunları ile Guava'da çok daha iyi (daha temiz, daha hızlı, daha güvenli ve genel olarak daha sağlam) ve daha küçük bellek alanı. Onların "mümkün olan en iyi yolu" yol gösterici prensibi şimdiye kadar geçerli gibi görünüyor.
Shadow Man

Ters yöne gitmeniz gerekiyorsa (yani, bir String'i parçalara bölmek), Guava sınıfı Splitter'a da bakın - ayrıca çok iyi tasarlanmış / uygulanmıştır.
Matt Passell

Java 8'de bir String.join()yöntem ve bir StringJoinersınıf vardır.
theTechnoKid

138

Kutunun dışında değil, ancak birçok kütüphane benzer:

Commons Lang:

org.apache.commons.lang.StringUtils.join(list, conjunction);

Bahar:

org.springframework.util.StringUtils.collectionToDelimitedString(list, conjunction);

125

On Android Kullanabileceğin TextUtils sınıfı.

TextUtils.join(" and ", names);

11
Bunu arıyordum. android üzerinde min api seviye 26String.join gerektirir .
okarakose

49

Hayır, standart Java API'sinde böyle bir kolaylık yöntemi yoktur.

Şaşırtıcı olmayan bir şekilde, Apache Commons, kendiniz yazmak istemiyorsanız , StringUtils sınıflarında böyle bir şey sağlar .


11
Her zaman String'in bir ayrımı olduğu, ancak bir birliği olmadığı beni rahatsız etti. Bir bakıma mantıklı geliyor, ancak String'de bunun için en azından statik bir yöntem olmaması sinir bozucu.
Powerlord

3
Ben seninleyim Bemrose. En azından onlar bize bir verdi isEmpty()yöntemi yerine (statik) join()yöntemi String:): rollseyes: ...
Bart Kiers

41

Java 8'de üç olasılık:

List<String> list = Arrays.asList("Alice", "Bob", "Charlie")

String result = String.join(" and ", list);

result = list.stream().collect(Collectors.joining(" and "));

result = list.stream().reduce((t, u) -> t + " and " + u).orElse("");

27

Bir java 8 toplayıcı ile bu, aşağıdaki kodla yapılabilir:

Arrays.asList("Bill", "Bob", "Steve").stream()
.collect(Collectors.joining(" and "));

Ayrıca, java 8'deki en basit çözüm:

String.join(" and ", "Bill", "Bob", "Steve");

veya

String.join(" and ", Arrays.asList("Bill", "Bob", "Steve"));

21

Bunu yazdım (fasulye ve sömürü için kullanıyorum toString, bu yüzden yazmayın Collection<String>):

public static String join(Collection<?> col, String delim) {
    StringBuilder sb = new StringBuilder();
    Iterator<?> 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 TLD 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, ", ")}

1
Değişen önermek Collection<>için Iterable<>?
Jason S

@JasonS +1. İyi bir nokta, ama okumak stackoverflow.com/questions/1159797/…
gavenkoa

19

Sahip olduğunuz kod, harici kütüphaneler olmadan JDK kullanmak istiyorsanız bunu yapmanın doğru yoludur. JDK'da kullanabileceğiniz basit bir "tek astar" yoktur.

Harici kütüphaneleri kullanabiliyorsanız , Apache Commons kütüphanesinde org.apache.commons.lang.StringUtils sınıfına bakmanızı tavsiye ederim .

Bir kullanım örneği:

List<String> list = Arrays.asList("Bill", "Bob", "Steve");
String joinedResult = StringUtils.join(list, " and ");

17

Bunu başarmanın ortodoks bir yolu, yeni bir işlev tanımlamaktır:

public static String join(String joinStr, String... strings) {
    if (strings == null || strings.length == 0) {
        return "";
    } else if (strings.length == 1) {
        return strings[0];
    } else {
        StringBuilder sb = new StringBuilder(strings.length * 1 + strings[0].length());
        sb.append(strings[0]);
        for (int i = 1; i < strings.length; i++) {
            sb.append(joinStr).append(strings[i]);
        }
        return sb.toString();
    }
}

Örneklem:

String[] array = new String[] { "7, 7, 7", "Bill", "Bob", "Steve",
        "[Bill]", "1,2,3", "Apple ][","~,~" };

String joined;
joined = join(" and ","7, 7, 7", "Bill", "Bob", "Steve", "[Bill]", "1,2,3", "Apple ][","~,~");
joined = join(" and ", array); // same result

System.out.println(joined);

Çıktı:

7, 7, 7 ve Bill ve Bob ve Steve ve [Bill] ve 1,2,3 ve Apple] [ve ~, ~


5
bir yöntem parametresine yöntemin kendisi ile aynı adı vermek muhtemelen en iyi fikir değildir. separatorçok daha müstehcen olur.
ccpizza

10

Java 8 çözümü java.util.StringJoiner

Java 8'in bir StringJoinersınıfı var . Ama yine de biraz kaynatma plakası yazmanız gerekiyor, çünkü Java.

StringJoiner sj = new StringJoiner(" and ", "" , "");
String[] names = {"Bill", "Bob", "Steve"};
for (String name : names) {
   sj.add(name);
}
System.out.println(sj);

String.join () yöntemini daha uygun bir yöntemle kullanırsanız, bir miktar büyük harf yazmanız gerekmez .
Andy Thomas

9

StringUtils sınıfına ve join yöntemine sahip apache commons kütüphanesini kullanabilirsiniz.

Bu bağlantıyı kontrol edin: https://commons.apache.org/proper/commons-lang/javadocs/api.2.0/org/apache/commons/lang/StringUtils.html

Yukarıdaki bağlantının zamanla eski hale gelebileceğini unutmayın, bu durumda en son referansı bulmanıza izin veren "apache commons StringUtils" için web'de arama yapabilirsiniz.

(bu iş parçacığından başvurulur) C # String.Format () ve String.Join () Java eşdeğerleri


7

Bunu yapabilirsiniz:

String aToString = java.util.Arrays.toString(anArray);
// Do not need to do this if you are OK with '[' and ']'
aToString = aToString.substring(1, aToString.length() - 1);

Veya bir astar (sadece '[' ve ']' istemediğinizde)

String aToString = java.util.Arrays.toString(anArray).substring(1).replaceAll("\\]$", "");

Bu yardımcı olur umarım.


1
Bu, seçim kavşağını eklemeyecektir.
hexium

OOPS !! Üzgünüm, bunu fark etmedim.
NawaMan

6

Bir görev hattında saf JDK ile yapmanın eğlenceli bir yolu:

String[] array = new String[] { "Bill", "Bob", "Steve","[Bill]","1,2,3","Apple ][" };
String join = " and ";

String joined = Arrays.toString(array).replaceAll(", ", join)
        .replaceAll("(^\\[)|(\\]$)", "");

System.out.println(joined);

Çıktı:

Bill ve Bob ve Steve ve [Bill] ve 1,2,3 ve Apple] [


Çok mükemmel ve çok eğlenceli bir yol değil!

String[] array = new String[] { "7, 7, 7","Bill", "Bob", "Steve", "[Bill]",
        "1,2,3", "Apple ][" };
String join = " and ";

for (int i = 0; i < array.length; i++) array[i] = array[i].replaceAll(", ", "~,~");
String joined = Arrays.toString(array).replaceAll(", ", join)
        .replaceAll("(^\\[)|(\\]$)", "").replaceAll("~,~", ", ");

System.out.println(joined);

Çıktı:

7, 7, 7 ve Bill ve Bob ve Steve ve [Bill] ve 1,2,3 ve Apple] [


"[Bill]", "1,2,3" ve "Apple] [" ile deneyin. Yaratıcı, ancak yanlış olduğu durumlar var.
Jason S

1
Şimdi "~, ~" ile deneyin. Bu tür mimariyle tamamen kurşun geçirmez bir program yapamazsınız.
Jason S

Evet, biliyorum ... Downvote'u kaldırdım. Ancak, özellikle birkaç yaşında olan bu tür soruları yanıtlamak için burada biraz daha dikkatli düşünmelisiniz. Yanıtlar yalnızca orijinal poster için hemen yararlı olmakla kalmaz, aynı zamanda Google aramalarında da görünür. (Aslında, birkaç yıldır sorular için eski, yeni cevaplar olabilir hiçbir gönderen değer.) Dezavantajları veya hatalar sonradan bağlam dışı buluyorum insanlar için zararlı olabilir var Çözümler.
Jason S

1
Burada benimki gibi diğerlerinden çok iyi bir çözüm değil, gerçekten zengin bilgi ve yan düşünme ile çok şey öğreniyorum. Diğerleri için rahatlayın, her biri kodlarının her satırının ne yaptığını anlamalıdır. Programlamanın bir sanat gibi olduğunu ve hatta her bir kod satırının programcı kişiliği hakkında bir şey ifade ettiğini unutmayın. Ve evet, bu kodu üretimde kullanmayacağım!
Daniel De León


4

Eğer kullanıyorsanız Eclipse Koleksiyonları (eski GS Koleksiyonları ), kullanabilirsiniz makeString()yöntemi.

List<String> list = Arrays.asList("Bill", "Bob", "Steve");

String string = ListAdapter.adapt(list).makeString(" and ");

Assert.assertEquals("Bill and Bob and Steve", string);

ListEclipse Collections türüne dönüştürebilirseniz , bağdaştırıcıdan kurtulabilirsiniz.

MutableList<String> list = Lists.mutable.with("Bill", "Bob", "Steve");
String string = list.makeString(" and ");

Yalnızca virgülle ayrılmış bir dize istiyorsanız, makeString()parametre almayan sürümünü kullanabilirsiniz .

Assert.assertEquals(
    "Bill, Bob, Steve", 
    Lists.mutable.with("Bill", "Bob", "Steve").makeString());

Not: Eclipse Collections için bir komutanım.


3

Java 1.8 akışı ile kullanılabilir,

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
List<String> list = Arrays.asList("Bill","Bob","Steve").
String str = list.stream().collect(Collectors.joining(" and "));

3

DÜZENLE

Ben de fark ettim toString()Altta yatan uygulama sorununu ve ayırıcıyı içeren öğe hakkında ettim ama paranoyak olduğumu düşündüm.

Bu konuda iki yorumum olduğu için cevabımı şu şekilde değiştiriyorum:

static String join( List<String> list , String replacement  ) {
    StringBuilder b = new StringBuilder();
    for( String item: list ) { 
        b.append( replacement ).append( item );
    }
    return b.toString().substring( replacement.length() );
}

Hangi orijinal soruya oldukça benziyor.

Yani tüm kavanozu projenize eklemek istemiyorsanız bunu kullanabilirsiniz.

Orijinal kodunuzda yanlış bir şey olmadığını düşünüyorum. Aslında, herkesin önerdiği alternatif neredeyse aynı görünüyor (bir dizi ek doğrulama yapmasına rağmen)

İşte Apache 2.0 lisansı ile birlikte .

public static String join(Iterator iterator, String separator) {
    // handle null, zero and one elements before building a buffer
    if (iterator == null) {
        return null;
    }
    if (!iterator.hasNext()) {
        return EMPTY;
    }
    Object first = iterator.next();
    if (!iterator.hasNext()) {
        return ObjectUtils.toString(first);
    }

    // two or more elements
    StringBuffer buf = new StringBuffer(256); // Java default is 16, probably too small
    if (first != null) {
        buf.append(first);
    }

    while (iterator.hasNext()) {
        if (separator != null) {
            buf.append(separator);
        }
        Object obj = iterator.next();
        if (obj != null) {
            buf.append(obj);
        }
    }
    return buf.toString();
}

Şimdi biliyoruz, teşekkürler açık kaynak


Bu şimdi çalışacaktır, ancak List.toString () öğesinin gelecekte nasıl davranacağından emin olamazsınız. Asla söz konusu nesne hakkında bazı bilgi dizeleri yazdırmak dışında bir toString () işlem güvenemem. Savunmanızda, bu çözümü öneren tek kişi siz değilsiniz.
Hans Doggen

Listedeki bir öğenin içeriği alt dizeyi içeriyorsa ne olur ", "?
Bart Kiers

@Hans & @Bart: Haklısın. Kimsenin farkına varamayacağını düşündüm: P Cevabımı değiştiriyorum.
OscarRyz

Kullanım durumuna bağlıdır. Hata ayıklama amacıyla toString () yalnızca belirli biçimlendirmeye güvenmemeniz şartıyla IMO'dur. Ve buna rağmen, kodunuz için bir test yazarsanız, gelecekteki değişiklikler yakalanır.
akostadinov

2

Google'ın Guava API'sında da .join () vardır, ancak (diğer yanıtlarda da açık olması gerektiği gibi), Apache Commons burada neredeyse standarttır.


1

Java 8

Collectors.joining(CharSequence delimiter, CharSequence prefix, CharSequence suffix)

yöntemini kullanarak, nullsafe prefix + suffixnull değerleri için .

Aşağıdaki şekilde kullanılabilir:

String s = stringList.stream().collect(Collectors.joining(" and ", "prefix_", "_suffix"))

Collectors.joining(CharSequence delimiter)Yöntem sadece çağırır joining(delimiter, "", "")içten.


0

Bunu Spring Framework'ün StringUtils öğesinden kullanabilirsiniz. Zaten bahsedildiğini biliyorum, ama aslında bu kodu alabilir ve Bahar'a ihtiyaç duymadan hemen çalışır.

// from https://github.com/spring-projects/spring-framework/blob/master/spring-core/src/main/java/org/springframework/util/StringUtils.java

/*
 * Copyright 2002-2017 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
public class StringUtils {
    public static String collectionToDelimitedString(Collection<?> coll, String delim, String prefix, String suffix) {
        if(coll == null || coll.isEmpty()) {
            return "";
        }
        StringBuilder sb = new StringBuilder();
        Iterator<?> it = coll.iterator();
        while (it.hasNext()) {
            sb.append(prefix).append(it.next()).append(suffix);
            if (it.hasNext()) {
                sb.append(delim);
            }
        }
        return sb.toString();
    }
}

-3

Bunu dene:

java.util.Arrays.toString(anArray).replaceAll(", ", ",")
                .replaceFirst("^\\[","").replaceFirst("\\]$","");

1
Muhtemelen soru bir Listenin Array'a göre kullanımını gerektirdiğinden mi? shrug
Nick Coelius

4
Çünkü dizelerinizde bir "," varsa çalışmaz.
Cyrille Pontvieux
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.