298

Printf 在 1.5 版本中被添加到 Java 中,但我似乎无法找到如何将输出发送到字符串而不是文件(这是 sprintf 在 C 中所做的)。有谁知道如何做到这一点?

4

5 回答 5

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

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

查看格式及其语法

于 2008-09-05T23:06:53.820 回答
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()是 where format()is,作为 的静态方法String

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

现在毫无疑问会发生什么。

真正的问题是,为什么这些框架的作者决定一个应该是实例方法,而另一个应该是静态的?在我看来,两者都更优雅地表示为静态方法。

不管你怎么看,事实是你使用静态版本更不容易出错,而且代码更容易理解(No Hidden Gotchas)。

当然也有一些方法非常适合作为实例方法,以 String.Length()

int length = "123".Length();

在这种情况下,很明显我们并没有尝试修改“123”,我们只是检查它,并返回它的长度。这是实例方法的完美候选。

我对不可变对象的实例方法的简单规则:

  • 如果需要返回相同类型的新实例,请使用静态方法。
  • 否则,使用实例方法。
于 2008-10-13T17:34:00.413 回答
5

从 Java 13 开始,您在 String 上有formatted 1 个方法,该方法与文本块一起添加为预览功能2。您可以使用它代替String.format()

Assertions.assertEquals(
   "%s %d %.3f".formatted("foo", 123, 7.89),
   "foo 123 7.890"
);
于 2020-07-03T00:04:08.173 回答
2

两种解决方案都可以模拟 printf,但方式不同。例如,要将值转换为十六进制字符串,您有以下 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)));
        ...
    
  • 还有第三种解决方案,只需将 charret逐个添加(char 是彼此相加的数字),例如:

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

......但这真的很难看。

于 2015-07-14T11:47:15.673 回答
1

您可以使用 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());

这将输出以下文本,有 3 个朋友打招呼 字符串流可以像这样创建 ByteArrayOutputStream:

ByteArrayOutputStream baos = new ByteArrayOutputStream();

您可以累积多种格式:

PrintStream ps = new PrintStream(baos);
ps.printf("there is a %s from %d %s ", "hello", 3, "friends");
ps.printf("there are %d % from a %", 2, "kisses", "girl");
System.out.println(baos.toString());

此输出有 3 个朋友打招呼 有一个女孩有 2 个吻
在 ByteArrayOutputStream 上调用重置以生成干净的新字符串

ps.printf("there is a %s from %d %s", "flip", 5, "haters");
baos.reset(); //need reset to write new string
ps.printf("there are %d % from a %", 2, "kisses", "girl");
System.out.println(baos.toString());

输出将是一个女孩的 2 个吻

于 2019-08-05T13:46:31.730 回答