【问题标题】:Why is there no String.Empty in Java? [closed]为什么 Java 中没有 String.Empty? [关闭]
【发布时间】:2011-03-27 21:48:08
【问题描述】:

我了解每次输入字符串文字""时,字符串池中都会引用同一个String对象。

但是为什么 String API 不包含 public static final String Empty = "";,所以我可以使用对 String.Empty 的引用?

它至少会节省编译时间,因为编译器会知道引用现有的字符串,而不必检查它是否已经被创建以供重用,对吧?而且我个人认为字符串文字的扩散,尤其是微小的文字,在很多情况下是一种“代码味道”。

那么在没有 String.Empty 的背后有一个宏大的设计原因,还是语言创建者根本不同意我的观点?

【问题讨论】:

  • Aidanc:我认为他的意思是你做outputBlah = "" 之类的事情,他可能更喜欢something == String.Empty 而不是something.Length > 0(你跳过一个空检查。)
  • @Aidanc - 他正在寻找像 Collections.EMPTY_SET 这样的“空成员”,而不是检查字符串“emptiness”的函数。
  • @Aidanc:激发这个灵感的实际上是 'TextBox.setText("");'。
  • 有一个String.isEmpty() 函数...你为什么要String.EMPTY
  • String.isEmpty() 不返回空字符串。

标签: java string


【解决方案1】:

String.EMPTY 是 12 个字符,"" 是两个字符,它们都将在运行时引用内存中完全相同的实例。我不完全确定为什么String.EMPTY 会节省编译时间,事实上我认为是后者。

特别是考虑到Strings 是不可变的,这不像您可以先获取一个空字符串,然后对其执行一些操作 - 最好使用StringBuilder(或StringBuffer,如果您想要线程安全) 并将其转换为字符串。

更新
从您对问题的评论:

实际上是什么启发了这个 TextBox.setText("");

我相信在适当的类中提供一个常量是完全合法的:

private static final String EMPTY_STRING = "";

然后在你的代码中引用它

TextBox.setText(EMPTY_STRING);

这样至少你明确表示你想要一个空字符串,而不是你忘记在你的IDE或类似的东西中填写字符串。

【讨论】:

  • 我仍然会 +1 给你,但我觉得很脏,因为你提到了 StringBuilder,而没有提到十分之九使用 StringBuilder 而不是串联是完全不合适的。
  • 我更喜欢 string.empty,主要是因为它更明确。此外,在某些情况下,可能更难在视觉上区分“”和“'”之类的东西。最后,正如其他人所指出的那样,当我们对实际工作感到厌倦时,它只是那些让我们争论不休的毫无意义的风格事物之一。 =)
  • @Nodel M:关于编译时间,我假设如果在 2 个具有相同字符串值的不同源文件中定义了 2 个字符串文字,那么当编译器遇到第二个时,它需要做某种检查以找出“嘿,我已经从这里知道了这个字符串”。诚然,我不是 java 编译器方面的专家,但怎么可能不是这样呢?而且我认为跳过该检查会导致编译时间的微小改进。
  • @Randolpho 使用字符串连接时,您实际上是在后台使用 StringBuilder。
  • 别忘了,对于 "",我们必须添加 //$NON-NLS-1$,它是 13 个字符 + 2 个来自 ""。所以 String.EMPTY 会在长度和美观上取胜。
【解决方案2】:

使用org.apache.commons.lang.StringUtils.EMPTY

【讨论】:

  • 看起来比空的 "" 更好看也更容易阅读。我希望不只是我。
  • @LakatosGyula - 我想可能是(只有你)。熟练的 Java 程序员在阅读 "" ... 时没有问题,并且大多数 可能会大声反对 EMPTY 的使用,除非在 EMPTY 具有特定领域含义的特定情况下。 (在这种情况下,可能有一个更合适的名称。)
  • @LakatosGyula 不只是你。我从 Java 转向 .NET 开发,String.Empty 是我很高兴在框架中找到的一个特性。我喜欢它的明确性质,而不是一组空引号。
  • @StephenC 当我看到一个空的“”时,我首先想到的是这是一个错误,有人没有完成函数等等。使用 String.EMPTY 我确切地知道开发人员打算返回一个空字符串。
  • 当 linter 说“使用命名常量而不是等等等等”时,这也很有帮助。每个程序员都知道“”并不神奇,但最好不用向客户解释。
