StringUtils.EMPTY 是否被推荐使用?

110

您是否使用StringUtils.EMPTY代替""

我的意思是无论是作为返回值还是设置字符串变量的值。我并不是说用于比较,因为在那里我们使用StringUtils.isEmpty()

12个回答

139

当然不是。

常量通常有以下3个用途:

  1. 记录值的含义(使用常量名称+ javadoc进行文档化)
  2. 在客户端之间同步共同的值。
  3. 提供快捷方式以避免某些初始化成本

这里没有涉及以上任何一种情况。


48
我仍然看到一个很小且罕见的用例需要使用 StringUtils.EMPTY。它明确表示使用空字符串是有意义的,而不是某种懒惰行为(“哦,这需要一个字符串,请传递 ""”)。如果有人遇到这段代码,他会在进行更改之前三思而后行。此外,如果 StringUtils.EMPTY 被定义为自己的变量,比如 MyClass.EMPTY,更改“空值的表示”将只需要更改一行代码。例如,您可以将其更改为 "<empty>" 而不是空字符串 ""。但我认为这有点过头了。 - Timmos
5
谢谢。现在我有一些理智的论点可以转交狂热者,而不是每次都要自己思考。 - Alex
4
EMPTY如何缺乏意义? EMPTY满足您列表中的1和2。有经验的开发人员严重低估初级开发人员在使用“”这样简单的东西时出错的潜力。 - Andrew T Finnell
9
@AndrewTFinnell,名称“EMPTY”并没有比空字符串本身多任何含义。最重要的是,它没有记录为什么在特定情况下使用空字符串的原因。这和将常量命名为“ONE”,并假装使用该常量而不是值没有意义是一样的。 - Holger
11
只因为个人偏见而进行的负评,并不代表“”足够清晰明了 :( 它是空白的吗?还是为空?如果我的字体大小很小,里面有一个空格我看不见吗?它是否被设计成为空白?里面是否有奇怪的“隐形”字符? - Dan Rayson
显示剩余2条评论

78

我使用StringUtils.EMPTY来隐藏字面量,并表达return StringUtils.EMPTY是完全被期望的,应该返回一个空字符串。使用""会让人误以为""可以很容易地改变成别的值,而这可能只是个错误。我认为EMPTY更具表现力。


46
其他人已经建议过这个:你也会用 ZERO 表示 0 和 ONE 表示 1 吗? - Jon Skeet
9
我不会将特殊的“空”情况与整数字面量的使用进行比较。 - Christopher Klewes
18
我发现 StringUtils.EMPTY 的表达力比 "" 差。 - bacar
1
@JonSkeet 非常尊重您。我觉得您在这里是不正确的。虽然您和我可能永远不会遇到这种情况,但有理由不使用字面值"",因为如果开发人员弄错了它,它就无法提供语法检查。是的,我见过初级开发人员搞砸像""这样简单的东西。我不赞成将EMPTY更改为其他含义而不是""的想法。我喜欢EMPTY的想法,只是因为编译器能够理解它的含义。 - Andrew T Finnell
有一件事我没看到提到过(我意识到这显得有点龟毛),那就是""(双引号)在匆忙间可能会被误解为带有引号的单引号'。 - John Darvill
显示剩余4条评论

31

不需要,只需使用""

字面上的""非常明确,没有任何误解。我不知道为什么你需要一个类常量来表示这个,但我只能假设该常量在包含StringUtils的程序包中被广泛使用,而不是使用""。但这并不意味着你应该使用它。

如果人行道上有一块石头,你并不需要把它扔掉。


13
如果人行道上有一块石头,你不需要把它扔掉。请告诉我6岁的儿子。 - roel

27

我很惊讶有多少人乐意盲目假设“”确实是一个空字符串,并且不(偶然地?)包含Unicode的一些神奇的不可见和无间距字符。为了万物的美好和合宜,请尽可能使用EMPTY。


4
你是否曾经在代码中见过这种情况?如果是,那是意外还是有意为之呢?这似乎很难意外发生,如果是有意为之,我也可以轻松地创建我的 own StringUtils 类并使用一个非空的 EMPTY 常量来引用它。 - Ian Robertson
7
是的,我见过这种情况。实际上,这种情况经常发生。人们经常从网站上剪贴内容,并将其从一个代码集剪贴到另一个代码集。还有一些公司仍在使用使用古老代码集的Clear Case,这些代码集会被盲目地翻译成Windows ISO集,如果你转移到Git,则会被转换为UTF-8。我已经花费了无数小时来修复代码集问题,包括这个问题。 - Andrew T Finnell
4
@AndrewTFinnell 我当然能理解一般情况下这可能会引起问题。但是你具体看到过多少次非空的看起来为空的字符串常量呢? - Ian Robertson
这就是单元测试存在的原因。它们必须在早期消除任何此类拼写错误/异常,以帮助避免任何意外行为。 - RAM237

24

我想在这里加上我的见解,因为我没有看到任何人谈论String interning和类初始化:

  • Java源代码中的所有String字面值都被interned,使得任何一个""StringUtils.EMPTY都是相同的对象
  • 使用StringUtils.EMPTY 可以初始化StringUtils类,因为它只有在其静态成员EMPTY未声明为final时才会访问(JLS在这一点上非常明确)。然而,org.apache.commons.lang3.StringUtils.EMPTYfinal的,因此不会初始化该类。

请参阅有关字符串驻留的相关答案类初始化,并参考JLS 12.4.1


2
只有当它没有被声明为final时,访问它才会导致StringUtils类的初始化。因此,由于这个字段被声明为final,访问它不会导致StringUtils类的初始化。 - Holger
@Holger 那是一般性的陈述,但实际上,我已经编辑并附上了一个链接到 javadoc,显示它是 final 的(因此不会初始化该类)。 - Matthieu

12

我不太喜欢使用它,因为return "";return StringUtils.EMPTY要短。

然而,使用StringUtils.EMPTY的一个优点是,如果你输入return " "而不是return "",你可能会遇到不同的行为(关于是否正确测试空字符串)。


14
你有没有注意到这个问题实际上会出现(在你本意使用""时不小心使用了“”)?就我个人而言,我更喜欢字面的写法,而且它从来没有给我造成过任何问题。 - Jon Skeet
2
@Jon,确实不是,但我试图找到使用它的优势 ;) - Romain Linsolas
1
没有平等时间规则。如果没有优势,那就没有优势。 - Erick Robertson
1
我不喜欢 "",而且我讨厌在代码中多次输入相同的字面字符串,即使只有一次。我宁愿在 Constants.java 中声明常量,而不是在源代码的各个地方重复使用它们。 - xenophōn
2
我认为 return ""; 很丑,我更喜欢使用 StringUtil.EMPTY(在我的自定义类 StringUtil 中声明,而不是 Apache 的 StringUtils)。 - xenophōn

