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?
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.
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);
Verwendung von Java 8+
String str = list.stream().collect(Collectors.joining())
oder auch
String str = String.join("", list);
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();
}
Wenn Sie für Android entwickeln, wird TextUtils.join
vom SDK bereitgestellt.
Dies ist der eleganteste und sauberste Weg, den ich bisher gefunden habe:
list.stream().collect(Collectors.joining(delimiter));
Guava ist eine hübsche Bibliothek von Google:
Joiner joiner = Joiner.on(", ");
joiner.join(sList);
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.
Ich bevorzuge String.join (Liste) in Java 8
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);
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.
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 (); }
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);
}
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();
}
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.
wenn Sie Json in Ihren Abhängigkeiten haben. Sie können new JSONArray(list).toString()
verwenden.
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
.
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));
}
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_()), ", ");
}