350

最近、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 には結合コマンドがないため、これに相当するものを見つけることができませんでした。

では、Java でこれを行う最善の方法は何でしょうか?

4

36 に答える 36

604

Java 8 より前:

ここでは、Apache の commons lang が役に立ちます。これは、Ruby で参照されているものと非常によく似た結合メソッドを提供します。

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"
于 2008-09-15T14:13:34.720 に答える
53

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, ",");
于 2008-09-15T14:15:23.750 に答える
49

Androidの場合、commonsのStringUtilsクラスが利用できないため、このために使用しました

android.text.TextUtils.join(CharSequence delimiter, Iterable tokens)

http://developer.android.com/reference/android/text/TextUtils.html

于 2011-05-15T22:16:13.707 に答える
31

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 の文字列ユーティリティに関する記事です。

于 2012-09-18T06:55:47.057 に答える
28

Java 8 では、以下を使用できますString.join()

List<String> list = Arrays.asList("foo", "bar", "baz");
String joined = String.join(" and ", list); // "foo and bar and baz"

ストリーム API の例については、この回答もご覧ください。

于 2014-03-22T12:30:59.070 に答える
20

あなたはそれを一般化することができますが、あなたがよく言うように、Javaには参加がありません。

これはうまくいくかもしれません。

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();
}
于 2008-09-15T14:07:31.897 に答える
15

java.lang.StringBuilder!に基づくアプローチを使用してください。(「文字の可変シーケンス。」)

あなたが言ったように、それらすべての文字列連結は、至る所で文字列を作成しています。 StringBuilderそれをしません。

なぜStringBuilder代わりにStringBufferStringBuilderjavadocから:

可能であれば、ほとんどの実装で高速になるため、このクラスをStringBufferよりも優先して使用することをお勧めします。

于 2008-09-15T14:05:17.487 に答える
10

Google コレクションを使用します。素晴らしいJoin機能があります。
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);
    }
}

オブジェクトを結合する前にオブジェクトを文字列に変換する必要がないため、オブジェクト コレクションの方がうまく機能すると思います。

于 2008-09-15T14:21:38.913 に答える
8

Apache commons StringUtils クラスには join メソッドがあります。

于 2008-09-15T14:17:36.647 に答える
6

Java 8

stringCollection.stream().collect(Collectors.joining(", "));
于 2015-10-31T11:38:39.100 に答える
4

StringBuilder とクラスを使用するSeparator

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

Separator は区切り文字をラップします。toString空の文字列を返す最初の呼び出しでない限り、区切り文字は Separator のメソッドによって返されます!

クラスのソースコード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;
    }

}
于 2008-11-17T22:07:32.153 に答える
3

これにはJavaのStringBuilderタイプを使用できます。もありますStringBufferが、多くの場合不要な追加のスレッドセーフロジックが含まれています。

于 2008-09-15T14:06:13.257 に答える
2

独自のjoin()メソッドを作成してみませんか?これは、文字列と区切り文字列のパラメータコレクションとして使用されます。メソッド内でコレクションを反復処理し、結果をStringBufferに構築します。

于 2008-09-15T14:06:32.023 に答える
2

Eclipse Collectionsを使用している場合は、makeString()またはを使用できますappendString()

makeString()Stringに似た表現を返しますtoString()

3つの形があります

  • 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()に似ていますが、 (like ) と ismakeString()に追加されます。これには同じ 3 つの形式があり、追加の最初の引数である Appendable があります。AppendableStringBuildervoid

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 コレクションのコミッターです。

于 2013-11-16T02:15:13.050 に答える
2

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

于 2016-04-25T11:55:01.727 に答える
1

Spring コンテキストにいる場合は、StringUtilsクラスも便利です。

次のような便利なショートカットがたくさんあります。

  • collectionToCommaDelimitedString(コレクション coll)
  • collectionToDelimitedString(コレクション coll, 文字列 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);
于 2015-01-21T09:44:39.330 に答える
1

StringBuilderメソッドで aを使用しappendて結果を作成する必要がありますが、それ以外の場合は Java が提供する優れたソリューションです。

于 2008-09-15T14:10:23.963 に答える
1

