Best way to build a delimited string from a list in java
我有一个对象列表,每个对象都有一个字符串属性。例如,我有一个
1 | 'James', 'Lily', 'Michael' |
考虑到Java似乎没有一个连接方法(而且,这比一个简单的分隔字符串更复杂一些),最直接的方法是什么?我已经尝试了一段时间,但我的代码变得非常混乱,我可以使用一些新的输入。
我在同一个版本中使用了这个(ApacheStringUtils)
1 |
JDK8 lambda的解决方案:
它提供","作为分隔符,以及前缀和后缀。
用最直接的方法。让一个
1 2 3 4 5 6 7 8 | StringBuilder builder = new StringBuilder(); for (int i = 0; i < persons.size(); i++) { builder.append("'").append(persons.get(i)).append("'"); if (i < persons.size() - 1) { builder.append(","); } } String string = builder.toString(); |
或者,您也可以使用
1 2 3 4 5 6 7 8 | StringBuilder builder = new StringBuilder(); for (Iterator<Person> iter = persons.iterator(); iter.hasNext();) { builder.append("'").append(iter.next()).append("'"); if (iter.hasNext()) { builder.append(","); } } String string = builder.toString(); |
注意,与使用
如果您想简单地手动执行,可以这样做:
1 2 3 4 5 6 7 | String mystr =""; for(int i = 0; i < personlist.size(); i++) { mystr +="\'" + personlist.get(i).firstName +"\'"; if(i != (personlist.size() - 1)) { mystr +=","; } } |
现在mystr包含了你的列表。注意,只有当我们不处理列表中的最后一个元素(使用index personlist.size()-1)时才添加逗号。
当然,有更优雅/有效的方法来完成这一点,但在我看来,这一点是最清楚的。
下面是带期望的单元测试:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | import static java.util.Arrays.*; import static org.hamcrest.CoreMatchers.*; import static org.junit.Assert.*; import org.junit.Test; public class JoinerTest { private static final Converter<Person, String> PERSON_CONVERTER = new Converter<Person, String>() { @Override public String convert(Person object) { return object.getFirstName(); } }; @Test public void shouldPresentFirstNames() { // given Person person1 = new Person(); person1.setFirstName("foo"); Person person2 = new Person(); person2.setFirstName("bar"); Joiner<Person> joiner = new Joiner<Person>(",","\'"); // when String firstNames = joiner.join(PERSON_CONVERTER, asList(person1, person2)); // then assertThat(firstNames, is("\'foo\', \'bar\'")); } } |
转换器只是一个接口:
1 2 3 | public interface Converter<F, T> { T convert(F object); } |
最后是细木工:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | public class Joiner<T> { private final String delimiter; private final String quote; public Joiner(String delimiter, String quote) { this.delimiter = delimiter; this.quote = quote; } public String join(Converter<T, String> converter, Iterable<T> objects) { StringBuilder builder = new StringBuilder(); for (T object : objects) { String string = converter.convert(object); builder.append(quote); builder.append(string); builder.append(quote); builder.append(delimiter); } if (builder.length() > 0) { builder.setLength(builder.length() - delimiter.length()); } return builder.toString(); } } |
通过使用不同的转换器,可以很容易地连接不同类型的属性。
我喜欢
1 2 3 4 5 6 7 8 9 10 | if (list != null) { Iterator iter = list.iter(); if (iter.hasNext()) { buffer.append(iter.next()); while (iter.hasNext()) { buffer.append(","); buffer.append(iter.next()); } } } |
它的主要优点是90%的执行时间可能在内部while循环中完成,并且这个解决方案只需要一个比较,就可以确定是否需要退出内部while循环。
其他解决方案也可以工作,但其解决方案如下:
1 2 3 4 5 6 | while (iter.hasNext()) { buffer.append(iter.next()); if (iter.hasNext()) { buffer.append(","); } } |
在while循环中嵌入不必要的if语句。这意味着当最后一个元素是唯一不同的元素时,必须对每个元素进行额外的比较。
通过将用于检查元素是否是最后一个元素的比较移动到一个比较(如果有多个元素),我们只需要为第一个元素以外的每个元素移动附加的","到一个预置的","
我建议您首先在
1 2 3 4 5 6 |
现在您可以使用:
1 2 3 4 5 6 7 | List<Person> list = //... get the list StringBuilder buf = new StringBuilder(list.get(0).toListEntry()); for(int i = 1; i < list.size(); i++) buf.append(" ," + list.get(i).toListEntry()); String stringList = buf.toString(); |
可以循环遍历列表中的每个项,并使用StringBuilder.append()方法将每个名称添加到列表中。这将使用String类,该类每次都会创建一个新的字符串实例,因为字符串是不可变的。
1)初始化字符串生成器2)使用list.size()获取列表中的项目数
1 | int listSize = personList.size() |
3)在字符串中添加第一个开头paren和引号。
1 | StringBuilderinstance.append("('") |
4)在调用append方法之前,使用for循环并将每个名称、结束引号、逗号和开始引号添加到StringBuilder实例中,检查我是否等于listsize如果您在最后一个索引中,请仅追加firstname、quote和结束paren:
1 2 3 4 5 6 7 | for(int i = 0, i<listSize, i++) { if(i == listSize - 1) StringBuilderinstance.append(firstName +"')") else StringBuilderinstance.append(firstName +"', '") } |
在核心Java中实现的一个简单的解决方案(没有外部依赖性)不在循环内进行条件评估,看起来可能是这样的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | private static final char QUOTE = '\''; private static final String SEPARATOR =","; public static String join(List<Person> people) { if (people.isEmpty()) { return""; } final StringBuilder builder = new StringBuilder(); for (Person person : people) { builder.append(QUOTE); builder.append(person.getFirstName()); builder.append(QUOTE); builder.append(SEPARATOR); } builder.setLength(builder.length() - SEPARATOR.length()); return builder.toString(); } |
使用String缓冲区避免了大量的字符串串接,在Java中性能不好。