【问题标题】:Why is String's format(Object... args) defined as a static method?为什么 String 的 format(Object... args) 被定义为静态方法?
【发布时间】:2009-04-27 04:43:19
【问题描述】:

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

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#中,也使用了静态方法而不是实例方法。

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

此外,DateFormat 类也使用这个:

public final String format(Date date)

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

有什么想法吗?

【问题讨论】:

  • 这并不重要,但我只是想知道这背后是否有任何理由。既然我们写的不是String.substring("abcde", 3, 2)而是"abcde".substring(3, 2),我想format也应该有类似的调用方法。
  • 同理,为什么是Collections.sort(List),而不是List.sort()。我从来没有那么喜欢过。
  • 我为此创建了一个错误报告。它被拒绝了,但它确实包含了一个解释。我去看看。我认为主要的一点是格式化注射器在语义上基本上与普通注射器不同。
  • 这种小小的无聊每天都让我发疯。

标签: java string format printf


【解决方案1】:

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

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

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

【讨论】:

  • 真的,谢谢!这让我想起了与此具有相似模式的公共布尔匹配(字符串正则表达式)。
【解决方案2】:

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

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

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

虽然能够通过将方法设为静态来表示 "bla: %d".format("foo"), 会很好,但您可以以对习惯于 printf() 的 C 程序员来说非常熟悉和简洁的方式使用格式。

import static java.lang.String.format;

public class Demo {

   public void Test() {

      //Do some stuff

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

   }
 }

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

【讨论】:

  • 不错!我没有想到。虽然我认为你想说的是 java.lang.String.format 而不是 java.lang.String.printf ;)
  • 是的,我写的时候有点累。修复它:)
【解决方案3】:

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

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

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

【讨论】:

  • "不想在 String 的接口上添加太多东西" - 为什么这是一件坏事?向类的接口添加方法根本不会影响性能,也不会减少任何 JVM 实现的工作,因为它们仍然必须实现 String.format。 “有一个版本将语言环境作为第一个参数” - 这可以通过使用不同的名称来完成,例如String.localeFormat(...).
【解决方案4】:

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

【讨论】:

    【解决方案5】:

    答案由 Format 方法负责。

    至少对我来说,说“格式字符串输入到 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 投票!

    【讨论】:

    • 这是一个 Java 问题。在 C# 示例中使用 Java 语法可能会有所帮助。
    • 嗨,dlamblin 虽然它被标记为 Java 问题,但它也适用于 C#,正如提问者所指出的那样。我认为,降低声誉是不公平的,因为我的回答(请在查看我的示例代码之前准备好文本部分)也适用于 Java!我请求你删除反对票。
    【解决方案6】:

    我真的认为format 必须是 String 的实例方法,所以也是如此

    • 蟒蛇:
      2.6: 打印 "%s" % ("Hello")
      3.0: print("{0}".format("Hello"))
    • 斯卡拉:
      2.7.6: println("%s".format("Hello"))

    【讨论】:

    • 在 Java 中:System.out.printf("%s%n", "Hello");我大部分时间都使用 printf() 而不是 String.format()。
    • 这如何回答这个问题?
    • 这个答案只是为了宣传自己喜欢的POW。
    【解决方案7】:

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

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

    【讨论】:

      【解决方案8】:

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

      【讨论】:

      • 你知道这就是原因......怎么办?
      • @Danon 10 年前,这个社区基本上处于测试阶段,对于什么是好的问题或答案有不同的规则。我曾经问过 Joshua Bloch,他告诉我 Gosling 在“Java 语言规范”中提到或写了一些在这方面类似于 C 的意图。
      【解决方案9】:

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

      【讨论】:

        【解决方案10】:

        我认为 Java 没有强制要求任何类似于其他任何东西的结构,即使是 C++。任何采用的东西都必须如此,因为开发人员接受它。此外,诸如“他们使它类似于其他东西”之类的论点并不能解释为什么他们不只是制作实例方法版本,而是使用原始包装器来做到这一点(除了实例 toString() 方法之外,它们还有静态版本)。

        这是我的想法:

        在正常情况下,两种形式是等价的,但假设我们有类似的东西:

        String invalidFormat = "%invalid"; // or something else that is invalid
        

        然后我们调用:

        String.format(invalidFormat, anything);
        // "anything" is indeed anything....
        

        invalid 成为参数,Java 通过抛出 IllegalArgumentException 的实例来澄清这一点(即使在 Formatter 的情况下,也有很多种)。

        但是,在类似的情况下:

        invalidFormat.format(anything);
        

        无效的不再是论据。现在的问题在于它被调用的实例,因此可能更好地描述为“无效状态”(而不是 Java 的“IllegalStateException”,它具有完全不同的用法)。但是因为字符串是不可变的,所以这个所谓的“状态”永远不会改变,所以它作为一种格式总是保持无效,即使它是一个有效的简单字符串。

        将其与 java.lang.Long 进行比较。两个版本的 toString 都不会抛出任何异常,所以它们都是等价的。

        【讨论】:

        • 那么为什么不将java.util.IllegalFormatException 改为不扩展java.lang.IllegalArgumentException,而是成为它自己的独立类呢?我认为通过插入对象来告诉字符串自己格式化是有意义的,但随后让它返回一个错误,即字符串不是有效的格式。
        • @RadonRosborough 我们很难在不破坏现有代码的情况下改变 java.lang.IllegalArgumentException 的行为?
        【解决方案11】:

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

        • 是一个面向对象的调用 调用静态助手。
        • 打字更短。
        • 它更简单,因为它少了一个参数。
        • 它更易于与代码完成一起使用。如果你从 格式化字符串并点击 .你得到 format() 作为 IDE 中的一个选项。
        • String.format(strfmt, objects) 可能被意外称为 strfmt.format(text, objects) 其中 不会做看起来应该做的事情。

        【讨论】:

        • 这如何回答这个问题?
        【解决方案12】:
        answer = String.Format("This is format string : {0}", someValue); 
        //More readable to me
        
        answer = "This is format string : {0}".Format(someValue);
        

        【讨论】:

          【解决方案13】:

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

          【讨论】:

            【解决方案14】:

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

            【讨论】:

            • -1 因为字符串类中的每个函数都可以这样说,而不仅仅是格式。
            • 别怪我。 String 上的大多数方法(至少在 c# 中)并不意味着任何突变。那些暗示突变的都返回一个字符串。但是,使用格式很明显,没有理由强迫您首先制作字符串。
            • 无论哪种方式,您都在制作字符串。这对回答这个问题没有任何帮助。没什么大不了的。对于其他一些方法,例如 length(),“询问”字符串是很有意义的(从 OO 的角度来看)。要求 String 格式化某些对象是否有意义? ggf31416 正确地注释了大多数字符串 /can't/ 格式化任何东西。所以,也许不是。
            • 无论哪种方式,您都在制作字符串。这对回答这个问题没有任何帮助。个人觉得没多大关系对于其他一些方法,例如 length(),“询问”字符串是很有意义的(从 OO 的角度来看)。要求 String 格式化某些对象是否有意义? ggf31416 正确地注释了大多数字符串 /can't/ 格式化任何东西。所以,也许不是。
            猜你喜欢
            • 2013-12-11
            • 1970-01-01
            • 2014-08-21
            • 2013-10-20
            • 2010-10-18
            • 1970-01-01
            • 2015-08-04
            • 2012-08-27
            • 2014-06-22
            相关资源
            最近更新 更多