在字符串文字上调用equals

时间:2013-12-04 20:24:53

标签: java string comparison

我只是整理了我的代码并且有这篇文章:

String saving = getValue();
if(saving != null && saving.equals("true")){
   // do something
}

然后我想到了另外一种方法来摆脱对null的检查:

if("true".equals(saving)){
   // do something
}

这绝对有效,但这样安全吗?我的意思是字符串文字存储在公共池中,而由new创建的字符串对象存储在堆上。但是常量池中的字符串也是对象,对吗?

但即使它使代码更短,它仍然是正确的做法。

9 个答案:

答案 0 :(得分:22)

这是安全的 - 正如您所见,这是一种避免空指针的好方法。

您提到new用于字符串。许多java静态代码分析工具将建议始终使用new String("foo");上的文字。

编辑:

如果你愿意,你甚至可以使用:     

if (Boolean.valueOf(saving)) {
    ...
}

根据docs,传递null将返回false

答案 1 :(得分:21)

为了确保对这个问题有完全平衡的答案,我想发表不同意见。

我认为这种机制是愚蠢的。

如果你有一个null,你应该尽快知道 - 隐藏它只会推迟它的发现。如果null不是例外,请将其替换为其他内容。

采用这种方法将使用所谓的防御性编程强化您的代码,在这种情况下,您的错误会尽快被发现,而不是直到所有事情都崩溃为止。

总之 - NullPointerException是你的朋友。您应该使用它来查找代码中的错误。一旦您确定Collections.emptySet()不是例外,非常就可以轻松使用 Empty 对象,例如null

出于习惯而使用尤达技术将不可避免地隐藏您不想隐藏的错误。 使用它会更早地暴露错误。对我而言,这是充分的论据,不使用它 - 永远。

给我 - 使用

if(saving != null && saving.equals("true")){

表示我实际上希望允许savings成为null并且这是可接受的情况 - 使用

if("true".equals(saving)){

只是以一种可能成为坏习惯的方式隐藏这种刻意的选择。

答案 2 :(得分:8)

它被称为yoda条件(在比较中将变量放在一个常量之前)可以被认为是不好的做法,也许对于那些可读性较差的人(比如我)。

但有时候使用yoda条件会使代码更“易于理解”->你不需要在它前面加上额外的空值检查,它可以有效地区分代码块和强烈禁止null的情况。 / p>

答案 3 :(得分:8)

我不同意一些答案。有时您执行想知道您的变量是否为null。这可能表明您的代码中发生了一些不好的事情,您可能想重新考虑您的逻辑。

我不喜欢if("someString".equals(myString));,因为我想要知道myString是否null并且可能会处理它或更改我的逻辑以防止像这样的情况。

想象一下,由于某些错误,你有一个被错误计算的对象数组:

myStrings = {..., ..., null, null, ...};

然后你想对数组的对象执行一些操作,你将拥有:

if("myString".equals(myObjArray[i])) { ... } 

你不会得到NullPointerException并且你会认为你对数组中的所有对象执行了操作..你永远不会知道你错误估计了它,因为你“隐藏”了这个例外。如果你这样做了:

if(myObjArray[i].equals("myString")) { ... } 

你会得到一个 NPE ,你会知道数组中出现了问题......你可能想要解决这个问题或者用另一种方式处理它。

答案 4 :(得分:5)

if("true".equals(saving)){
   // do something
}

这是非常安全和良好的做法。字符串“true”永远不会为null。因此,您永远不会将String与null进行比较。这段代码非常好

答案 5 :(得分:4)

首先放置文字的格式避免了潜在的NPE,"literal".equals(null)总是假的。

这是因为“文字”表达式总是评估为String对象(因此永远不为空),String.equals(obj)检查其他 object为null(通过asinstanceof)。对象一个对象 - 无需担心“堆”。

最好在an equals implementation中设置空值,因为null.equals(null) 允许:“equals方法在非null上实现等价关系对象引用“

这是String.equals the source(对于OpenJDK):

public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        // ..
    }
    return false;
}

答案 6 :(得分:2)

很抱歉,我无法就此问题达成一致。

如果您首先使用常量,则支持可以掩盖编程错误的结构。一个人应该只生成代码

  1. 添加功能,
  2. 修正编程错误
  3. 或尝试支持结构以避免编程错误(如 设计模式)。
  4. 最重要的是,你对这个变量有一个弱的断言。以下代码总是被强制检查空值。

    如果您必须处理来自其他模块的空值,您的任务是尽早将它们映射到域模型中的正确表示。

    在你自己的代码中,避免将null作为参数或返回值,因此不再需要任何空检查,包括建议的代码片段。

    你知道,这个主题更多的是关于避免null而不是接受它来征服你的代码。

答案 7 :(得分:2)

if ("true".equals(saving))

完全是“保存”的,并由虚拟产品推荐,如SonarLint和建立此“良好”状态的任何其他顾问认为的规则,即您的主要要求是遵循。

我说是愚蠢的,下面是我的解释。

如果您有以下代码会怎样?

if (!saving.equals("true"))
    {
    if (saving.length() > 10)
        {
        // do something
        }
    }

您可以使用以下建议代码

if (!"true".equals(saving))
    {
    if (saving.length() > 10)
        {
        // do something
        }
    }

但是,当您的代码部署到生产环境中时,如果保存变量尚未初始化且包含NULL,则程序将在length()函数上崩溃。

您已更改代码以避免在NullPointerException函数上使用equals(),但是您的程序将在NullPointerException函数上返回另一个length()

好的反应是停止使用String文字提示,并分析代码以找到理想的解决方案,如以下示例所示。

if (saving != null)
    {
    if (!saving.equals("true"))
        {
        if (saving.length() > 10)
            {
            // do something
            }
        }
    }

if (saving == null) saving = "";

if (!saving.equals("true"))
    {
    if (saving.length() > 10)
        {
        // do something
        }
    }

可能是冗长的,但是如果您要使用Java进行编程,那就是要付出的代价。

使用字符串文字equals()方法来避免NullPointerException具有以下缺点

  1. 解决方案很棘手
  2. 该代码自然不是人类可读的
  3. 平等不会崩溃,但程序的另一部分将继续 崩溃
  4. 如果使用此技巧,
  5. 代码将很快变得难以阅读 lower()和Greater()函数(例如:if('USA'.greater(sCode)))
  6. 给人一种错误的印象,认为代码是安全的

答案 8 :(得分:0)

不仅安全,而且还是解决此问题的首选方式