当我在一个Java应用程序中工作时,我最近需要组装一个以逗号分隔的值列表,以传递给另一个web服务,而不知道预先会有多少个元素。我能想到的最好的是这样的:

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缺少join命令,我找不到任何等价的命令。

那么,在Java中最好的方法是什么呢?


当前回答

使用StringBuilder和类Separator

StringBuilder buf = new StringBuilder();
Separator sep = new Separator(", ");
for (String each : list) {
    buf.append(sep).append(each);
}

分隔符包装分隔符。分隔符由Separator的toString方法返回,除非第一次调用返回空字符串!

类分隔符的源代码

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;
    }

}

其他回答

Java 8 之前:

Apache的commons lang在这里是你的朋友——它提供了一个连接方法,非常类似于你在Ruby中引用的方法:

StringUtils.join (java.lang.Iterable字符)


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"

字符串。join(CharSequence分隔符,CharSequence…元素)

String joinedString = String.join(" - ", "04", "05", "06"); // "04 - 05 - 06"

字符串。join(CharSequence分隔符,Iterable<?扩展CharSequence>元素

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"

您可能应该使用带有append方法的StringBuilder来构造结果,但除此之外,这是Java所提供的最好的解决方案。

修正答案Rob Dickerson。

更容易使用:

public static String join(String delimiter, String... values)
{
    StringBuilder stringBuilder = new StringBuilder();

    for (String value : values)
    {
        stringBuilder.append(value);
        stringBuilder.append(delimiter);
    }

    String result = stringBuilder.toString();

    return result.isEmpty() ? result : result.substring(0, result.length() - 1);
}

使用Dollar就像输入一样简单:

String joined = $(aCollection).join(",");

注意:它也适用于数组和其他数据类型

实现

在内部,它使用了一个非常巧妙的技巧:

@Override
public String join(String separator) {
    Separator sep = new Separator(separator);
    StringBuilder sb = new StringBuilder();

    for (T item : iterable) {
        sb.append(sep).append(item);
    }

    return sb.toString();
}

Separator类只在第一次调用时返回空String,然后返回分隔符:

class Separator {

    private final String separator;
    private boolean wasCalled;

    public Separator(String separator) {
        this.separator = separator;
        this.wasCalled = false;
    }

    @Override
    public String toString() {
        if (!wasCalled) {
            wasCalled = true;
            return "";
        } else {
            return separator;
        }
    }
}

使用StringBuilder和类Separator

StringBuilder buf = new StringBuilder();
Separator sep = new Separator(", ");
for (String each : list) {
    buf.append(sep).append(each);
}

分隔符包装分隔符。分隔符由Separator的toString方法返回,除非第一次调用返回空字符串!

类分隔符的源代码

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;
    }

}