连接string对象列表的最佳方法是什么?
串联一个String对象列表的最佳方法是什么? 我正在考虑这样做:
List<String> sList = new ArrayList<String>(); // add elements if (sList != null) { String listString = sList.toString(); listString = listString.subString(1, listString.length() - 1); }
我不知何故发现这比使用StringBuilder / StringBuffer方法更整齐。
任何想法/意见?
你的方法依赖于Java的ArrayList#toString()实现。
虽然这个实现在Java API中有logging,而且不太可能改变,但它有可能。 自己实现这个要可靠得多(循环,StringBuilders,recursion,无论你喜欢什么)。
当然,这种做法可能看起来是“整洁的”,也可能是“太甜”或“金钱”,但在我看来,这是一种糟糕的做法。
使用Apache Commons Lang中的一个StringUtils.join方法。
import org.apache.commons.lang3.StringUtils; String result = StringUtils.join(list, ", ");
如果你有幸使用Java 8,那么更简单一点就是使用String.join
String result = String.join(", ", list);
使用Java 8+
String str = list.stream().collect(Collectors.joining())
甚至
String str = String.join("", list);
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(); }
如果您正在为Android开发,那么SDK提供了TextUtils.join
。
番石榴是来自Google的漂亮图书馆:
Joiner joiner = Joiner.on(", "); joiner.join(sList);
这是迄今为止我发现的最优雅和最干净的方式:
list.stream().collect(Collectors.joining(delimiter));
你看过这个Coding Horror博客条目吗?
微型优化剧院的悲剧悲剧
我不确定它是否“整洁”,但从性能的angular度来看,这可能并不重要。
我更喜欢Java 8中的String.join(list)
如果你正在使用java 8,你可以写一个单行的,而不是依赖于ArrayList.toString()
实现:
String result = sList.stream() .reduce("", String::concat);
如果您更喜欢使用StringBuffer
而不是String,因为String::concat
的运行时间为O(n^2)
,您可以先将每个String
转换为StringBuffer
。
StringBuffer result = sList.stream() .map(StringBuffer::new) .reduce(new StringBuffer(""), StringBuffer::append);
我不知何故发现这比使用StringBuilder / StringBuffer方法更整齐。
我想这取决于你采取了什么方法。
AbstractCollection#toString()方法只遍历所有元素,并将它们附加到StringBuilder。 所以你的方法可能会节省几行代码,但代价是额外的string操作。 这种权衡是否合理取决于你。
在我看来,StringBuilder将是快速和高效的。
基本forms看起来像这样:
public static String concatStrings(List<String> strings) { StringBuilder sb = new StringBuilder(); for(String s: strings) { sb.append(s); } return sb.toString(); }
如果这太简单了(可能是这样),你可以使用类似的方法,像这样添加一个分隔符:
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(); }
我同意那些回答这个问题的人,他们说你不应该依赖Java的ArrayList的toString()方法。
假设只是移动一个指针/设置一个字节为空(或者Java实现StringBuilder#setLength)会更快,而不是每次通过循环检查一个条件以查看何时附加分隔符,那么可以使用以下方法:
public static String Intersperse(Collection <?> collection,String delimiter) { StringBuilder sb = new StringBuilder(); for(对象项目:集合) { 如果(item == null)继续; sb.append(item).append(delimiter); } sb.setLength(sb.length() - delimiter.length()); 返回sb.toString(); }
Peter Lawrey的答案的下一个变化,没有在每个循环中初始化一个新的string
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(); }
ArrayList
inheritance自AbstractCollection
toString()
– 方法,即:
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(", "); } }
build立自己的string会更有效率。
如果你真的想在某种列表中预先聚合string,你应该提供自己的方法来有效地join它们,例如:
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); }
在Java 8中,你也可以使用reducer,如下所示:
public static String join(List<String> strings, String joinStr) { return strings.stream().reduce("", (prev, cur) -> prev += (cur + joinStr)); }
根据性能需求和要添加的元素数量,这可能是一个好的解决scheme。 如果元素的数量很高, Arraylist
的内存重新分配可能比StringBuilder
慢一点。
使用Functional Java库,导入这些:
import static fj.pre.Monoid.stringMonoid; import static fj.data.List.list; import fj.data.List;
…那么你可以这样做:
List<String> ss = list("foo", "bar", "baz"); String s = stringMonoid.join(ss, ", ");
或者,通用的方法,如果你没有一个string列表:
public static <A> String showList(List<A> l, Show<A> s) { return stringMonoid.join(l.map(s.showS_()), ", "); }
如果你有你的依赖json。你可以使用new JSONArray(list).toString()