Java中的Sprintf等效项


284

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

Answers:


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方法并传入输入字符串。

这是一个为什么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");

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

真正的问题是,这些框架的作者为什么决定一个应该是实例方法,而另一个应该是静态方法呢?我认为,这两种方法都可以更好地表达为静态方法。

不管您的意见如何,事实是,使用静态版本时您不太容易犯错误,并且代码更易于理解(没有隐藏的陷阱)。

当然,有些方法是完美的实例方法,例如String.Length()

int length = "123".Length();

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

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

  • 如果需要返回相同类型的新实例,请使用静态方法。
  • 否则,请使用实例方法。

4
我看到您以某种方式得到了我建议修改格式字符串的想法。我从未考虑过有人会期望String发生更改的可能性,因为它们的不变性非常重要。
erickson

4
看到格式字符串通常更像是“ The price is%4d”,而不是“%4d”,我仍然看到很多潜在的混淆。您对静态方法有什么看法?:)
FlySwat

44
这个答案似乎与问题无关。
Steve McLeod

2
答案是不连渣,似乎更贴近.NET
Photodeus

3
-1。向下投票b / c是切线的。不一定是不可变的最佳样式。这种样式比简单的方法调用更为冗长,尤其是对于链式操作而言。而且它放弃了运行时多态性,因为它调用了静态方法,这一点很重要。YMMV。
Andrew Janke

3

两种解决方案都可以模拟printf,但是方式不同。例如,要将值转换为十六进制字符串,您有以下两种解决方案:

  • 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 ret逐个加(char是互相加成的数字!),例如:

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

...但是那真的很丑。


所有的好主意,但是却将您的代码变成了同事无法理解的只写代码。

0

您可以对带有PrintStream的OutputStream进行任何处理。像这样,打印到字符串流中:

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();
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.