C#のString.Format()およびString.Join()に相当するJava


111

これは初心者向けの質問ですが、JavaでのC#の文字列操作に相当するものはありますか?

具体的には、とについて話しString.FormatているString.Join


String.formatがありますが、自分の結合をロールする必要があります。
Omar Kooheji 2008年

1
join()の場合、私はこの回答が好きです:stackoverflow.com/a/6116469/562139
scorpiodawg

回答:


92

Java Stringオブジェクトにはformatメソッド(1.5以降)がありますが、メソッドはありませんjoin

まだ含まれていない便利な文字列ユーティリティメソッドを取得するには、org.apache.commons.lang.StringUtilsを使用できます。


13
googleコレクション:google-collections.googlecode.comにもジョイナーがあります。
ロン

10
ロンのコメントに関する参考までに、google-collectionsは少し前にGuavaに名前が変更されました。
Kevin Bourrillion、2011

3
Java 8がString.join()メソッドを導入していることを反映するには、この回答を更新する必要があります。
Duncan Jones

46

String.format。参加に関しては、あなた自身で書く必要があります:

 static String join(Collection<?> s, String delimiter) {
     StringBuilder builder = new StringBuilder();
     Iterator<?> iter = s.iterator();
     while (iter.hasNext()) {
         builder.append(iter.next());
         if (!iter.hasNext()) {
           break;                  
         }
         builder.append(delimiter);
     }
     return builder.toString();
 }

上記はhttp://snippets.dzone.com/posts/show/91からのものです


6
より正確には、jdk1.4以下の場合はStringBuffer、jdk1.5以降の場合はStringBuilderです。後者は同期されないため、少し高速です。
VonC、2008年

2
2つのiter.hasNext()呼び出しの代わりに、通常はデリミタを追加してから、「buf.substring(0、buf.length()-delimeter.length())を返します」。
Vilmantas Baranauskas

2
デリミタを回避するために早期に終了することで、少しだけ効率化できます:while(true)(add_iter; if(!iter.hasNext())break; add_delim;}
13ren 2009年


29

Java 8以降、 join()、Stringクラスの2つのクラスメソッドとして使用できるようになりました。どちらの場合も、最初の引数は区切り文字です。

個別CharSequenceのを追加の引数として渡すことができます

String joined = String.join(", ", "Antimony", "Arsenic", "Aluminum", "Selenium");
// "Antimony, Arsenic, Alumninum, Selenium"

または、あなたは渡すIterable<? extends CharSequence>ことができます:

List<String> strings = new LinkedList<String>();
strings.add("EX");
strings.add("TER");
strings.add("MIN");
strings.add("ATE");

String joined = String.join("-", strings);
// "EX-TER-MIN-ATE"

Java 8は、次のStringJoinerように使用できる新しいクラスも追加します。

StringJoiner joiner = new StringJoiner("&");
joiner.add("x=9");
joiner.add("y=5667.7");
joiner.add("z=-33.0");

String joined = joiner.toString();
// "x=9&y=5667.7&z=-33.0"


12

次のように、文字列に可変引数を使用することもできます。

  String join (String delim, String ... data) {
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < data.length; i++) {
      sb.append(data[i]);
      if (i >= data.length-1) {break;}
      sb.append(delim);
    }
    return sb.toString();
  }

4

参加に関しては、これは少し複雑に見えないかもしれません:

public String join (Collection<String> c) {
    StringBuilder sb=new StringBuilder();
    for(String s: c)
        sb.append(s);
    return sb.toString();
}

私は好きなだけJava 5構文を使用することができません(それを信じるかどうか、最近1.0.xを使用しています)。 。

編集の追加:文字列の追加は遅くなる可能性がありますが、GUIコードまたはいくつかの短時間実行ルーチンで作業している場合、.005秒または.006を取るかどうかは実際には関係ないため、「joinMe」というコレクションがある場合は既存の文字列 "target"に追加したい場合、これをインライン化するだけで恐ろしいことではありません。

