27

我想知道为什么Java 5 及更高版本使用 String 类中的静态方法提供了一个 printf 样式的格式化程序,如下所示:

public static String format(String format, Object... args)

代替

public String format(Object... args)

这样我们就可以写"%02d".format(5)get05而不是String.format("%02d", 5).

我想如果我可以修改 String 类,我可以添加这个:

public String format(Object... args) {
    return format(this, args)
}

得到相同的结果。

我发现在 C# 中,也使用静态方法而不是实例方法。

我想知道他们为什么决定这样做,但我没有做出解释。实例方法trimsubstring返回一个新的字符串实例,所以他们应该对format.

此外,该DateFormat课程还使用了这个:

public final String format(Date date)

用于格式化日期。因此,如果我们将 DateFormat 的实例视为格式化程序,则 String 的实例也可以用作格式化程序。

有任何想法吗?

4

14 回答 14

13

也许"%02d".format(5)似乎暗示format正在调用该方法的对象是格式字符串。

在这种情况下,格式字符串恰好也是 a String,因此更进一步,人们可能会争辩说所有Strings 都是格式字符串

可能可以通过说String类中的静态方法可用于格式化字符串来避免这种情况,而不是String一般地对所有 s 进行一些隐式声明。

于 2009-04-27T04:50:18.263 回答
7

虽然我不是 Java 的设计者,但我可以告诉你一个将其设为静态的明确原因。

Java 5 出现了许多特性,但有两个值得注意的是:

  • 执行“导入静态”命令的能力,允许在类中轻松使用静态方法,而无需列出其类名。
  • 一种轻松执行 printfs 的静态实用程序方法。

虽然"bla: %d".format("foo"),通过将方法设为静态可以说您可以以对习惯使用printf().

import static java.lang.String.format;

public class Demo {

   public void Test() {

      //Do some stuff

      format("Hey, this is easy to read!");

   }
 }

这就是为什么!通过使用静态导入,printfs 看起来几乎和 C 中的一样。太棒了!

于 2009-04-27T06:54:14.957 回答
5

主要原因可能是Java的设计者不想在String的接口上添加太多东西。使其成为成员函数意味着将其放在字符串上。请记住,非静态方法必须在 String 对象上。

第二个原因是静态格式与 C 的 printf 保持相似,看起来像 printf(FORMAT, ARG1, ARG2...)

另一个原因是格式重载:有一个版本将语言环境作为第一个参数(在字符串之前),因此在字符串对象上执行此操作会很棘手。

于 2009-04-27T04:46:49.067 回答
3

"%02d".format(5) 看起来像 "%02d" 使用格式 5 而不是相反的格式。大多数字符串也不适合作为格式(“hello world”.format(5)?),因此该方法应该为大多数字符串对象抛出异常。

于 2009-04-27T04:57:12.163 回答
3

答案由 Format 方法负责。

至少对我来说,说“格式字符串输入到格式方法”比说“格式对格式字符串进行操作”更合乎逻辑和直观。就是这样,因为我们“通常”将设计时已知的格式字符串传递给 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# 语法的 -ve 投票!

于 2009-04-27T05:08:25.473 回答
2

我真的认为format必须是 String 的实例方法,所以也这样做

  • Python:
    2.6:打印“%s”%(“你好”)
    3.0:打印(“{0}”.format(“你好”))
  • 斯卡拉:
    2.7.6: println("%s".format("你好"))
于 2010-01-17T11:28:52.490 回答
0

调用 strfmt.format(objects) 而不是 String.format(strfmt, objects)

  • 是面向对象的调用,而不是对静态助手的调用。
  • 它的打字时间更短。
  • 它更简单,因为它少了一个参数。
  • 它更容易与代码完成一起使用。如果您从格式字符串开始并点击 . 您将 format() 作为 IDE 中的一个选项。
  • String.format(strfmt, objects) 可能被意外称为 strfmt.format(text, objects) ,它不会做它看起来做的事情。
于 2009-04-27T20:40:29.853 回答
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 都不会抛出任何异常,所以它们都是等价的。

于 2009-04-27T06:31:02.890 回答
0

可能表明它是为了方便而存在的“实用程序”函数,但它实际上并不是字符串的内在函数。也就是说,String"%02d"是一种表示格式的方式,但它实际上并不进行任何格式化。

该方法的存在是为了方便地格式化字符串,但Formatter(执行实际格式化)也可以格式化其他类型的对象(日期等)。

于 2009-04-27T04:49:56.237 回答
0

仅仅因为这个调用让人想起 C 的sprintf函数。

于 2009-04-27T05:10:15.813 回答
0

可能是因为 String 是不可变的,因此此方法必须创建并返回 String 实例的新实例。如果该方法未声明为静态的,您可能希望它修改调用它的 String 实例。

于 2009-04-27T05:37:52.317 回答
0
answer = String.Format("This is format string : {0}", someValue); 
//More readable to me

answer = "This is format string : {0}".Format(someValue);
于 2011-03-12T07:06:28.823 回答
0

只是糟糕的设计。蟒蛇发现它很痛苦。

于 2016-10-13T02:07:48.837 回答
-1

在 C# 中,字符串是不可变的。我认为这在 Java 中也是如此(对此不是 100% 确定)。因此,您不会通过对其调用格式方法来更改字符串,而只是返回带有格式的新字符串。这使它成为类级方法而不是实例级方法,因此它是静态的。您可以使用扩展函数在 C# 中添加实例级外观,但这只是静态函数之上的语法糖。

于 2009-04-27T04:58:15.327 回答