ruby で行っているのと同じことを Java で行ってみませんか? つまり、すべてのピースを配列に追加した後にのみ、区切り文字で区切られた文字列を作成します。

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 ループを別のヘルパー メソッドに移動し、StringBuffer の代わりに StringBuilder を使用することもできます...

編集:追加の順序を修正しました。

于 2008-09-15T14:10:35.150 に答える
1

Java 5 変数引数を使用すると、すべての文字列をコレクションまたは配列に明示的に詰め込む必要がなくなります。

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"));
    }
}
于 2008-09-16T19:36:23.517 に答える
0

次のようなことを試すことができます:

StringBuilder sb = new StringBuilder();
if (condition) { sb.append("elementName").append(","); }
if (anotherCondition) { sb.append("anotherElementName").append(","); }
String parameterString = sb.toString();
于 2008-09-15T14:09:26.900 に答える
0

文字列連結を使用する代わりに、コードがスレッド化されていない場合は StringBuilder を使用し、スレッド化されている場合は StringBuffer を使用する必要があります。

于 2008-09-15T14:29:10.860 に答える
0

これが本当に良いかどうかはわかりませんが、少なくとも 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");
}
于 2008-09-15T14:17:37.037 に答える
0

あなたのアプローチはそれほど悪くはありませんが、+ 記号を使用する代わりに 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() を呼び出すだけです。

于 2008-09-15T14:19:09.683 に答える
0

答えを修正 ロブ・ディッカーソン.

使い方は簡単です:

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);
}
于 2015-03-19T01:30:50.667 に答える
0

izb からのバージョンのわずかな改善 [速度]:

public static String join(String[] strings, char del)
{
    StringBuilder sb = new StringBuilder();
    int len = strings.length;

    if(len > 1) 
    {
       len -= 1;
    }else
    {
       return strings[0];
    }

    for (int i = 0; i < len; i++)
    {
       sb.append(strings[i]).append(del);
    }

    sb.append(strings[i]);

    return sb.toString();
}
于 2010-07-26T19:19:14.010 に答える
0

そのため、探しているように見えるようにするために、いくつかのことを行うことができます。

1) List クラスを拡張し、それに join メソッドを追加します。join メソッドは、区切り文字を連結して追加する作業を単純に行います (これは join メソッドのパラメーターになる可能性があります)。

2) Java 7 は拡張メソッドを Java に追加する予定のようです。これにより、特定のメソッドをクラスにアタッチするだけで済みます。したがって、その結合メソッドを作成し、それを拡張メソッドとして List に追加するか、コレクション。

Java 7 はまだリリースされていないため、ソリューション 1 がおそらく唯一の現実的なソリューションです:) しかし、問題なく動作するはずです。

これらの両方を使用するには、すべてのアイテムを通常どおりリストまたはコレクションに追加し、新しいカスタム メソッドを呼び出してそれらを「結合」します。

于 2008-09-16T19:50:47.147 に答える
0

したがって、基本的には次のようなものです。

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();
    }
}
于 2008-09-15T14:15:58.990 に答える
0

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は、最初に呼び出されたときにのみ空の文字列を返し、その後は区切り文字を返します。

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;
        }
    }
}
于 2010-02-01T19:24:59.827 に答える
0

これを必要以上に複雑にしています。あなたの例の終わりから始めましょう:

String parameterString = "";
if ( condition ) parameterString = appendWithDelimiter( parameterString, "elementName", "," );
if ( anotherCondition ) parameterString = appendWithDelimiter( parameterString, "anotherElementName", "," );

String の代わりに StringBuilder を使用する小さな変更により、これは次のようになります。

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();

また、append の 2 番目の呼び出しの "," を、任意に設定できる一般的な区切り文字列に置き換えることもできます。(無条件に) 追加する必要があることがわかっているリストがある場合は、文字列のリストを受け取るメソッド内にこのコードを配置できます。

于 2008-09-15T14:30:45.880 に答える
0
//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(); 
于 2008-09-15T15:16:44.397 に答える
-2
public static String join(String[] strings, char del)
{
    StringBuffer sb = new StringBuffer();
    int len = strings.length;
    boolean appended = false;
    for (int i = 0; i < len; i++)
    {
        if (appended)
        {
            sb.append(del);
        }
        sb.append(""+strings[i]);
        appended = true;
    }
    return sb.toString();
}
于 2008-09-15T14:09:28.583 に答える