【解决方案3】:

如果您想与空字符串进行比较而不担心空值,您可以执行以下操作。

if ("".equals(text))

最终你应该做你认为最清楚的事情。大多数程序员认为“”表示空字符串,而不是有人忘记放入任何内容的字符串。

如果您认为有性能优势,您应该对其进行测试。如果您认为它不值得为自己测试,则说明它确实不值得。

听起来你试图解决一个在 15 多年前设计语言时就已经解决的问题。

【讨论】:

  • 我迟到了,但由于 Java 字符串是不可变的,我相信 JVM 中的所有空字符串只是对同一个 String 对象的不同引用。所以简单地说以下也是正确的:if ("" == text)
  • @AjoyBhatia 问题是您可以创建新的空字符串。 if ("" == new String()) 是假的。更好的测试if(text.isEmpty())
  • @AjoyBhatia - 仅当字符串被保留时。 stackoverflow.com/questions/10578984/what-is-string-interning
【解决方案4】:

不要只说“字符串的内存池以文字形式重用,大小写关闭”。编译器在幕后所做的并不是重点。这个问题是合理的,特别是考虑到它收到的赞成票数量。

这是关于对称性,没有它,API 将更难用于人类。众所周知,早期的 Java SDK 忽略了这条规则,现在为时已晚。以下是我脑海中的一些示例,请随意加入您“最喜欢”的示例:

  • BigDecimal.ZERO,但没有 AbstractCollection.EMPTY、String.EMPTY
  • Array.length 但 List.size()
  • List.add()、Set.add() 和 Map.put()、ByteBuffer.put(),别忘了 StringBuilder.append()、Stack.push()

【讨论】:

  • 即使您将 List 参数命名为 length(),您仍然需要括号,因为它是一种方法。 Array.length 是一个公共的 final 变量,它之所以有效,是因为数组是不可变的。所以你仍然有 Array.length 和 List.length()。我认为这更令人困惑且容易出错。至于 .append() 和 .push(),虽然它们确实执行类似的任务,但我认为它们的命名恰当。附加字符串正是您正在做的事情,但您不会“附加”堆栈,而是推送和弹出值。而 StringBuilder.push() 会隐含 StringBuilder.pop(),这是不可能的。
  • 来自模板/泛型,一致的接口也有助于算法。如果一个算法需要一个集合的长度,length(T) 或 T.length() 就是我们所关心的。类似地,添加到堆栈、列表或字符串的末尾可以通过通用 add() 或 append() 完成。您提到 Java 中的数组是具有公开长度属性的不可变/内置类型。没关系,这并不意味着编译器无法处理或生成长度(T)或 T.length()的代码。 Kotlin 为各种情况生成了许多内在方法。
  • 但是一个一致命名的 length() 方法只允许我们检查长度。这有多大用处?如果您的目标是抽象列表和数组以通过接口以某种方式使用它们,那么您还需要一种一致的方式来读取或写入数据。所以现在您需要生成 get()、set() 和 add() 方法。本质上,您正在创建功能较少的 Array 列表视图。既然 Arrays.asList() 可用、易于使用且轻量级,为什么要重新发明轮子呢? Arrays、Lists、StringBuilders 和 Stacks 都有特定的用途。似乎更好地设计您的界面以使用最合适的方式。
【解决方案5】:

Apache StringUtils 也解决了这个问题。

其他选项的失败:

  • isEmpty() - 不安全。如果 字符串为空,抛出 NPE
  • length() == 0 - 再次不是空安全的。 也不考虑 空白字符串。
  • 与 EMPTY 常量的比较 - 5 月 不是空安全的。空格问题

Granted StringUtils 是另一个可以拖动的库,但它工作得很好,可以节省大量时间和检查空值或优雅处理 NPE 的麻烦。

【讨论】:

  • 所以...似乎唯一安全的选择是糟糕的尤达条件:"".equals(s)?
【解决方案6】:

如果您真的想要一个 String.EMPTY 常量,您可以在您的项目中创建一个名为“Constants”(例如)的实用程序静态最终类。此类将维护您的常量,包括空字符串...

