使一个空字符串值得吗?

时间:2008-10-17 22:00:54

标签: java string

我有一个同事发誓

//in a singleton "Constants" class
public static final String EMPTY_STRING = "";

在整个项目中可用的常量类中。这样,我们可以编写类似

的内容
if (Constants.EMPTY_STRING.equals(otherString)) {
    ...
}

而不是

if ("".equals(otherString)) {
    ...
}

我说是

  1. 不值得 - 它不会在堆/堆栈/字符串池中保存任何空间,
  2. 难看
  3. 滥用常数类。
  4. 谁是这里的白痴?

18 个答案:

答案 0 :(得分:65)

默认情况下,字符串文字是固定的,因此无论您在代码中引用多少次“”,都只会有一个空的String对象。我没有看到声明EMPTY_STRING有任何好处。否则,你也可以为整数文字声明一,二,三,四等。

当然,如果您想稍后更改EMPTY_STRING的值,将它放在一个地方很方便;)

答案 1 :(得分:16)

为什么你想在Java中使用全局变量?詹姆斯戈斯林真的试图摆脱他们;请不要带回来。

无论

0 == possiblyEmptyString.length()

possiblyEmptyString.isEmpty() // Java 6 only

同样清楚。

答案 2 :(得分:7)

我更喜欢看EMPTY_STRING。

它使它成为英语。 “”.equals'读取'与EMPTY_STRING.equals不同。

答案 3 :(得分:7)

具有讽刺意味的是,常数的重点是使它们易于改变。因此,除非你的同事计划将EMPTY_STRING重新定义为空字符串以外的东西 - 这将是一个非常愚蠢的事情 - 将一个真正的固定构造(如“”)转换为常量是一件坏事。

正如Dan Dyer所说,它就像把常数定义为1:它完全没有意义,如果有人重新定义它,那将是完全混乱的 - 可能有风险。

答案 4 :(得分:6)

嗯,我也可以猜,但我做了一个快速测试...几乎像作弊......

使用各种方法检查任意字符串。 (几次迭代)

结果表明isEmpty()既快又实际上更具可读性; 如果isEmpty()不可用,则length()是一个不错的选择。

使用常量可能不值得。

"".equals(someString())      :24735 ms
t != null && t.equals("")    :23363 ms
t != null && t.equals(EMPTY) :22561 ms
EMPTY.equals(someString())   :22159 ms
t != null && t.length() == 0 :18388 ms
t != null && t.isEmpty()     :18375 ms
someString().length() == 0   :18171 ms

在这种情况下;

"IAmNotHardCoded".equals(someString())

我建议在一个地方定义一个常数,因为它是一个全局类 所有常数真的很糟糕。如果没有相关的地方,你可能会做错其他的事情......

Customer.FIELD_SHOE_SIZE //"SHOE_SIZE"

可能会被视为相关的地方;

CommonConstants.I__AM__A__LAZY__PROGRAMMER // true

不是。

对于BigIntegers和类似的东西,我倾向于最终在本地定义一个最终的静态;像:

private final static BigDecimal ZERO = new BigDecimal(0);
private final static BigDecimal B100 = new BigDecimal("100.00");

多数民众赞成我的错误,对于BigInts和BigDecimals而言,不会有一些糖...

答案 5 :(得分:4)

我和你的同事在一起。虽然空字符串很难输入错误,但您可能会意外地在其中放置空格,并且在扫描代码时可能很难注意到。更重要的是,使用在多个地方使用的所有字符串常量来执行此操作是一个好习惯 - 尽管我倾向于在类级别而不是全局常量中执行此操作。

FWIW,C#有一个静态属性string.Empty就是为了这个目的,我发现它极大地提高了代码的可读性。

答案 6 :(得分:3)

我不喜欢这两种选择。为什么不if (otherString.length() == 0)

编辑:我实际上总是编码

if (otherString == null || otherString.length() == 0)

答案 7 :(得分:3)

作为问题的切线,我通常建议使用实用程序函数,当你真正检查的是“没有用的值”时,而不是特别是空字符串。一般来说,我倾向于使用:

import org.apache.commons.lang.StringUtils;

// Check if a String is whitespace, empty ("") or null.
StringUtils.isBlank(mystr); 
// Check if a String is empty ("") or null.
StringUtils.isEmpty(mystr); 

以上两个概念:

  • 检查其他各种情况,包括安全无效,(更重要的是)
  • 传达您要测试的内容,而不是如何测试它。

答案 8 :(得分:2)

.NET中不时出现同样的论点(其中已经有一个只读的静态字段string.Empty)。这是一个品味问题 - 但我个人认为“不那么突兀。”

答案 9 :(得分:2)

当一个名称捕获值的语义时,使用空字符串值的常量确实有意义的一种情况。例如:

if (Constants.FORM_FIELD_NOT_SET.equals(form.getField("foobar"))) {
    ...
}

这使得代码更加自我记录(除了更好的设计是添加方法检查字段是否设置为表单本身的论点之外)。

答案 10 :(得分:2)

呵呵,好笑的是: 一旦编译完成,你就不会看到“静态最终”事物和字符串文字之间的区别(在字节码中),因为Java编译器总是将“静态最终字符串”内联到目标类中。只需将空字符串更改为可识别的字符串(如LGPL文本),然后查看引用该常量的结果* .class代码文件。您会发现您的文本被复制到该类文件中。

