从Collection / Array / List中创build逗号分隔string的最复杂的方法?

在我使用数据库的过程中,我注意到我写了查询string,在这个string中,我必须在list / array / collection的where子句中join一些限制。 应该是这样的:

select * from customer where customer.id in (34, 26, ..., 2); 

你可以简化这个问题,把这个问题简化为你有string集合的问题,并且想用一个string创build一个以逗号分隔的string列表。

我迄今为止使用的方法是这样的:

 String result = ""; boolean first = true; for(String string : collectionOfStrings) { if(first) { result+=string; first=false; } else { result+=","+string; } } 

但是,这是你可以看到非常丑陋的。 你不能看到第一次看到什么发生,特别是当构造的string(如每个SQL查询)变得越来越复杂。

你(更)优雅的方式是什么?

由于string是不可变的,所以如果要在代码中改变string,可能需要使用StringBuilder类。

StringBuilder类可以被看作是一个可变的String对象,当它的内容被改变时它会分配更多的内存。

通过照顾冗余的尾随逗号 ,可以更加清楚和有效地写出问题中原来的build议:

  StringBuilder result = new StringBuilder(); for(String string : collectionOfStrings) { result.append(string); result.append(","); } return result.length() > 0 ? result.substring(0, result.length() - 1): ""; 

使用Google Guava API的join方法:

 Joiner.on(",").join(collectionOfStrings); 

我只是看了今天的代码。 这是AviewAnew答案的一个变种。

 collectionOfStrings = /* source string collection */; String csList = StringUtils.join(collectionOfStrings.toArray(), ","); 

我们使用的StringUtils (< – commons.lang 2.x或commons.lang 3.x链接 )来自Apache Commons 。

我写这个循环的方式是:

 StringBuilder buff = new StringBuilder(); String sep = ""; for (String str : strs) { buff.append(sep); buff.append(str); sep = ","; } return buff.toString(); 

不要担心sep的性能。 一个任务是非常快的。 无论如何,热点往往会剥离循环的第一个迭代(因为它经常要处理诸如空和单/双态内联检查之类的奇怪事情)。

如果你使用它(不止一次),把它放在一个共享的方法。

在stackoverflow处理如何将一个id列表插入到SQL语句中还有另外一个问题。

从Java 8开始,您可以使用:

  • String String.join(CharSequence delimiter, CharSequence... elements)
  • String String.join(CharSequence delimiter, Iterable<? extends CharSequence> elements)
  • 如果你想取非String ,并将它们join到String ,可以使用Collectors.joining(CharSequence delimiter) ,例如:

    String joined = anyCollection.stream().map(Object::toString).collect(Collectors.joining(","));

我发现迭代器的成语优雅,因为它有一个testing更多的元素(为了简洁,ommited null /空testing):

 public static String convert(List<String> list) { String res = ""; for (Iterator<String> iterator = list.iterator(); iterator.hasNext();) { res += iterator.next() + (iterator.hasNext() ? "," : ""); } return res; } 

有很多手动解决scheme,但我想重申和更新上面的朱莉的答案。 使用google集合Joiner类 。

 Joiner.on(", ").join(34, 26, ..., 2) 

它处理var args,iterables和数组,并正确处理多个char的分隔符(不像gimemel的答案)。 如果你需要的话,它也会处理你的列表中的空值。

这是一个令人难以置信的通用版本,我从以前的build议的组合:

 public static <T> String buildCommaSeparatedString(Collection<T> values) { if (values==null || values.isEmpty()) return ""; StringBuilder result = new StringBuilder(); for (T val : values) { result.append(val); result.append(","); } return result.substring(0, result.length() - 1); } 
 String.join(", ", collectionOfStrings) 

在Java8 API中可用。

替代(不需要添加谷歌番石榴依赖):

 Joiner.on(",").join(collectionOfStrings); 