在同样的想法中,您可以创建零、一个 int 常量……它们在 Integer 类中不存在,但就像我评论的那样,写和读会很痛苦:

for(int i=Constants.ZERO; ...) {
    if(myArray.length > Constants.ONE) {
        System.out.println("More than one element");
    }
}

等等

【讨论】:

【解决方案7】:

所有"" 字面量都是同一个对象。为什么要制造所有额外的复杂性?它只是打字时间更长而且不太清楚(编译器的成本是最小的)。由于 Java 的字符串是不可变的对象,因此根本不需要区分它们,除非可能是为了提高效率,但使用空字符串文字没什么大不了的。

如果您真的想要一个 EmptyString 常量,请自己制作。但它只会鼓励更冗长的代码;这样做永远不会有任何好处。

【讨论】:

  • x = String.Emptyx = "" 更能传达意图。后者可能是一个意外遗漏。说从不有任何好处是不正确的。
  • @Jeffrey:我不认为我特别同意。我想这是其中没有硬性规定的事情之一。
  • 是的,需要指出的是,java 编译器会在字符串池中创建新实例之前检查字符串文字是否已经存在。
  • @Jeffrey - 知道这是一个非常古老且主观的讨论。 x = String.Empty 传达了意图,是的。但是假设语言提供了一个常量String.Empty,当您遇到x = "" 时,您仍然对意图非常了解,就好像没有这样的常量一样。您需要保证世界上所有以空字符串为目的的 Java 代码的地方都不使用 "" 以获得您提到的信息增益。具有讽刺意味的是,C# 确实使用了常量并鼓励使用它,所以正如我所说,我知道这是一个非常自以为是的讨论。
  • @chiccodoro - 是的,这是真的。这就是为什么空字符串文字 "" 应该是非法的,以排除意外。我在开玩笑!
【解决方案8】:

要补充 Noel M 所说的内容,您可以查看此问题,此答案表明该常量已被重用。

http://forums.java.net/jive/message.jspa?messageID=17122

字符串常量总是“interned” 所以真的不需要这样 常数。

String s=""; String t=""; boolean b=s==t; // true

【讨论】:

  • 链接已失效。
【解决方案9】:

似乎这是显而易见的答案:

String empty = org.apache.commons.lang.StringUtils.EMPTY;

太棒了,因为“空初始化”代码不再有“魔术字符串”,而是使用常量。