for(String s : joinMe)
    target += s;

これは非常に非効率的(そして悪い習慣)ですが、何千もの文字列が存在するか、これが巨大なループ内にあるか、コードが本当にパフォーマンスクリティカルでない限り、何も知覚できません。

さらに重要なのは、覚えやすく、短く、すばやく読みやすいことです。パフォーマンスは、常にデザインの選択において自動的に勝つとは限りません。


forループは正しいですが、Collection <String>にする必要もあります。そうでない場合は、「for(Object o:c)」と言う必要があります。cのすべてが文字列であることを保証できないためです。
マイケルマイヤーズ

良い点は、私はジェネリックでさらに錆びています。私はそれを編集します。
ビル・K

インラインで連結する場合、文字列+文字列+文字列の場合、コンパイラは実際に値を追加するためにStringBuilderを使用します。for-loopメソッドで2番目にあるかどうか、コンパイラーが同じことをするかどうかは疑問です。
Spencer Kormos、2008年

@Spencer K:これはStringBuilderを使用しますが、反復ごとに新しいものを作成します(ほとんどの場合、最も効率的な方法ですが、コンパイラーはそれをどのように認識すべきですか?)。JITコンパイラーが実行時にそれを最適化するかどうかはわかりません。
マイケルマイヤーズ

2
あ、ちょっと待って。+ =話してるの?ええ、それは吸う。現在私の回答にあるループと追加はStringBuilderを使用しており、それが私が話していることです。+ =はループ内で使用したくないという点で大幅に改善されていますが、バグがあるほどではありませんが、がらくたのように動作する可能性があります(バグは、パフォーマンスの問題で一般的に使用される用語ではありません-少なくとも私の20年間のプログラミングで)。また、JITはこれを大幅に改善できます。しかし、私はそれに依存しません。
Bill K

4

これはかなり単純な答えです。+=コードが少ないので使用し、オプティマイザに変換させてStringBuilderください。この方法を使用すると、ループ内の「is last」チェックを実行する必要がなく(パフォーマンスの向上)、最後の区切り文字を削除することを心配する必要がありません。

        Iterator<String> iter = args.iterator();
        output += iter.hasNext() ? iter.next() : "";
        while (iter.hasNext()) {
            output += "," + iter.next();
        }

1
サードパーティのライブラリを含まない非常にエレガントなソリューション!
デニスイツコビッチ2014年

2

単純な結合関数を追加するためにApacheライブラリ全体をインポートしたくなかったので、これが私のハックです。

    public String join(String delim, List<String> destinations) {
        StringBuilder sb = new StringBuilder();
        int delimLength = delim.length();

        for (String s: destinations) {
            sb.append(s);
            sb.append(delim);
        }

        // we have appended the delimiter to the end 
        // in the previous for-loop. Let's now remove it.
        if (sb.length() >= delimLength) {
            return sb.substring(0, sb.length() - delimLength);
        } else {
            return sb.toString();
        }
    }

@MrSnowflake標準の文字列ビルダーにはメソッド「removeCharAt(int index)」がありますか?実行中のバージョンに表示されません
NSjonas 14

@NSjonas-はい、私の答えに対する彼の編集は間違っています。removeCharAt存在しませんし、全体の機能は、もはや文字列を返す...これを修正します。
Martin Konecny 14

一方で、この現在の解決策は、「空のリストを渡すと、インデックスが範囲外の例外になる」
NSjonas '31

delimが1文字を超える場合、編集して右の長さを取得しました。また、本当に必要な最初の文字ではなく、最後の文字をトリミングしていた問題を修正しました
NSjonas '31 / 07/31

フィードバックのためのThx。更新しました。
Martin Konecny、2014

1

複数の文字列を1つに結合(連結)する場合は、StringBuilderを使用する必要があります。使用するよりもはるかに優れています

for(String s : joinMe)
    target += s;

