Java 从集合/数组/列表创建逗号分隔字符串的最复杂方法?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/205555/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
The most sophisticated way for creating comma-separated Strings from a Collection/Array/List?
提问by maerch
During my work with databases I noticed that I write query strings and in this strings I have to put several restrictions in the where-clause from a list/array/collection. Should look like this:
在我使用数据库的过程中,我注意到我编写了查询字符串,并且在这个字符串中,我必须在列表/数组/集合中的 where 子句中设置一些限制。应该是这样的:
select * from customer
where customer.id in (34, 26, ..., 2);
You can simplify this by reducing this to the question that you have collection of strings and want to create a comma-separated list of this strings in just one string.
您可以通过将其简化为您拥有字符串集合并希望仅在一个字符串中创建此字符串的逗号分隔列表的问题来简化此问题。
My approach I have used so far is something like that:
我到目前为止使用的方法是这样的:
String result = "";
boolean first = true;
for(String string : collectionOfStrings) {
if(first) {
result+=string;
first=false;
} else {
result+=","+string;
}
}
But this is as you can see very ugly. You cannot see what happens there on the first look, especially when the constructed strings (like every SQL query) is getting complicated.
但这是你可以看到的非常丑陋。您第一眼看不到那里发生了什么,尤其是当构造的字符串(如每个 SQL 查询)变得复杂时。
What is your (more) elegant way?
你的(更)优雅的方式是什么?
采纳答案by gimel
Note: This answers was good when it was written 11 years ago, but now there are far better options to do this more cleanly in a single line, both using only Java built-in classes or using a utility library. See other answers below.
注意:这个答案在 11 年前写的时候很好,但是现在有更好的选择可以在一行中更干净地做到这一点,无论是仅使用 Java 内置类还是使用实用程序库。请参阅下面的其他答案。
Since strings are immutable, you may want to use the StringBuilder class if you're going to alter the String in the code.
由于字符串是不可变的,如果您要更改代码中的字符串,您可能需要使用 StringBuilder 类。
The StringBuilder class can be seen as a mutable String object which allocates more memory when its content is altered.
StringBuilder 类可以被看作是一个可变的 String 对象,它在其内容被改变时分配更多的内存。
The original suggestion in the question can be written even more clearly and efficiently, by taking care of the redundant trailing comma:
通过处理多余的尾随逗号,问题中的原始建议可以写得更加清晰和有效:
StringBuilder result = new StringBuilder();
for(String string : collectionOfStrings) {
result.append(string);
result.append(",");
}
return result.length() > 0 ? result.substring(0, result.length() - 1): "";
回答by Dónal
I'm not sure how "sophisticated" this is, but it's certainly a bit shorter. It will work with various different types of collection e.g. Set<Integer>, List<String>, etc.
我不确定这有多“复杂”,但肯定要短一些。它将适用于各种不同类型的集合,例如 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) + ")";
}
Exercise for reader: modify this method so that it correctly handles a null/empty collection :)
读者练习:修改此方法,使其正确处理空/空集合:)
回答by Denis Fradlin
There are some third-party Java libraries that provide string join method, but you probably don't want to start using a library just for something simple like that. I would just create a helper method like this, which I think is a bit better than your version, It uses StringBuffer, which will be more efficient if you need to join many strings, and it works on a collection of any type.
有一些第三方 Java 库提供了字符串连接方法,但您可能不想开始使用库来处理诸如此类的简单事情。我只想创建一个像这样的辅助方法,我认为它比你的版本好一点,它使用 StringBuffer,如果你需要连接许多字符串,它会更有效,并且它适用于任何类型的集合。
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();
}
Another suggestion with using Collection.toString() is shorter, but that relies on Collection.toString() returning a string in a very specific format, which I would personally not want to rely on.
使用 Collection.toString() 的另一个建议较短,但这依赖于 Collection.toString() 以非常特定的格式返回字符串,我个人不想依赖它。
回答by Telcontar
I think it's not a good idea contruct the sql concatenating the where clause values like you are doing :
我认为这不是一个好主意,像你正在做的那样构造连接 where 子句值的 sql :
SELECT.... FROM.... WHERE ID IN( value1, value2,....valueN)
Where valueX
comes from a list of Strings.
当valueX
来自一个字符串列表。
First, if you are comparing Strings they must be quoted, an this it isn't trivial if the Strings could have a quote inside.
首先,如果您正在比较字符串,它们必须被引用,如果字符串内部可以有引号,这并不是微不足道的。
Second, if the values comes from the user,or other system, then a SQL injection attack is possible.
其次,如果这些值来自用户或其他系统,则可能发生 SQL 注入攻击。
It's a lot more verbose but what you should do is create a String like this:
它更加冗长,但您应该做的是创建一个像这样的字符串:
SELECT.... FROM.... WHERE ID IN( ?, ?,....?)
and then bind the variables with Statement.setString(nParameter,parameterValue)
.
然后将变量与Statement.setString(nParameter,parameterValue)
.
回答by Ogre Psalm33
I just looked at code that did this today. This is a variation on AviewAnew's answer.
我只是看了今天这样做的代码。这是 AviewAnew 答案的变体。
collectionOfStrings = /* source string collection */;
String csList = StringUtils.join(collectionOfStrings.toArray(), ",");
The StringUtils( <-- commons.lang 2.x, or commons.lang 3.x link) we used is from Apache Commons.
我们使用的StringUtils(<-- commons.lang 2.x,或commons.lang 3.x 链接)来自Apache Commons。
回答by Tom Hawtin - tackline
The way I write that loop is:
我编写该循环的方式是:
StringBuilder buff = new StringBuilder();
String sep = "";
for (String str : strs) {
buff.append(sep);
buff.append(str);
sep = ",";
}
return buff.toString();
Don't worry about the performance of sep. An assignment is veryfast. Hotspot tends to peel off the first iteration of a loop anyway (as it often has to deal with oddities such as null and mono/bimorphic inlining checks).
不要担心 sep 的性能。一个任务非常快。无论如何,热点往往会剥离循环的第一次迭代(因为它通常必须处理诸如空值和单态/双态内联检查之类的奇怪问题)。
If you use it lots (more than once), put it in a shared method.
如果你经常使用它(不止一次),把它放在一个共享方法中。
There is another question on stackoverflow dealing with how to insert a list of ids into an SQL statement.
关于如何将 id 列表插入 SQL 语句的 stackoverflow 上还有另一个问题。
回答by Julie
Use the Google Guava API's join
method:
使用Google Guava API的join
方法:
Joiner.on(",").join(collectionOfStrings);
回答by silverminken
Just another method to deal with this problem. Not the most short, but it is efficient and gets the job done.
处理这个问题的另一种方法。不是最简短的,但它很有效并且可以完成工作。
/**
* 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();
}
回答by Miguel Ping
I found the iterator idiom elegant, because it has a test for more elements (ommited null/empty test for brevity):
我发现迭代器习语很优雅,因为它对更多元素进行了测试(为简洁起见,省略了空/空测试):
public static String convert(List<String> list) {
String res = "";
for (Iterator<String> iterator = list.iterator(); iterator.hasNext();) {
res += iterator.next() + (iterator.hasNext() ? "," : "");
}
return res;
}
回答by GregUzelac
You may be able to use LINQ (to SQL), and you may be able to make use of the Dynamic Query LINQ sample from MS. http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx
您可以使用 LINQ(到 SQL),并且可以使用 MS 的动态查询 LINQ 示例。http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx