public String appendWithDelimiter( String original, String addition, String delimiter ) {
if ( original.equals( "" ) ) {
return addition;
} else {
return original + delimiter + addition;
}
}
String parameterString = "";
if ( condition ) parameterString = appendWithDelimiter( parameterString, "elementName", "," );
if ( anotherCondition ) parameterString = appendWithDelimiter( parameterString, "anotherElementName", "," );
我意识到这样做并不是特别有效,因为正在创建字符串遍地都是,但我要讲的是优化,而不是优化。
在Ruby中,我可以做这样的事情,感觉更优雅:
parameterArray = [];
parameterArray << "elementName" if condition;
parameterArray << "anotherElementName" if anotherCondition;
parameterString = parameterArray.join(",");
但是由于Java缺少连接命令,所以我找不到任何等效的命令。
那么,用Java做到这一点的最好方法是什么?
#1 楼
Java 8之前的版本:Apache的commons lang是您的朋友-它提供了一种与您在Ruby中所引用的方法非常相似的join方法:
StringUtils.join(java.lang.Iterable,char)
Java 8:
Java 8通过
StringJoiner
和String.join()
开箱即用。以下代码段显示了如何使用它们:StringJoiner
StringJoiner joiner = new StringJoiner(",");
joiner.add("01").add("02").add("03");
String joinedString = joiner.toString(); // "01,02,03"
String.join(CharSequence delimiter, CharSequence... elements))
String joinedString = String.join(" - ", "04", "05", "06"); // "04 - 05 - 06"
String.join(CharSequence delimiter, Iterable<? extends CharSequence> elements)
List<String> strings = new LinkedList<>();
strings.add("Java");strings.add("is");
strings.add("cool");
String message = String.join(" ", strings);
//message returned is: "Java is cool"
评论
我想知道-是否考虑集合中对象的字符串表示形式是否包含定界符本身?
– GreenieMeanie
09年7月8日在20:03
正是我在寻找什么:来自org.apache.commons.lang3.StringUtils包的StringUtils.join(java.util.Collection,String),jar文件是commons-lang3-3.0.1.jar
– Umar
2011年8月30日6:58
在Android上,您也可以使用TextUtils.join()。
–詹姆斯·沃尔德(James Wald)
2012年2月29日在23:07
这不是最好的方法。即使Collection中的Object为null / empty,它也将始终添加char。它很干净,但有时会打印一个双定界符char。
–斯蒂芬·席尔克(Stephan Schielke)
2012年8月30日在8:32
我想知道如果这样的API无法处理空值和空值有什么意义?
– arunwithasmile
8月28日10:43
#2 楼
您可以编写一个适用于java.util.Lists的小联接样式实用程序方法public static String join(List<String> list, String delim) {
StringBuilder sb = new StringBuilder();
String loopDelim = "";
for(String s : list) {
sb.append(loopDelim);
sb.append(s);
loopDelim = delim;
}
return sb.toString();
}
然后像这样使用它:
List<String> list = new ArrayList<String>();
if( condition ) list.add("elementName");
if( anotherCondition ) list.add("anotherElementName");
join(list, ",");
评论
如果已经存在至少两个实现(apache和guava),为什么还要编写自己的方法?
– Timofey
2012年11月24日,11:16
例如,如果希望减少外部依赖关系,这可能很有用。
–托马斯·祖姆布伦
13年2月9日在21:10
我有点喜欢用loopDelim代替条件。这是一种hack,但是它从循环中删除了条件语句。我仍然更喜欢使用迭代器并在循环之前添加第一个元素,但这确实是一个不错的技巧。
–Vlasec
15年1月13日在19:13
您是否可以将intitializer中的List
– k_g
2015年2月22日,0:56
@Tim例如apache不会跳过空白字符串。
–banterCZ
2015年5月19日晚上8:55
#3 楼
在Android上,公用的StringUtils类不可用,因此我使用了android.text.TextUtils.join(CharSequence delimiter, Iterable tokens)
http://developer.android.com/reference/ android / text / TextUtils.html
#4 楼
Google的Guava库具有com.google.common.base.Joiner类,可帮助解决此类任务。示例:
"My pets are: " + Joiner.on(", ").join(Arrays.asList("rabbit", "parrot", "dog"));
// returns "My pets are: rabbit, parrot, dog"
Joiner.on(" AND ").join(Arrays.asList("field1=1" , "field2=2", "field3=3"));
// returns "field1=1 AND field2=2 AND field3=3"
Joiner.on(",").skipNulls().join(Arrays.asList("London", "Moscow", null, "New York", null, "Paris"));
// returns "London,Moscow,New York,Paris"
Joiner.on(", ").useForNull("Team held a draw").join(Arrays.asList("FC Barcelona", "FC Bayern", null, null, "Chelsea FC", "AC Milan"));
// returns "FC Barcelona, FC Bayern, Team held a draw, Team held a draw, Chelsea FC, AC Milan"
这里是有关Guava字符串实用程序的文章。
#5 楼
在Java 8中,您可以使用String.join()
:List<String> list = Arrays.asList("foo", "bar", "baz");
String joined = String.join(" and ", list); // "foo and bar and baz"
也可以查看此答案以获取Stream API示例。
#6 楼
您可以将其概括化,但是正如您所说的,Java中没有join。这可能会更好。
public static String join(Iterable<? extends CharSequence> s, String delimiter) {
Iterator<? extends CharSequence> iter = s.iterator();
if (!iter.hasNext()) return "";
StringBuilder buffer = new StringBuilder(iter.next());
while (iter.hasNext()) buffer.append(delimiter).append(iter.next());
return buffer.toString();
}
评论
我同意这个答案,但是有人可以编辑签名,以便它接受Collection
– Outlaw程序员
08-09-15 at 14:19
更好的是,使用Iterable
–Jason Cohen
08/09/15在18:34
甚至更好,使用Iterable <?扩展Charsequence>,然后您就可以接受StringBuilders和String以及流和其他类似字符串的对象的集合。 :)
–Jason Cohen
08年9月15日在18:35
您想改用StringBuilder。它们相同,只是StringBuffer提供了不必要的线程安全性。有人可以编辑它!
– Casebash
2010年8月11日4:43
此代码有几个错误。 1. CharSequence具有大写的s。 2. s.iterator()返回Iterator <?扩展CharSequence>。 3. Iterable没有isEmpty()方法,请改用next()方法
– Casebash
2010年8月12日,0:42
#7 楼
在Java 8中,您可以这样操作: list.stream().map(Object::toString)
.collect(Collectors.joining(delimiter));
如果列表包含空值,则可以使用:
list.stream().map(String::valueOf)
.collect(Collectors.joining(delimiter))
它还支持前缀和后缀:
list.stream().map(String::valueOf)
.collect(Collectors.joining(delimiter, prefix, suffix));
#8 楼
使用基于java.lang.StringBuilder
的方法! (“可变的字符序列。”)就像您提到的那样,所有这些字符串连接都在各处创建Strings。
StringBuilder
不会这样做。为什么用
StringBuilder
代替StringBuffer
?来自StringBuilder
javadoc:在可能的情况下,建议优先使用此类而不是StringBuffer,因为在大多数实现中它会更快。
评论
是的另外,StringBuffer是线程安全的,而StringBuilder不是。
–琼·昂斯托特(Jon Onstott)
13年3月21日在17:33
#9 楼
我会使用Google收藏夹。有一个不错的加入工具。http://google-collections.googlecode.com/svn/trunk/javadoc/index.html?com / google / common / base / Join.html但是如果我想自己编写它,
package util;
import java.util.ArrayList;
import java.util.Iterable;
import java.util.Collections;
import java.util.Iterator;
public class Utils {
// accept a collection of objects, since all objects have toString()
public static String join(String delimiter, Iterable<? extends Object> objs) {
if (objs.isEmpty()) {
return "";
}
Iterator<? extends Object> iter = objs.iterator();
StringBuilder buffer = new StringBuilder();
buffer.append(iter.next());
while (iter.hasNext()) {
buffer.append(delimiter).append(iter.next());
}
return buffer.toString();
}
// for convenience
public static String join(String delimiter, Object... objs) {
ArrayList<Object> list = new ArrayList<Object>();
Collections.addAll(list, objs);
return join(delimiter, list);
}
}
我认为它与对象集合一起使用效果更好,因为现在您不必先将对象转换为字符串你加入他们。
#10 楼
Apache commons StringUtils类具有一个join方法。#11 楼
Java 8stringCollection.stream().collect(Collectors.joining(", "));
#12 楼
您可以为此使用Java的StringBuilder
类型。还有StringBuffer
,但是它包含通常不需要的额外线程安全逻辑。#13 楼
还有最少的一个(如果您不只是为了加入字符串而将Apache Commons或Guava包含在项目依赖项中)/**
*
* @param delim : String that should be kept in between the parts
* @param parts : parts that needs to be joined
* @return a String that's formed by joining the parts
*/
private static final String join(String delim, String... parts) {
StringBuilder builder = new StringBuilder();
for (int i = 0; i < parts.length - 1; i++) {
builder.append(parts[i]).append(delim);
}
if(parts.length > 0){
builder.append(parts[parts.length - 1]);
}
return builder.toString();
}
评论
使用delim代替File.separator。
– Pradeep Kumar
2015年2月1日,下午1:53
#14 楼
使用StringBuilder和类Separator
StringBuilder buf = new StringBuilder();
Separator sep = new Separator(", ");
for (String each : list) {
buf.append(sep).append(each);
}
分隔符包装定界符。分隔符由Separator的
toString
方法返回,除非在第一次调用时返回空字符串!类
Separator
的源代码public class Separator {
private boolean skipFirst;
private final String value;
public Separator() {
this(", ");
}
public Separator(String value) {
this.value = value;
this.skipFirst = true;
}
public void reset() {
skipFirst = true;
}
public String toString() {
String sep = skipFirst ? "" : value;
skipFirst = false;
return sep;
}
}
评论
如何修改Separator,使其使用StringBuilder而不是连接字符串呢?
–穆罕默德·努尔(Mohamed Nuur)
2011年6月2日22:14
@Mohamed Separator只是返回分隔符,它不连接字符串本身。
–akuaku
2011年6月9日下午0:41
此类分隔符是什么???为什么不只使用简单的String ..?!
– maxxyme
16 Dec 28'在12:14
#15 楼
Java 8本机类型List<Integer> example;
example.add(1);
example.add(2);
example.add(3);
...
example.stream().collect(Collectors.joining(","));
Java 8自定义对象:
List<Person> person;
...
person.stream().map(Person::getAge).collect(Collectors.joining(","));
#16 楼
为什么不编写自己的join()方法?它会将字符串和定界符字符串作为参数集合。在该方法内,对集合进行迭代,并在StringBuffer中建立结果。#17 楼
如果您使用的是Spring MVC,则可以尝试执行以下步骤。import org.springframework.util.StringUtils;
List<String> groupIds = new List<String>;
groupIds.add("a");
groupIds.add("b");
groupIds.add("c");
String csv = StringUtils.arrayToCommaDelimitedString(groupIds.toArray());
这将导致
a,b,c
#18 楼
如果使用的是Eclipse Collections,则可以使用makeString()
或appendString()
。makeString()
返回String
表示形式,类似于toString()
。它具有三种形式
makeString(start, separator, end)
makeString(separator)
默认开始和结束为空字符串makeString()
默认分隔符为", "
(逗号和空格)代码示例:
MutableList<Integer> list = FastList.newListWith(1, 2, 3);
assertEquals("[1/2/3]", list.makeString("[", "/", "]"));
assertEquals("1/2/3", list.makeString("/"));
assertEquals("1, 2, 3", list.makeString());
assertEquals(list.toString(), list.makeString("[", ", ", "]"));
appendString()
与makeString()
相似,但它附加到Appendable
(如StringBuilder
)并且是void
。它具有相同的三种形式,并带有一个附加的第一个参数Appendable。MutableList<Integer> list = FastList.newListWith(1, 2, 3);
Appendable appendable = new StringBuilder();
list.appendString(appendable, "[", "/", "]");
assertEquals("[1/2/3]", appendable.toString());
如果不能将集合转换为Eclipse Collections类型,则只需对其进行调整即可使用相关的适配器。
List<Object> list = ...;
ListAdapter.adapt(list).makeString(",");
注意:我是Eclipse集合的提交者。
#19 楼
您可能应该使用带有StringBuilder
方法的append
来构造结果,但是否则,这与Java必须提供的解决方案一样好。#20 楼
为什么在Java中做的事情与在ruby中做的事情不一样,那就是仅在将所有片段添加到数组之后才创建分隔符分隔的字符串?ArrayList<String> parms = new ArrayList<String>();
if (someCondition) parms.add("someString");
if (anotherCondition) parms.add("someOtherString");
// ...
String sep = ""; StringBuffer b = new StringBuffer();
for (String p: parms) {
b.append(sep);
b.append(p);
sep = "yourDelimiter";
}
您可能希望将for循环移动到单独的帮助器方法中,并且还使用StringBuilder代替StringBuffer...。
编辑:固定了追加的顺序。
评论
是的,为什么要使用StringBuffer而不是StringBuilder(因为您正在使用Java 1.5+)?您的附件也有错误的显示方式。
– Tom Hawtin-大头钉
08/09/15在14:22
#21 楼
使用Java 5变量args,因此您不必将所有字符串显式填充到集合或数组中:import junit.framework.Assert;
import org.junit.Test;
public class StringUtil
{
public static String join(String delim, String... strings)
{
StringBuilder builder = new StringBuilder();
if (strings != null)
{
for (String str : strings)
{
if (builder.length() > 0)
{
builder.append(delim).append(" ");
}
builder.append(str);
}
}
return builder.toString();
}
@Test
public void joinTest()
{
Assert.assertEquals("", StringUtil.join(",", null));
Assert.assertEquals("", StringUtil.join(",", ""));
Assert.assertEquals("", StringUtil.join(",", new String[0]));
Assert.assertEquals("test", StringUtil.join(",", "test"));
Assert.assertEquals("foo, bar", StringUtil.join(",", "foo", "bar"));
Assert.assertEquals("foo, bar, x", StringUtil.join(",", "foo", "bar", "x"));
}
}
#22 楼
对于在Spring上下文中的人来说,他们的StringUtils类也很有用:有许多有用的快捷方式,例如:
collectionToCommaDelimitedString(Collection coll)
collectionToDelimitedString(Collection coll,String delim)
arrayToDelimitedString(Object [] arr,String delim)
等等。
如果您还没有使用Java 8并且已经在Spring上下文中,那么这可能会有所帮助。
与Apache Commons相比,我更喜欢它(尽管也很好) ),以便像这样更轻松地获得收藏支持:
// Encoding Set<String> to String delimited
String asString = org.springframework.util.StringUtils.collectionToDelimitedString(codes, ";");
// Decoding String delimited to Set
Set<String> collection = org.springframework.util.StringUtils.commaDelimitedListToSet(asString);
#23 楼
您可以尝试这样的操作:StringBuilder sb = new StringBuilder();
if (condition) { sb.append("elementName").append(","); }
if (anotherCondition) { sb.append("anotherElementName").append(","); }
String parameterString = sb.toString();
评论
看起来它会在字符串的末尾留下一个逗号,我希望避免。 (当然,由于您知道它的存在,因此可以对其进行修剪,但这也有点不雅观。)
– Sean McMains
08/09/15在14:36
#24 楼
所以基本上是这样的:public static String appendWithDelimiter(String original, String addition, String delimiter) {
if (original.equals("")) {
return addition;
} else {
StringBuilder sb = new StringBuilder(original.length() + addition.length() + delimiter.length());
sb.append(original);
sb.append(delimiter);
sb.append(addition);
return sb.toString();
}
}
评论
这里的问题是他似乎正在调用appendWithDelimiter()分配。解决方案应仅实例一个StringBuffer并使用该单个实例。
– Stu Thompson
08/09/15在14:22
#25 楼
不知道这是否真的更好,但是至少它使用的是StringBuilder,它可能会更有效。如果可以在参数清单之前构建以下列表,下面是一种更通用的方法做任何参数定界。
// Answers real question
public String appendWithDelimiters(String delimiter, String original, String addition) {
StringBuilder sb = new StringBuilder(original);
if(sb.length()!=0) {
sb.append(delimiter).append(addition);
} else {
sb.append(addition);
}
return sb.toString();
}
// A more generic case.
// ... means a list of indeterminate length of Strings.
public String appendWithDelimitersGeneric(String delimiter, String... strings) {
StringBuilder sb = new StringBuilder();
for (String string : strings) {
if(sb.length()!=0) {
sb.append(delimiter).append(string);
} else {
sb.append(string);
}
}
return sb.toString();
}
public void testAppendWithDelimiters() {
String string = appendWithDelimitersGeneric(",", "string1", "string2", "string3");
}
#26 楼
您的方法还不错,但是应该使用StringBuffer而不是+号。 +具有很大的缺点,即为每个单个操作都创建了一个新的String实例。字符串越长,开销越大。因此,使用StringBuffer应该是最快的方法:public StringBuffer appendWithDelimiter( StringBuffer original, String addition, String delimiter ) {
if ( original == null ) {
StringBuffer buffer = new StringBuffer();
buffer.append(addition);
return buffer;
} else {
buffer.append(delimiter);
buffer.append(addition);
return original;
}
}
创建完字符串后,只需在返回的StringBuffer上调用toString()。
评论
在没有充分理由的情况下,在此处使用StringBuffer只会使其变慢。使用+运算符将在内部使用速度更快的StringBuilder,因此,除了使用StringBuffer不需要线程安全之外,他没有其他优势。
–弗雷德里克
09年7月8日在20:14
另外...语句“ +的最大缺点是,为每个单个操作都创建了一个新的String实例”。编译器将根据它们生成StringBuilder.append()调用。
–弗雷德里克
09年7月8日在20:17
#27 楼
如果您的代码未线程化,则应使用StringBuilder,如果不是,则应使用StringBuffer。而不是使用字符串连接。#28 楼
您正在使它变得比必需的更加复杂。让我们从示例的结尾开始:String parameterString = "";
if ( condition ) parameterString = appendWithDelimiter( parameterString, "elementName", "," );
if ( anotherCondition ) parameterString = appendWithDelimiter( parameterString, "anotherElementName", "," );
通过使用StringBuilder而不是String的微小变化,它变为:
StringBuilder parameterString = new StringBuilder();
if (condition) parameterString.append("elementName").append(",");
if (anotherCondition) parameterString.append("anotherElementName").append(",");
...
完成后(我假设您还必须检查其他一些条件),只需确保使用以下命令删除尾部逗号即可:
if (parameterString.length() > 0)
parameterString.deleteCharAt(parameterString.length() - 1);
最后,用所需的字符串
parameterString.toString();
您也可以在第二个调用中替换“,”以追加具有可以设置为任何内容的通用定界符字符串。如果您知道需要附加的事物列表(无条件地),则可以将此代码放在采用字符串列表的方法中。
#29 楼
//Note: if you have access to Java5+,
//use StringBuilder in preference to StringBuffer.
//All that has to be replaced is the class name.
//StringBuffer will work in Java 1.4, though.
appendWithDelimiter( StringBuffer buffer, String addition,
String delimiter ) {
if ( buffer.length() == 0) {
buffer.append(addition);
} else {
buffer.append(delimiter);
buffer.append(addition);
}
}
StringBuffer parameterBuffer = new StringBuffer();
if ( condition ) {
appendWithDelimiter(parameterBuffer, "elementName", "," );
}
if ( anotherCondition ) {
appendWithDelimiter(parameterBuffer, "anotherElementName", "," );
}
//Finally, to return a string representation, call toString() when returning.
return parameterBuffer.toString();
#30 楼
因此,您可能需要做几件事来感觉到您正在寻找的感觉:1)扩展List类-并向其中添加join方法。 join方法将简单地进行串联和添加定界符的工作(这可能是join方法的一个参数)。
2)Java 7似乎将向Java添加扩展方法-它只允许您将特定的方法附加到类上:因此您可以编写该join方法并将其作为扩展方法添加到List或Collection中。
解决方案1可能是唯一的现实现在,一个,虽然因为Java 7还没有发布:)但它应该可以正常工作。
要使用这两个功能,只需将所有项目添加为List或Collection作为通常,然后调用新的自定义方法以“加入”它们。
评论
StringbBilder是必经之路-java.lang.StringBuilder。对于Java 8,请查看以下答案:stackoverflow.com/a/22577623/1115554