StringBuilderは同期を使用しないため、StringBufferよりもパフォーマンスが若干向上します。

このような汎用ユーティリティメソッドの場合、(最終的には)多くの状況で何度も呼び出されるため、効率的にして、多くの一時オブジェクトを割り当てないでください。私たちは数多くのさまざまなJavaアプリのプロファイルを作成してきましたが、ほとんどの場合、文字列の連結と文字列/ char []の割り当てにはかなりの時間/メモリを消費します。

再利用可能なコレクション-> stringメソッドは、最初に必要な結果のサイズを計算し、次にその初期サイズでStringBuilderを作成します。これにより、文字列を追加するときに使用される内部char []の不必要な二重化/コピーが回避されます。


re:サイズを事前に計算する:これが機能するとき、それは素晴らしいことです。常に可能であるとは限りません。毎回バッファーサイズを2倍にする(または実際に固定係数を掛ける)と、n log nのパフォーマンスが得られるというどこかで読んだことを覚えています。一般的なケースでは、代わりに、連結する予定のすべての文字列のリストを作成します。ArrayListを使用する場合、(シーケンスの長さが事前にわかっていない限り)再度コピーが行われます。LinkedListを使用する場合は、ノードオブジェクトでより多くのRAMとガベージコレクションを使用します。時々あなたは勝つことができない。やってみて!
Ian

上記の例/問い合わせでは、結合する文字列の順序付けられたコレクションまたは配列を想定しています。内部のchar []配列の成長は通常、その結果ということも、サイズを事前計算することで、あなたは余分な未使用の文字を避ける。
DJB

1

私は自分で書いた:

public static String join(Collection<String> col, String delim) {
    StringBuilder sb = new StringBuilder();
    Iterator<String> iter = col.iterator();
    if (iter.hasNext())
        sb.append(iter.next().toString());
    while (iter.hasNext()) {
        sb.append(delim);
        sb.append(iter.next().toString());
    }
    return sb.toString();
}

しかしCollection、JSPではサポートされていないため、タグ関数については次のように記述しました。

public static String join(List<?> list, String delim) {
    int len = list.size();
    if (len == 0)
        return "";
    StringBuilder sb = new StringBuilder(list.get(0).toString());
    for (int i = 1; i < len; i++) {
        sb.append(delim);
        sb.append(list.get(i).toString());
    }
    return sb.toString();
}

そして.tldファイルに入れます:

<?xml version="1.0" encoding="UTF-8"?>
<taglib version="2.1" xmlns="http://java.sun.com/xml/ns/javaee"
    <function>
        <name>join</name>
        <function-class>com.core.util.ReportUtil</function-class>
        <function-signature>java.lang.String join(java.util.List, java.lang.String)</function-signature>
    </function>
</taglib>

そして、JSPファイルで次のように使用します。

<%@taglib prefix="funnyFmt" uri="tag:com.core.util,2013:funnyFmt"%>
${funnyFmt:join(books, ", ")}



0

ここにはString.Joinの過度に複雑な実装がたくさんあります。Java 1.8がなく、新しいライブラリをインポートしたくない場合は、以下の実装で十分です。

public String join(Collection<String> col, String delim) {
    StringBuilder sb = new StringBuilder();
    for ( String s : col ) {
        if ( sb.length() != 0 ) sb.append(delim);
        sb.append(s);
    }
    return sb.toString();
}

-1
ArrayList<Double> j=new ArrayList<>; 
j.add(1);
j.add(.92);
j.add(3); 
String ntop=j.toString(); //ntop= "[1, 0.92, 3]" 

したがって、基本的に、文字列ntopはコレクション全体の値をカンマ区切りと角かっこで格納します。


1
これが質問のどの部分に答えるかわかりませんか?文字列のビットをビットごとに配列に追加する予定がない限り、これはString.formatではありません。[1,0.92,3]は、汎用文字列.joinほど用途が広くありません。
Omar Kooheji 2013年

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.