wake-up-neo.net

Beste Möglichkeit, Liste von String-Objekten zu verketten?

Was ist der beste Weg, um eine Liste von String-Objekten zu verketten? Ich denke daran, dies zu tun:

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

// add elements

if (sList != null)
{
    String listString = sList.toString();
    listString = listString.subString(1, listString.length() - 1);
}

Ich fand das irgendwie schöner als mit dem StringBuilder/StringBuffer-Ansatz.

Irgendwelche Gedanken/Kommentare?

123
Jagmal

Ihr Ansatz ist von der ArrayList # toString () -Implementierung von Java abhängig.

Die Implementierung ist zwar in der Java-API dokumentiert und es ist unwahrscheinlich, dass sie sich ändert, aber es besteht eine Chance. Es ist viel zuverlässiger, dies selbst zu implementieren (Schleifen, StringBuilders, Rekursion, was immer Sie möchten).

Sicher, dieser Ansatz mag "ordentlicher" oder "zu süß" oder "Geld" erscheinen, ist aber meiner Meinung nach ein schlechterer Ansatz.

43
Jack Leow

Verwenden Sie eine der StringUtils.join -Methoden in Apache Commons Lang.

import org.Apache.commons.lang3.StringUtils;

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

Wenn Sie das Glück haben, Java 8 zu verwenden, ist es noch einfacher. Verwenden Sie einfach String.join .

String result = String.join(", ", list);
299
Jeff Olson

Verwendung von Java 8+

String str = list.stream().collect(Collectors.joining())

oder auch 

String str = String.join("", list);
122
Andrei N

Eine Variation der Antwort von codefin

public static String concatStringsWSep(Iterable<String> strings, String separator) {
    StringBuilder sb = new StringBuilder();
    String sep = "";
    for(String s: strings) {
        sb.append(sep).append(s);
        sep = separator;
    }
    return sb.toString();                           
}
41
Peter Lawrey

Wenn Sie für Android entwickeln, wird TextUtils.join vom SDK bereitgestellt.

25
Chunliang Lyu

Dies ist der eleganteste und sauberste Weg, den ich bisher gefunden habe:

list.stream().collect(Collectors.joining(delimiter));
16

Guava ist eine hübsche Bibliothek von Google:

Joiner joiner = Joiner.on(", ");
joiner.join(sList);
15
andras

Hast du diesen Coding Horror Blog-Eintrag gesehen?

Die traurige Tragödie des Mikro-Optimierungstheaters

Ich bin nicht sicher, ob es "ordentlicher" ist oder nicht, aber aus Sicht der Leistung wird es wahrscheinlich nicht viel ausmachen.

4
sdfx

Ich bevorzuge String.join (Liste) in Java 8

4
Manish Mulani

Anstatt von der ArrayList.toString()-Implementierung abhängig zu sein, können Sie einen Einzeiler schreiben, wenn Sie Java 8 verwenden:

String result = sList.stream()
                     .reduce("", String::concat);

Wenn Sie lieber StringBuffer anstelle von String verwenden, da String::concat eine Laufzeit von O(n^2) hat, können Sie zuerst jede String in StringBuffer konvertieren.

StringBuffer result = sList.stream()
                           .map(StringBuffer::new)
                           .reduce(new StringBuffer(""), StringBuffer::append);
3
Sreekanth

Ich fand es irgendwie schöner als mit dem StringBuilder/StringBuffer Ansatz.

Ich denke, es hängt davon ab, welchen Ansatz Sie gewählt haben. 

Die Methode AbstractCollection # toString () durchläuft einfach alle Elemente und hängt sie an einen StringBuilder an. Ihre Methode kann also einige Zeilen Code einsparen, jedoch auf Kosten zusätzlicher String-Manipulation. Ob dieser Kompromiss gut ist, liegt bei Ihnen.

3
Kevin