6

如果你的类除了这个神奇的值以外没有使用commons的其他内容,那么为了这个依赖项而引入它会很遗憾。

StringUtils的设计者大量使用这个常量,这是正确的做法,但这并不意味着你也应该使用它。


我的意思是,既然作者选择了这种方式(避免使用“魔法值”),那么这是可以接受的。但是它应该是私有的。 - cherouvim
1
作者在代码中频繁使用0。如果他们定义一个常量int ZERO = 0,是否会更好呢?如果不是,有什么区别呢? - Jon Skeet
6
这取决于上下文。如果这是一个FCKEditorStringUtils,那么它们的EMPTY将是“<p>&nbsp</p>”,我宁愿重用EMPTY而不是在类中的各个地方复制这个神奇的值。因此,通过EMPTY,他们可能指的是EMPTY_CONTENT而不是EMPTY_STRING(因此您的ZERO示例有点不公平)。您会重用ERROR_VISA_INVALID=0常量吗? - cherouvim

3

我发现在某些情况下,StringUtils.EMPTY 对于可读性很有用。特别是在以下情况下:

  1. Ternary operator eg.

    item.getId() != null ? item.getId() : StringUtils.EMPTY;
    
  2. Returning empty String from a method, to confirm that yes I really wanted to do that.

使用常量可以创建对StringUtils.EMPTY的引用。否则,如果您尝试每次实例化字符串文字"",JVM将不得不检查它是否已经存在于字符串池中(它很可能已经存在,因此没有额外的实例创建开销)。使用StringUtils.EMPTY无疑避免了检查字符串池的必要性。