你可以试试

 List collections = Arrays.asList(34, 26, "...", 2); String asString = collection.toString(); // justValues = "34, 26, ..., 2" String justValues = asString.substring(1, asString.length()-1); 

我认为这不是一个好主意构造sql连接你的where子句值正在做:

SELECT …. FROM …. WHERE ID IN(value1,value2,… valueN)

其中valueX来自一个string列表。

首先,如果您要比较string,则必须引用它,如果string可以在内部引用,这并不是微不足道的。

其次,如果值来自用户或其他系统,那么SQL注入atack是可能的。

这是更详细的,但你应该做的是创build一个像这样的string:

SELECT …. FROM …. WHERE ID IN(?,?,….?)

然后将variables绑定到Statement.setString(nParameter,parameterValue)

到目前为止,这将是最短的解决scheme,除了使用番石榴或Apache Commons

 String res = ""; for (String i : values) { res += res.isEmpty() ? i : ","+i; } 

很好用0,1和n元素列表。 但是你需要检查空列表。 我在GWT中使用这个,所以我没有StringBuilder。 而对于只有几个元素的简短列表,其他地方也可以;)

如果有人偶然发现了这个问题,我已经使用Java 8 reduce()添加了一个简单的变体。 它还包括其他一些已经提到的解决scheme:

 import java.util.Arrays; import java.util.List; import org.apache.commons.lang.StringUtils; import com.google.common.base.Joiner; public class Dummy { public static void main(String[] args) { List<String> strings = Arrays.asList("abc", "de", "fg"); String commaSeparated = strings .stream() .reduce((s1, s2) -> {return s1 + "," + s2; }) .get(); System.out.println(commaSeparated); System.out.println(Joiner.on(',').join(strings)); System.out.println(StringUtils.join(strings, ",")); } } 