答案 11 :(得分:2)

David Arno说: -

  讽刺的是,整个问题   常数是使它们容易   多变

这根本不是真的。常量的重点是重用相同的值并提高可读性。

常量值的变化非常罕见(因此名称)。通常更改配置值,但在某处保存为数据(如配置文件或注册表项)

自早期编程以来,常量已被用于将隐藏的十六进制值(如0xff6d8da412)转换为人类可读的内容,而永远意图更改值。

const int MODE_READ       = 0x000000FF;
const int MODE_EXECUTE    = 0x00FF0000;
const int MODE_WRITE      = 0x0000FF00;
const int MODE_READ_WRITE = 0x0000FFFF;

答案 12 :(得分:1)

我们只是针对以下情况执行以下操作:

public class StaticUtils
{
    public static boolean empty(CharSequence cs)
    {
        return cs == null || cs.length() == 0;
    }

    public static boolean has(CharSequence cs)
    {
        return !empty(cs);
    }
}

然后只是import static StaticUtils.*

答案 13 :(得分:0)

或者只是将其作为字符串即可。IsNullOrEmpty(otherString)

答案 14 :(得分:0)

如果您希望在oracle的可空字符串列中存储“空”字符串,则必须将EMPTY_STRING的定义更改为“”之外的其他内容! (我记得上次我被迫使用Oracle时,它不知道空字符串和空字符串之间的区别)。

但是,这应该在您的数据访问层中完成,因此应用程序的其余部分不知道它,和/或整理您的数据模型,因此您不需要在同一列中存储空字符串AND空字符串

答案 15 :(得分:0)

为什么最好在C#中使用String.Empty,因此在其他语言中使用公共常量,因为常量是静态的,因此只占用内存中的一个实例。

每次你做这样的事情: -

stringVariable = "";

您正在创建一个空字符串的新实例,并使用stringVariable指向它。

因此,每次对变量(指针)进行“”赋值时,“”空字符串就是一个新的字符串实例,直到它不再有任何指针赋值为止。

通过将字符串全部指向同一个常量来初始化字符串,意味着只创建一个“”,并且每个初始化变量都指向相同的空字符串。

这可能听起来微不足道,但创建和销毁字符串比创建指针(变量)并将它们指向现有字符串要多得多。

由于字符串初始化很常见,所以最好这样做: -

const String EMPTY_STRING = "";
String variable1 = EMPTY_STRING;
String variable2 = EMPTY_STRING;
String variable3 = EMPTY_STRING;
String variable4 = EMPTY_STRING;
String variable5 = EMPTY_STRING;

您创建了5个字符串指针,但只创建了1个字符串

而不是: -

String variable1 = "";
String variable2 = "";
String variable3 = "";
String variable4 = "";
String variable5 = "";

您已经创建了5个字符串指针和5个单独的空字符串。

在这种情况下不是一个主要问题,但在几十个类中的数千行代码中,不必要的内存浪费和处理器使用,创建另一个空字符串变量,当它们都指向同一个时,制作应用程序效率更高。

当然,编译器应该足够聪明地确定几个静态字符串并重复使用重复项,但为什么要假设?

此外,它不太容易引入错误,因为“”和“”都会编译,但你可能会错过你意外添加的空间,这可能会产生虚假的运行时错误,例如条件逻辑,如: -

myvariable = " ";
While (myVariable == ""){
 ...
}

while块内的代码无法访问,因为myVariable将不满足第一次迭代的条件。使用“”而不是“”初始化的错误很容易错过,而: -

myvariable = EMPTY_STRING;
While (myVariable == EMPTY_STRING){
 ...
}

...不太可能导致运行时错误,尤其是错误拼写EMPTY_STRING会生成编译错误,而不必在运行时捕获错误。

最干净的解决方案是创建一个静态类,其中包含您需要的各种字符串常量的成员,如果您需要的不仅仅是一个空字符串。

public static class StringConstants{
    public static String Empty = "";
    public static String EMail = "mailto:%s";
    public static String http = "http://%s";
    public static String https = "https://%s";
    public static String LogEntry = "TimeStamp:%tYmdHMSL | LogLevel:%s| Type:%s | Message: '%s'";

}

String myVariable = StringConstants.Empty;

您甚至可以扩展本机String对象,具体取决于您的语言。

答案 16 :(得分:0)

嗯,规则是正确的,但是从不同的意义上来看!让我们看看原因,首先通过equals()检查java中的所有对象引用。早些时候,在某些语言中,它是使用'=='运算符完成的,如果不小心有人使用'='代表'==',那就是灾难。现在魔术数字/常数的问题,对于计算机所有常数/数字都是相似的。而不是'int ONE = 1'可以肯定使用1,但是对于双PI = 3.141 ......这是否正确?如果有人试图稍后改变精度会发生什么。

如果我们想出一份清单,那么规则将针对一般指引解决的不是吗?我的意思是说规则应该有所帮助,只有当我们非常了解规则时,我们才能确定地改变规则。常识占上风。正如我的朋友所建议的那样,表示退出条件的0/1等程序常量可以是硬编码的,因此幻数原则不适用。但对于那些参与逻辑检查/规则的人来说,最好将它们作为可配置的常量。

答案 17 :(得分:0)

  1. 是的 - 它没有任何好处。
  2. 取决于你习惯的,我敢肯定。
  3. 不,这只是一个常数 - 而不是滥用。