【讨论】:

    【解决方案10】:

    我知道每次输入字符串字面量“”时,字符串池中都会引用同一个字符串对象。
    没有这样的保证。而且你不能在你的应用程序中依赖它,这完全取决于 jvm 来决定。

    还是语言创造者根本不同意我的观点?
    是的。对我来说,这似乎是非常低优先级的事情。

    【讨论】:

    • 没有这样的保证 ...嗯,JLS does state 应该是这样的。
    • @Tim 除非您拨打“实习生”电话,否则不会。以编程方式构造两个相等的大字符串并进行检查很容易。
    • @Tim 例如,重复 a += "a"; 100 次,对 b 做同样的操作并检查。
    • 您说得对,但您描述的不是字符串文字,也不是在编译时可以保证结果的表达式(例如String username = "Bob" + " " + "Smith";)。以编程方式创建的字符串不能保证被实习,除非您明确调用intern(),如您所说。 OP 的场景描述了在整个代码中使用空白字符串文字 "",但这是会发生自动实习的情况。
    • @Tim String a = ""; for(int i = 0; i < 100; i++) {a += "a";} String b = ""; for(int i = 0; i < 100; i++) {b += "b";} a.intern(); b.intern(); 现在 ab 指向 PermGen 中的相同内存位置。见this article
    【解决方案11】:

    迟到的答案,但我认为它为这个话题增加了一些新的东西。

    之前的答案都没有回答原始问题。有些人试图证明缺少常数是合理的,而另一些人则展示了我们可以处理缺少常数的方法。但是没有人为常数的好处提供令人信服的理由,所以它的缺乏仍然没有得到适当的解释。

    常量会很有用,因为它可以防止某些代码错误被忽视。

    假设您有一个庞大的代码库,其中包含数百个对“”的引用。有人在滚动代码时修改了其中一个并将其更改为“”。这样的更改很可能会在生产中被忽视,届时可能会导致一些问题的来源难以检测。

    OTOH,一个名为 EMPTY 的库常量,如果遇到相同的错误,则会为类似 EM PTY 的内容生成编译器错误。

    定义你自己的常数会更好。仍然有人可能会错误地更改它的初始化,但由于它的广泛使用,这种错误的影响比单个用例中的错误更难被忽视。

    这是使用常量而不是字面值所获得的一般好处之一。人们通常认识到,将常量用于数十个地方使用的值可以让您轻松地在一个地方更新该值。很少有人承认的是,这也可以防止该值被意外修改,因为这种变化会随处可见。所以,是的,“”比 EMPTY 短,但 EMPTY 比“”更安全。

    所以,回到最初的问题,我们只能推测语言设计者可能没有意识到为经常使用的文字值提供常量的好处。希望有一天我们会看到在 Java 中添加字符串常量。

    【讨论】:

      【解决方案12】:

      有趣的是,它有多老了,仍然没有像 C# 中那样好的字符串类。 我已经做 Java 几年了,我还在做 c#。当我使用 Java 时,我想念 c# 语言对字符串的完整性。 主要是我想念 string.Empty 和 string.IsNullOrEmpty(string)。 我也很怀念小写字符串类型。

      ++++1 用于将这些东西添加到 Java。所有的解决方法就是这样。 2020 年及以后的快乐编码!

      【讨论】:

        【解决方案13】:

        对于那些声称""String.Empty 可以互换或者"" 更好的人来说,你大错特错了。

        每次你做类似 myVariable = "";您正在创建一个对象的实例。 如果 Java 的 String 对象有一个 EMPTY 公共常量,那么只有 1 个对象实例 ""

        例如:-

        String.EMPTY = ""; //Simply demonstrating. I realize this is invalid syntax
        
        myVar0 = String.EMPTY;
        myVar1 = String.EMPTY;
        myVar2 = String.EMPTY;
        myVar3 = String.EMPTY;
        myVar4 = String.EMPTY;
        myVar5 = String.EMPTY;
        myVar6 = String.EMPTY;
        myVar7 = String.EMPTY;
        myVar8 = String.EMPTY;
        myVar9 = String.EMPTY;
        

        10 (11 包括 String.EMPTY) 指向 1 个对象的指针

        或者:-

        myVar0 = "";
        myVar1 = "";
        myVar2 = "";
        myVar3 = "";
        myVar4 = "";
        myVar5 = "";
        myVar6 = "";
        myVar7 = "";
        myVar8 = "";
        myVar9 = "";
        

        10 个指针指向 10 个对象

        这是低效的,并且在整个大型应用程序中可能很重要。

        也许 Java 编译器或运行时足够高效,可以自动将 "" 的所有实例指向同一个实例,但它可能不会并且需要额外的处理才能做出该决定。

        【讨论】:

        • 错了,根据stackoverflow.com/questions/1881922/… ,“”字符串将从字符串池中重用。
        • 我说它可能会重用同一个对象,如果是这样,效率仍然较低,因为它需要找到那个对象(在字符串池中),那我怎么错了?无论如何,String.Empty 的优越性有几个原因,包括防止诸如 myVar = " "; 之类的错误。和可读性以及我已经说过的性能改进。如果没有其他原因,最好使用常量而不是创建字符串文字;更容易维护代码。
        • 我怀疑您的性能参数是否有效,因为 JLS 表示常量将在编译时被视为文字(docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.10.5)。可读性是一个更好的论据。
        • @AntonySmith - 我想你需要多学习一点 Java 或者你现在知道你的错误了。 Java 字符串是不可变的并且在池中。因此,在 JVM 中,“”只有一个 String 对象,无论它在代码中出现多少次。您可以通过 if (text == "") 检查字符串是否为空
        • 错了。这条评论应该被删除。
        猜你喜欢
        • 1970-01-01
        • 2011-04-09
        • 2011-11-25
        • 2012-09-24
        • 2011-03-09
        • 1970-01-01
        • 2012-01-28
        • 2013-06-21
        • 2013-08-21
        相关资源
        最近更新 更多