我想知道为什么 Java 5及以上版本提供了一个printf风格的格式化程序,在类String中使用静态方法,如下所示:
public static String format(String format, Object... args)
而不是
public String format(Object... args)
这样我们就可以写"%02d".format(5)
来获取05
而不是String.format("%02d", 5)
。
我想象如果我可以修改String类,我可以添加它:
public String format(Object... args) {
return format(this, args)
}
得到相同的结果。
我发现在C#中,也使用静态方法代替实例方法。
我想知道为什么他们决定这样做,但我没有得到解释。实例方法trim
和substring
返回一个新的字符串实例,因此他们应该使用format
完成相同的操作。
此外,DateFormat
类也使用此:
public final String format(Date date)
用于格式化日期。因此,如果我们将DateFormat的实例视为格式化程序,则String的实例也可以用作格式化程序。
有什么想法吗?
答案 0 :(得分:11)
或许"%02d".format(5)
似乎暗示调用format
方法的对象是格式字符串。
在这种情况下,格式字符串恰好也是String
,所以进一步说明,可以说所有String
都是格式字符串。
可以通过说String
类中的静态方法可以用来格式化字符串,而不是通常对所有String
做一些隐式声明来避免这种情况。
答案 1 :(得分:7)
虽然我不是Java的设计师,但我可以告诉你一个明确的理由让它变得静止。
Java 5推出了许多功能,但有两个注意事项:
虽然能够通过使方法静态来说"bla: %d".format("foo"),
是一件好事,但你可以使用格式,这种格式对于习惯于printf()
的C程序员来说非常熟悉和清晰。< / p>
import static java.lang.String.format;
public class Demo {
public void Test() {
//Do some stuff
format("Hey, this is easy to read!");
}
}
这就是原因!通过使用静态导入,printfs看起来几乎与他们在C. Awesome中完全一样!
答案 2 :(得分:5)
主要原因可能是Java的设计者不想在String的接口上添加太多东西。使它成为一个成员函数意味着将它放在字符串上。请记住,非静态方法必须在String对象上。
第二个原因是静态格式与C的printf保持相似, 看起来像printf(FORMAT,ARG1,ARG2 ......)
另一个原因是格式重载:有一个版本将locale作为第一个参数(在字符串之前),因此在字符串对象上执行此操作会很棘手。
答案 3 :(得分:3)
“%02d”.format(5)看起来像“%02d”使用格式5而不是相反的格式。大多数字符串也不适合作为格式(“hello world”.format(5)?),因此该方法应该为大多数字符串对象抛出异常。
答案 4 :(得分:3)
答案取决于格式化方法。
至少在我看来,“格式字符串输入到格式方法”比说“格式字符串格式化”更合乎逻辑和直观。就是这样,因为我们“通常”将格式字符串(在设计时已知)传递给Format。相反,对于Trim,我们“通常”传递变量字符串,其值在设计时是未知的。
因此,使格式化方法保持静态,使代码读取更加直观。请看下面的(C#)。
answer = String.Format("This is format string : {0}", someValue);
//More readable to me
answer = "This is format string : {0}".Format(someValue);
编辑:尽管我使用过C#示例代码,但它很适用于Java。我得到了投票使用C#语法!
答案 5 :(得分:2)
我真的认为format
必须是String的实例方法,所以
2.6: print "%s" % ("Hello")
3.0: print("{0}".format("Hello"))
2.7.6: println("%s".format("Hello"))
答案 6 :(得分:1)
调用strfmt.format(objects)而不是String.format(strfmt,objects)
答案 7 :(得分:0)
可能是为了表明它是一个“实用程序”函数,为方便起见而存在,但它实际上并不是String的内在函数。也就是说,字符串"%02d"
是一种表示格式的方式,但它实际上并不进行任何格式化。
该方法可以方便地格式化字符串,但Formatter(执行实际格式化)也可以格式化其他类型的对象(日期等)。
答案 8 :(得分:0)
仅仅因为这个电话让人想起C的sprintf
功能。
答案 9 :(得分:0)
可能是因为String是不可变的,因此该方法必须创建并返回String实例的新实例。如果该方法未声明为static,您可能希望它修改已调用它的String实例。
答案 10 :(得分:0)
我认为Java并不是强制要求任何构造类似于其他任何构造,甚至是C ++。任何采用的都必须如此,因为开发人员接受它。此外,“他们使其与其他东西相似”这样的论点并没有解释为什么他们不只是制作一个实例方法版本,他们用原始包装器做这个(除了实例toString()方法,他们有静态版本)。
这就是我的想法:
在正常情况下,两种形式都是等价的,但假设我们有类似的东西:
String invalidFormat = "%invalid"; // or something else that is invalid
然后我们打电话:
String.format(invalidFormat, anything);
// "anything" is indeed anything....
无效成为参数,Java通过抛出IllegalArgumentException实例来澄清这一点(即使在Formatter的情况下,也有很多种类)。
然而,在某些事情上:
invalidFormat.format(anything);
无效的不再是参数。问题现在在于它被调用的实例,因此被更好地描述为“无效状态”(不是Java的“IllegalStateException”,它具有完全不同的用法)。但是因为字符串是不可变的,所以这个所谓的“状态”永远不会改变,所以它总是作为一种格式保持无效,即使它是一个有效的简单字符串。
将此与java.lang.Long进行比较。两个版本的toString都不会抛出任何异常,所以它们都是等价的。
答案 11 :(得分:0)
answer = String.Format("This is format string : {0}", someValue);
//More readable to me
answer = "This is format string : {0}".Format(someValue);
答案 12 :(得分:0)
糟糕的设计。蟒蛇发现它很痛苦。
答案 13 :(得分:-1)
在C#中,strings are immutable。我认为在Java中也是如此(不是100%肯定)。因此,您不是通过调用格式方法来更改字符串,而是仅返回带有格式的新字符串。这使它成为类级方法而不是实例级方法,因此它是静态的。您可以使用扩展函数在C#中添加实例级别Facade,但这只是静态函数之上的语法糖。