【问题标题】:Java: String: equalsIgnoreCase vs switching everything to Upper/Lower CaseJava:字符串:equalsIgnoreCase vs 将所有内容切换为大写/小写
【发布时间】:2011-05-25 16:51:27
【问题描述】:

我注意到在 Java 中有几种比较字符串的方法。

我很久以前就养成了使用equalsIgnoreCase 的习惯,以避免出现区分大小写字符串的问题。

另一方面,其他人更喜欢以大写或小写形式传递所有内容。

从我站立的位置(即使从技术上讲我是坐着的),我看不出有什么真正的不同。

有人知道一种做法是否比另一种更好吗?如果是,为什么?

【问题讨论】:

标签: java string string-comparison


【解决方案1】:

使用equalsIgnoreCase,因为它比在比较之前将两个字符串都转换为大写更具可读性。 可读性胜过微优化。

什么更具可读性?

if (myString.toUpperCase().equals(myOtherString.toUpperCase())) {

或

if (myString.equalsIgnoreCase(myOtherString)) {

我想我们都同意equalsIgnoreCase 更具可读性。

【讨论】:

  • 是的,但是……这有点像稻草人。如果您正在使用大小写无关紧要的字符串,那么您很可能会在比较之前很久就准备好字符串。假设您正在将用户输入的单词与字典进行匹配。在特定情况下,您将拥有字典,并且您将转换用户字符串一次。
  • @CurtainDog:如果您正在搜索字典,那么您肯定不想使用equals 或 equalsIgnoreCase。这样做意味着您正在遍历字典中表现不佳的项目。难道你不想使用更合适的数据结构,比如HashMap?
  • 如果你有equals,不要认为你可以摆脱使用equals ;) 但你是对的,第二种形式更具可读性,只是(1)我不在野外很少看到第一种形式(如书面形式); (2) 两种形式都有一个位置(第一种形式是比较已经准备好进行比较的字符串)
  • @CurtainDog:如果您在HashMap 中有一个单词(键)和定义(值)的字典,您可以使用HashMap.get(Object key) 从字典中检索一个项目。不需要equals。也许 JVM 在后台使用 equals 来解决 HashMap 中的冲突,但这对高级程序员来说都是透明的。
  • @Asaph 仍然,等于 is 使用,这是很久以前那句话的重点。
【解决方案2】:

equalsIgnoreCase 避免了与特定于语言环境的差异有关的问题(例如,在土耳其语言环境中有两个不同的大写“i”字母)。另一方面,Maps 只使用 equals() 方法。

【讨论】:

  • 我在 OpenJDK 源代码中查找了这一点以确保,因为 javadoc 似乎没有提到语言环境。该方法逐个字符地比较字符串。如果两个字符的大写不同,则以小写进行比较,这显然是格鲁吉亚字母表所需要的。这使得 equalsIgnoreCase 的性能稍差,但更正确。
  • 那么在土耳其语中从小写转换为大写时,如何处理选择?
  • 您需要指定区域设置。例如:"turkish".toUpperCase(Locale.ENGLISH)
  • @koljaTM 是的,有两个不同的大写“i”字母......但也有两个不同的小写“i”字母伴随着它们,所以我不确定这有什么关系. en.wikipedia.org/wiki/Turkish_alphabet
  • @JakeGriffin 这很重要,否则it breaks。
【解决方案3】:

但后者的问题是,您假设大写或小写都已通过,您不能盲目地信任调用者。因此,您必须在方法的开头包含 ASSERT 语句,以确保输入始终符合您的预期。

【讨论】:

  • 我认为您的意思是“调用者”,而不是“被调用者”。对吗?
  • 这应该是对 asaph 的评论吗?
【解决方案4】:

两者都不是更好,它们在不同的场景中都有各自的用途。

很多时候,当您必须进行字符串比较时,有机会至少按摩其中一个字符串以使其更容易比较,在这些情况下,您会看到字符串在被转换为特定大小写、修剪等之前比较。

另一方面,如果您只想对两个字符串进行不区分大小写的即时比较,请随意使用equalsIgnoreCase,毕竟这就是它的用途。但是,我要提醒您,如果您看到很多 equalsIgnoreCase,这可能是代码异味。

【讨论】:

    【解决方案5】:

    这取决于用例。

    如果您要进行一对一的字符串比较,equalsIgnoreCase 可能更快,因为在内部它只是在遍历字符串时将每个字符大写(下面的代码来自 java.lang.String),这比在执行相同的比较之前将它们全部大写或小写:

    if (ignoreCase) 
    {
        // If characters don't match but case may be ignored,
        // try converting both characters to uppercase.
        // If the results match, then the comparison scan should
        // continue.
        char u1 = Character.toUpperCase(c1);
        char u2 = Character.toUpperCase(c2);
        if (u1 == u2) {
            continue;
        }
        // Unfortunately, conversion to uppercase does not work properly
        // for the Georgian alphabet, which has strange rules about case
        // conversion.  So we need to make one last check before
        // exiting.
        if (Character.toLowerCase(u1) == Character.toLowerCase(u2)) {
            continue;
        }
    }
    

    但是,当您想以不区分大小写的方式对充满字符串(尤其是所有在美国拉丁/ASCII 空间中的字符串)的数据结构进行查找时,修剪/小写会更快要检查的字符串并将它们放入 HashSet 或 HashMap 之类的东西中。

    这比在 List 的每个元素上调用 equalsIgnoreCase 更好,因为 equalsIgnoreCase() 的轻微性能提升被您基本上对数组执行 contains() 的修改版本的事实所抵消,这是 O (n)。使用预先规范化的字符串,您可以使用在 O(1) 中运行的单个 contains() 调用来检查整个字符串列表。

    【讨论】:

      【解决方案6】:

      jdk 8 中的equalsIgnoreCase 文档

      • 将此字符串与另一个字符串进行比较,忽略大小写 考虑因素。如果两个字符串忽略大小写,则认为它们相等 两个字符串的长度相同且对应的字符 是相等的,忽略大小写。

        两个字符 c1 和 c2 被认为是相同的 如果以下至少一项为真,则忽略大小写:

        • 两个字符相同(由 == 运算符比较)
        • 将方法 java.lang.CharactertoUpperCase(char) 应用于每个字符会产生相同的结果
        • 将方法 java.lang.CharactertoLowerCase(char) 应用于每个字符 产生相同的结果

      我的想法:

      因此,我们使用 equalsIgnoreCase 遍历字符串(仅当它们的大小值相同时)比较每个字符。在最坏的情况下,我们的性能将是 O(3cn),其中 n = 字符串的大小。我们不会使用额外的空间。

      使用 toUpper() 然后比较字符串是否相等,你总是遍历每个字符串一次,将所有字符串转换为大写,然后通过引用检查 (equals()) 进行等价。这是 theta(2n + c)。但请记住,当您执行 toUpperCase() 时,您实际上必须创建两个新字符串,因为 Java 中的字符串是不可变的。

      所以我会说 equalsIgnoreCase 更高效且更易于阅读。

      我会再次考虑用例,因为这对我来说就是归根结底。 toUpper 方法在某些用例中可能有效,但 98% 的时间我使用 equalsIgnoreCase()。

      【讨论】:

        【解决方案7】:

        根据这篇文章,性能方面两者都是相同的:

        http://www.params.me/2011/03/stringtolowercasestringtouppercase-vs.html

        所以我会根据代码的可读性来决定,在某些情况下,如果我总是将一个值传递给一个方法来创建对象,那么 toLowerCase() 会更好,否则 equalsIgnoreCase() 更有意义。

        【讨论】:

        • 那篇文章实际上并没有引用任何真正的性能测试,并且错误地指出“equalsIgnoreCase 函数在内部使用 toLowerCase 函数”,至少对于 OpenJDK 6 而言并非如此。
        【解决方案8】:

        当我使用纯英文字符时,如果我调用.equalsIgnoreCase()不止一次或者如果我我正在使用switch 声明。这样它只执行一次大小写更改操作,因此效率更高。

        例如,在工厂模式中:

        public static SuperObject objectFactory(String objectName) {
            switch(objectName.toUpperCase()) {
                case "OBJECT1":
                    return new SubObject1();
                    break;
                case "OBJECT2":
                    return new SubObject2();
                    break;
                case "OBJECT3":
                    return new SubObject3();
                    break;
            }
            return null;
        }
        

        (使用switch 语句比if..else if..else 块进行字符串比较稍快)

        【讨论】:

          猜你喜欢
          • 2013-02-01
          • 1970-01-01
          • 2015-07-14
          • 2020-12-05
          • 2014-10-30
          • 2018-12-24
          • 1970-01-01
          • 2010-12-29
          相关资源
          最近更新 更多