4
你的多次查找的论点不成立。在Java语言规范3.0的第13.4.9章节中提到,StringUtils.EMPTY常量是在编译时解析的。 - Roland Illig
4
在编译时和类加载时会检查字符串池中的存在性,而不是每次执行此类语句时都在运行时检查。请注意,这里的翻译力求简洁明了,但不改变原意。 - user207421
2
由于 StringUtil.EMPTY 是编译时常量,对它的引用会编译为完全相同的字节码,就像直接使用 "" 一样。另外,我不知道三元运算符为什么会有任何区别。它就像任何其他表达式一样。适用于使用或不使用命名常量的任何原因都同样适用于三元运算符。 - Holger

2
不,因为我还有更多要写。在Java中,一个空的字符串是平台无关的空字符串。File.separator比"/"或"\"更好。但你可以按照自己的喜好来做。你不可能得到像return " ";这样的错别字。

8
我不太理解为什么大多数程序员害怕写“太多”的代码。通过编写StringUtils.EMPTY,您可以实现自我注释的代码,这样更容易阅读。根据史蒂夫·麦康奈尔(或他在《代码大全2.0》中引用的某项研究)的说法,代码被阅读的次数比编写的次数多7倍。 - Paweł Dyda
1
您说得特别对,但是:“”.equals(someString) 和 StringUtils.EMPTY.equals(someString) 的阅读难度是一样的。 - Christian Kuetbach
2
@AndrewTFinnell 这就是为什么理智的程序员会写 someString.isEmpty() - Holger
1
@samkass 这正是有经验的程序员所期望的。与其得到“null”不为空的结果,不如向提供了“null”的调用者抛出一个“NullPointerException”。越早强制拒绝“null”,你在处理“null”方面就会遇到越少的问题。这样,你就不必在代码中添加晦涩的“null安全”结构,更不用说为了一个最简单的内置函数而创建对第三方库的依赖了... - undefined
1
@samkass嗯,你建议使用StringUtils.EMPTY.equals(someString)作为空值安全解决方案,但这已经陷入了一个陷阱,因为将null视为“非空”很少是你想要的,即使在极少数情况下你确实想要这样做,这个表达式也不能告诉读者这是有意为之的。所以,只需写成someString != null && someString.isEmpty(),以说明你已经考虑了如何处理null。如果someString不是String类型,仍然会得到编译器错误(与equals不同,它会接受任何类型)。无论如何,如果你的意思是isEmpty!isEmpty,就不要使用equals - undefined
显示剩余3条评论

1
说实话,我并不认为这两者有什么用。如果你想要与空字符串比较,只需使用StringUtils.isNotEmpty(..)即可。

2
StringUtils.isNotEmpty(..) 还会进行空值检查,因此它与与空字符串比较并不完全相同。 - cherouvim
你如何比较 null?作为 equals 的第二个参数,但结果将是相同的 - false - Bozho
1
isNotEmpty"".equals(…) 的相反,因此,它将像空字符串一样处理 null,这与与空字符串进行比较是不同的,"".equals("")true"".equals(null)falseStringUtils.isNotEmpty("")falseStringUtils.isNotEmpty(null)false。如果您只想知道一个字符串是否为空,请使用 string.isEmpty(),它具有正确的行为,即当它是空字符串时返回 true,如果字符串为 null 则抛出 NullPointerException... - Holger

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接