Javaで同等のSprintf


284

Printfは1.5リリースでJavaに追加されましたが、出力をファイルではなく文字列に送信する方法を見つけることができないようです(Cでsprintfが行うことです)。誰でもこれを行う方法を知っていますか?

回答:


473
// Store the formatted string in 'result'
String result = String.format("%4d", i * j);

// Write the result to standard output
System.out.println( result );

形式とその構文を見る


28

文字列は不変の型です。それらを変更することはできません。新しい文字列インスタンスのみを返します。

そのため、次のように呼び出す必要があるため、インスタンスメソッドを使用したフォーマットはほとんど意味がありません。

String formatted = "%s: %s".format(key, value);

元のJavaの作成者(および.NETの作成者)は、ターゲットを変更するのではなく、フォーマットメソッドを呼び出して入力文字列を渡すため、この状況では静的メソッドがより適切であると判断しました。

これがformat()インスタンスメソッドとして馬鹿げている理由の例です。.NET(およびおそらくJava)ではReplace()、インスタンスメソッドです。

あなたはこれを行うことができます:

 "I Like Wine".Replace("Wine","Beer");

ただし、文字列は不変であるため、何も起こりません。Replace()新しい文字列を返そうとしますが、何も割り当てられていません。

これは、次のような多くの一般的な新人のミスを引き起こします:

inputText.Replace(" ", "%20");

繰り返しになりますが、何も起こらず、代わりに次のことを行う必要があります。

inputText = inputText.Replace(" ","%20");

ここで、文字列が不変であることを理解すれば、それは完全に理にかなっています。そうしないと、混乱してしまいます。の適切な場所は、静的メソッドとしてのReplace()場所format()ですString

 inputText = String.Replace(inputText, " ", "%20");

今、何が起こっているのかについて疑問はありません。

本当の問題は、なぜこれらのフレームワークの作成者は、1つをインスタンスメソッドに、もう1つを静的メソッドにすべきだと決めたのですか?私の意見では、どちらも静的メソッドとしてよりエレガントに表現されています。

あなたの意見に関係なく、真実はあなたが静的バージョンを使用して間違いを犯す傾向が少なく、コードが理解しやすいことです(隠された問題はありません)。

もちろん、インスタンスメソッドとして完璧ないくつかのメソッドがあります。String.Length()を使用してください。

int length = "123".Length();

この状況では、「123」を変更しようとしているのではなく、検査して長さを返すだけであることは明らかです。これは、インスタンスメソッドの完全な候補です。

不変オブジェクトのインスタンスメソッドの簡単なルール:

  • 同じタイプの新しいインスタンスを返す必要がある場合は、静的メソッドを使用します。
  • それ以外の場合は、インスタンスメソッドを使用します。

4
どういうわけか、フォーマット文字列を変更することを提案していたアイデアを思いついたようです。不変性は非常に基本的であるため、誰かが文字列を変更することを期待する可能性を考えたことはありません。
エリクソン2008年

4
通常、フォーマット文字列は「価格は%4d」ではなく「%4d」に近いため、混乱の可能性はまだたくさんあります。静的メソッドに対して何がありますか?:)
FlySwat

44
この回答は質問とは関係がないようです。
スティーブマクロード

2
答えはJavaでもありません
。.NET

3
-1。反対投票b / c接線です。そして、必ずしも不変のものに最適なスタイルではありません。このスタイルは、特にチェーン操作の場合、単純なメソッド呼び出しよりも詳細です。また、静的メソッドを呼び出すため、実行時のポリモーフィズムを放棄します。これは重要です。YMMV。
Andrew Janke 14

3

どちらのソリューションもprintfをシミュレートしますが、方法は異なります。たとえば、値を16進文字列に変換するには、次の2つの解決策があります。

  • format()、に最も近いsprintf()

    final static String HexChars = "0123456789abcdef";
    
    public static String getHexQuad(long v) {
        String ret;
        if(v > 0xffff) ret = getHexQuad(v >> 16); else ret = "";
        ret += String.format("%c%c%c%c",
            HexChars.charAt((int) ((v >> 12) & 0x0f)),
            HexChars.charAt((int) ((v >>  8) & 0x0f)),
            HexChars.charAt((int) ((v >>  4) & 0x0f)),
            HexChars.charAt((int) ( v        & 0x0f)));
        return ret;
    }
  • replace(char oldchar , char newchar)、やや高速ですがかなり制限されています:

        ...
        ret += "ABCD".
            replace('A', HexChars.charAt((int) ((v >> 12) & 0x0f))).
            replace('B', HexChars.charAt((int) ((v >>  8) & 0x0f))).
            replace('C', HexChars.charAt((int) ((v >>  4) & 0x0f))).
            replace('D', HexChars.charAt((int) ( v        & 0x0f)));
        ...
  • 次のように、charをret1つずつ追加することで構成される3番目の解決策があります(charは互いに加算される数値です)。

    ...
    ret += HexChars.charAt((int) ((v >> 12) & 0x0f)));
    ret += HexChars.charAt((int) ((v >>  8) & 0x0f)));
    ...

...しかし、それは本当に醜いでしょう。


すべての素晴らしいアイデアですが、あなたのコードを同僚に理解できない書き込み専用コードに変えます。
ベン・

0

PrintStreamを使用して、OutputStreamであるすべてに対してprintfを実行できます。どういうわけか、文字列ストリームに出力します:

PrintStream ps = new PrintStream(baos);
ps.printf("there is a %s from %d %s", "hello", 3, "friends");
System.out.println(baos.toString());
baos.reset(); //need reset to write new string
ps.printf("there is a %s from %d %s", "flip", 5, "haters");
System.out.println(baos.toString());
baos.reset();

文字列ストリームは、次のByteArrayOutputStreamのように作成できます。

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