Angenommen, es ist schneller, einen Zeiger einfach zu setzen/ein Byte auf null zu setzen (oder Java implementiert StringBuilder # setLength), anstatt eine Bedingung jedes Mal in der Schleife zu überprüfen, um zu sehen, wann das Trennzeichen angehängt wird, könnten Sie diese Methode verwenden:

public static String Intersperse (Collection <?> collection, String-Trennzeichen) 
 {
 StringBuilder sb = new StringBuilder (); 
 für (Objektelement: Sammlung) 
 {
 if (item == null) weiter; 
 sb.append (item) .append (Trennzeichen); 
 } 
 sb.setLength (sb.length () - delimiter.length ()); 
 return sb.toString (); 
}
2
MonkeeSage

ArrayList erbt ihre toString()- Methode von AbstractCollection

public String toString() {
    Iterator<E> i = iterator();
    if (! i.hasNext())
        return "[]";

    StringBuilder sb = new StringBuilder();
    sb.append('[');
    for (;;) {
        E e = i.next();
        sb.append(e == this ? "(this Collection)" : e);
        if (! i.hasNext())
            return sb.append(']').toString();
        sb.append(", ");
    }
}

Die Saite selbst zu bauen, wird wesentlich effizienter.


Wenn Sie die Zeichenfolgen wirklich zuvor in einer Art Liste zusammenfassen möchten, sollten Sie eine eigene Methode bereitstellen, um sie effizient zu verknüpfen, z. so was:

static String join(Collection<?> items, String sep) {
    if(items.size() == 0)
        return "";

    String[] strings = new String[items.size()];
    int length = sep.length() * (items.size() - 1);

    int idx = 0;
    for(Object item : items) {
        String str = item.toString();
        strings[idx++] = str;
        length += str.length();
    }

    char[] chars = new char[length];
    int pos = 0;

    for(String str : strings) {
        str.getChars(0, str.length(), chars, pos);
        pos += str.length();

        if(pos < length) {
            sep.getChars(0, sep.length(), chars, pos);
            pos += sep.length();
        }
    }

    return new String(chars);
}
2
Christoph

Nächste Variante der Antwort von Peter Lawrey ohne Initialisierung einer neuen Zeichenfolge in jeder Schleife

String concatList(List<String> sList, String separator)
{
    Iterator<String> iter = sList.iterator();
    StringBuilder sb = new StringBuilder();

    while (iter.hasNext())
    {
        sb.append(iter.next()).append( iter.hasNext() ? separator : "");
    }
    return sb.toString();
}
2
user2979550

Es scheint mir, dass der StringBuilder schnell und effizient ist.

Die Grundform würde ungefähr so ​​aussehen:

public static String concatStrings(List<String> strings)
{
    StringBuilder sb = new StringBuilder();
    for(String s: strings)
    {
        sb.append(s);
    }
    return sb.toString();       
}

Wenn das zu einfach ist (und wahrscheinlich auch ist), können Sie einen ähnlichen Ansatz verwenden und ein Trennzeichen wie folgt hinzufügen:

    public static String concatStringsWSep(List<String> strings, String separator)
{
    StringBuilder sb = new StringBuilder();
    for(int i = 0; i < strings.size(); i++)
    {
        sb.append(strings.get(i));
        if(i < strings.size() - 1)
            sb.append(separator);
    }
    return sb.toString();               
}

Ich stimme den anderen zu, die auf diese Frage geantwortet haben, wenn sie sagen, dass Sie sich nicht auf die toString () - Methode von Javas ArrayList verlassen sollten.

2
codefin

wenn Sie Json in Ihren Abhängigkeiten haben. Sie können new JSONArray(list).toString() verwenden.

0
programer8

Abhängig von der Notwendigkeit der Leistung und der Menge der hinzuzufügenden Elemente ist dies möglicherweise eine gute Lösung. Wenn die Anzahl der Elemente hoch ist, kann die Neuzuordnung von Arraylist etwas langsamer sein als StringBuilder.

0
georg

In Java 8 können Sie auch einen Reduzierer verwenden, etwa:

public static String join(List<String> strings, String joinStr) {
    return strings.stream().reduce("", (prev, cur) -> prev += (cur + joinStr));
}
0

Importieren Sie diese mit der Functional Java library:

import static fj.pre.Monoid.stringMonoid;
import static fj.data.List.list;
import fj.data.List;

... dann kannst du folgendes machen:

List<String> ss = list("foo", "bar", "baz");
String s = stringMonoid.join(ss, ", ");

Oder generisch, wenn Sie keine Liste mit Strings haben:

public static <A> String showList(List<A> l, Show<A> s) {
  return stringMonoid.join(l.map(s.showS_()), ", ");
}
0
Apocalisp