只是另一种方法来处理这个问题。 不是最短的,但它是有效的,并完成工作。

 /** * Creates a comma-separated list of values from given collection. * * @param <T> Value type. * @param values Value collection. * @return Comma-separated String of values. */ public <T> String toParameterList(Collection<T> values) { if (values == null || values.isEmpty()) { return ""; // Depending on how you want to deal with this case... } StringBuilder result = new StringBuilder(); Iterator<T> i = values.iterator(); result.append(i.next().toString()); while (i.hasNext()) { result.append(",").append(i.next().toString()); } return result.toString(); } 

有一些第三方Java库提供了string连接方法,但是您可能不想仅仅为了简单的事情而开始使用库。 我只是创build一个像这样的帮助方法,我认为它比你的版本好一点,它使用了StringBuffer,如果你需要连接多个string,效率会更高,而且它可以处理任何types的集合。

 public static <T> String join(Collection<T> values) { StringBuffer ret = new StringBuffer(); for (T value : values) { if (ret.length() > 0) ret.append(","); ret.append(value); } return ret.toString(); } 

另一个使用Collection.toString()的build议较短,但依赖于Collection.toString()以非常特定的格式返回一个string,我个人不希望依赖它。

如果你使用Spring,你可以这样做:

 StringUtils.arrayToCommaDelimitedString( collectionOfStrings.toArray() ) 

(包org.springframework.util)

在Android中你应该使用这个:

 TextUtils.join(",",collectionOfStrings.toArray()); 

我不确定这是多么“复杂”,但它肯定有点短。 它可以处理各种不同types的集合,例如Set <Integer>,List <String>等。

 public static final String toSqlList(Collection<?> values) { String collectionString = values.toString(); // Convert the square brackets produced by Collection.toString() to round brackets used by SQL return "(" + collectionString.substring(1, collectionString.length() - 1) + ")"; } 

练习读者 :修改这个方法,以便正确处理空/空集合:)

使代码难看的是第一种情况下的特殊处理。 这个小代码中的大部分代码都是专注于代码的日常工作,而不是处理这个特殊情况。 这就是像gimel的解决scheme,通过移动循环外的特殊处理。 有一个特殊情况(呃,你可以看到特殊情况的开始和结束 – 但只有其中一个需要特别处理),所以在循环内处理它是不必要的复杂。

连接'方法'在数组中可用,扩展AbstractCollections但不覆盖toString()方法的类(几乎与java.util中的所有集合一样)

例如:String s = java.util.Arrays.toString(collectionOfStrings.toArray());

s = s.substing(1,s.length() – 1); // []保证在那里


这是相当奇怪的方式,因为它只适用于像数据sql明智的数字。

我刚刚签入了我的图书馆美元testing:

 @Test public void join() { List<Integer> list = Arrays.asList(1, 2, 3, 4, 5); String string = $(list).join(","); } 

它只使用一个静态导入$创build一个stream利的包装清单/数组/string/等。

注意

使用范围前面的列表可以重写为$(1, 5).join(",")

关于INexpression式的好处是,如果有重复的值,它不会改变结果。 所以,只需复制第一个项目并处理整个列表。 这假定列表中至less有一个项目。 如果没有项目,我build议先检查一下,然后再执行SQL。

这将做的伎俩,是明显的在做什么,不依赖于任何外部库:

 StringBuffer inString = new StringBuffer(listOfIDs.get(0).toString()); for (Long currentID : listOfIDs) { inString.append(",").append(currentID); } 

虽然我认为你最好的select是使用Guava的Joiner,但是如果我用手工编写代码的话,我会发现这个方法比第一个标志更优雅,或者把最后一个逗号切掉。

 private String commas(Iterable<String> strings) { StringBuilder buffer = new StringBuilder(); Iterator<String> it = strings.iterator(); if (it.hasNext()) { buffer.append(it.next()); while (it.hasNext()) { buffer.append(','); buffer.append(it.next()); } } return buffer.toString(); } 

如果你有一个数组,你可以这样做:

 Arrays.asList(parameters).toString() 

您可能能够使用LINQ(到SQL),并且您也许能够使用来自MS的dynamic查询LINQ示例。 http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx

 java.util.List<String> lista = new java.util.ArrayList<String>(); lista.add("Hola"); lista.add("Julio"); System.out.println(lista.toString().replace('[','(').replace(']',')')); $~(Hola, Julio) 
 String commaSeparatedNames = namesList.toString().replaceAll( "[\\[|\\]| ]", "" ); // replace [ or ] or blank 

string表示由集合元素的列表组成,它们按其迭代器返回的顺序包含在方括号中(“[]”)。 相邻的元素由字符“,”(逗号和空格)分隔。

AbstractCollection javadoc

List token = new ArrayList(result); 最终的StringBuilder builder =新的StringBuilder();

  for (int i =0; i < tokens.size(); i++){ builder.append(tokens.get(i)); if(i != tokens.size()-1){ builder.append(TOKEN_DELIMITER); } } 

builder.toString();

另一种select,根据我在这里看到(稍作修改)。

 public static String toString(int[] numbers) { StringBuilder res = new StringBuilder(); for (int number : numbers) { if (res.length() != 0) { res.append(','); } res.append(number); } return res.toString(); } 

有一个简单的方法。 你可以在一行中得到你的结果。

 String memberIdsModifiedForQuery = memberIds.toString().replace("[", "(").replace("]", ")"); 

要获得完整的想法检查下面的代码

  public static void main(String[] args) { List<Integer>memberIds=new ArrayList<Integer>(); //This contain member ids we want to process //adding some sample values for example memberIds.add(3); memberIds.add(4); memberIds.add(2); String memberIdsModifiedForQuery = memberIds.toString().replace("[", "(").replace("]", ")"); //here you will get (3,4,5) That you can directly use in query System.out.println(memberIdsModifiedForQuery); String exampleQuery="select * from customer where customer.id in "+memberIdsModifiedForQuery+" "; }