【问题标题】:String Comparison : individual comparison Vs appended string comparison字符串比较:单独比较与附加字符串比较
【发布时间】:2009-01-06 13:24:29
【问题描述】:

我有六个字符串变量,分别是 str11、str12、str13、str21、str21 和 str23。

我需要比较这些变量的组合。

我必须检查的组合是 str11 -- str12 -- str13 作为一组,str21 -- str22 -- str23 作为另一组。我必须比较这两组。

现在我很困惑我应该使用哪种方法进行比较?

我可以附加相同组的字符串并进行比较,这只是一个比较 说( str11 append str12 append str13 ) eqauls ( str21 append str22 append str23 )

或者

我应该单独进行 3 次比较吗?

if( str11 equals str21 ) {

    if( str12 equals str22 ) {

        if( str13 equals str23 ) {

        }

    }

}

当我进行字符串比较时,由于字符串长度而使我付出代价的性能因素是什么? 让我们假设所有字符串的长度相同(大约)。

【问题讨论】:

  • 你为什么要担心这里的性能?比较是瓶颈吗?

标签: java string comparison


【解决方案1】:

我会单独测试。

“AB”“CD”“EF”是否等于“ABC”“DE”“F”?

我不这么认为。

附:如果是,那么它是一个非常特殊的情况,如果您决定这样编码(作为串联比较),那么请把它注释掉。

【讨论】:

    【解决方案2】:

    绝对没有必要将比较分成三个 if 语句。您也可以简单地对您的比较进行 AND,例如

    if (  str11 equals str21
       && str12 equals str22
       && str13 equals str23) ...
    

    【讨论】:

      【解决方案3】:

      您的变量名称表示主要的代码异味。听起来您应该有两个数组,而不是六个变量,每个数组包含三个字符串。换句话说,像这样的事情最初会更好:

      String[][] strs = new String[2][3];
      strs[0][0] = str11;
      strs[0][1] = str12;
      ...

      根据您从哪里获得六个字符串,您可能不需要在比较之前立即手动执行此操作,但可能会以更友好的格式传递您的参数。

      如果您确实希望通过比较字符串对象的数组来做到这一点,并且您使用的是 Java 1.5 或更高版本,请记住您可以访问 java.util.Arrays.equals() 方法来实现数组相等。尽可能多地使用库方法是避免重新发明轮子的额外工作和可能的实现错误(例如,迄今为止提交的两个实现都存在错误)的好方法。

      您采用的确切路径可能取决于您所编写的域 - 如果您的特定问题要求您始终比较 3 元组,那么编写代码来显式比较三个字符串的组不是一个好主意,因为它可能比比较任意长度数组的代码更容易理解。 (如果你要走这条路,那么我们一定要使用带有 && 的单个 if() 条件,而不是嵌套的 if 块,正如 Adam Bellaire 所演示的那样。

      不过,一般来说,如果您将其设置为使用任意长度的数组,您将拥有一个更可重用的代码块。

      【讨论】:

        【解决方案4】:

        将字符串附加在一起并进行比较将不起作用。例如,字符串 1 和 2 可以为空,字符串 3 可以包含“gorps”,而字符串 4 包含“gorps”,而字符串 5 和 6 为空。附加结果的比较将返回 true,尽管这将是误报。你必须想出一个你保证不会包含在任何字符串中的分隔符才能让它工作,这可能会变得混乱。

        我会按照您的方式进行比较。它易于阅读且简单明了。

        【讨论】:

        • @Tom 我已经保证了分隔符,那么?
        • 如果您决定添加分隔符,那么您将扩大字符串连接的成本(对于 n 个字符串,您需要执行 n-1 个额外的连接)
        • 如果您有保证的分隔符,该方案将起作用,但字符串连接涉及创建额外的字符串对象。正如我所说,我会进行个人比较。另一种方法可行,但成本更高。
        • @Binary - 我知道。我将此作为 concat 方法起作用的唯一条件。正如我所说,我会采用个体比较法。
        • @Tom:我听到了,这更像是对读者的警告,我从你的回复中推测出你的反应,尽管这是一个坏主意。祝你好运:)
        【解决方案5】:

        对一个大的 char[] 的迭代可能比对 n 个总长度相等的单独字符串的迭代更快。 这是因为数据非常本地化,CPU 很容易预取数据。

        但是,当您在 Java 中连接多个字符串时,您将使用 StringBuilder/Buffer,然后在某些情况下将 i 转换回字符串。由于 SB.append() 的工作方式和 Java 字符串是不可变的,这将导致内存分配增加,进而会造成内存瓶颈并显着降低应用程序的速度。

        我建议保持字符串不变并进行单独比较。较长的 char[] 所带来的性能提升很可能远低于您在较高分配率下可能遇到的问题。

        【讨论】:

          【解决方案6】:

          恕我直言:我认为您的代码和问题不仅有点味道,而且几乎很臭(这里是大笑脸)。

          1) 变量名表明实际上有字符串向量;如前所述
          2) 个人比较与串联比较的问题引发了如何定义字符串元组相等的问题;也已经提到了。

          但最让我印象深刻的是:

          3) 对我来说,这看起来像是一个典型的“过早优化”并在错误的地方计算 CPU 周期的案例。

          如果您真的关心性能,请忘记 3 次单独比较与单次比较的成本。而是:

          创建两个连接字符串的额外开销如何?

            (str11 + str12 + str13) = (str21 + str22 + str23)
          

          让我们分析一下w.r.t。到内存管理器和要完成的操作。在底层,这意味着 4 个额外的内存分配、2 个额外的 strcpy,以及另外 4 个额外的 strcat 或 strcpy(取决于 VM 的执行方式;但大多数会使用另一个 strcpy)操作。然后调用单个比较,它不首先使用 strlen 计算字符;相反,它要么预先知道大小(如果对象标头还包括字符数,这很可能),要么它只是运行到一个 0 字节。这被称为一次与 3 次。要比较的实际字符数大致相同(忘记额外的 0 字节)。这给我们留下了 2 次额外的 strcmp 调用(几个 nS),而我上面描述的开销(几个 uS)。如果我们将 GC 回收开销(0 分配与 4)相加,我会说您的“优化”解决方案很容易比 3 strcmps 慢 100 到 1000 倍!

          补充说明:
          从理论上讲,JITter 可以优化它或其中的一部分,并按照 Adam Bellaire 的建议实际生成代码,但我怀疑任何 JIT 开发人员都关心优化此类代码。顺便说一句,系统的字符串例程(又名字符串操作)通常比手工编码快得多,所以不要自己开始循环单个字符。

          【讨论】:

            【解决方案7】:

            我会将这两个组添加到两个数组中,然后遍历数组以比较该数组中的各个字符串。 Markus Lausberg 给出了一个很好的例子。

            我不会担心性能成本。只需以最易读的方式编写即可。 Java 编译器在性能优化方面非常出色。

            示例方法:

                public boolean compareGroups(String[] group1, String[] group2){
                if (group1.length != group2.length ){
                    return false;
                }
            
                for (int i = 0; i < group1.length; i++) {
                    if (!group1[i].equals(group2[i])){
                        return false;
                    }
                }
            
                return true;
            }
            

            而且调用方法当然很简单:

                    String[] group1 = new String[]{"String 1", "String 2", "String 3"};
                String[] group2 = new String[]{"String 1", "String 2", "String 3"};
            
                boolean result = compareGroups(group1, group2);
            

            【讨论】:

            • @Rolf 是的,当然。我没有改变现有的问题。如果我没有错,这是另一个问题
            【解决方案8】:

            我会用简单的方法

            动态运行两个数组的所有数组元素。

                        boolean isEqual = true;
                        for(int n = 0;n<str1.length;++n){
                            isEqual &= str1[n].equals(str2[n]);
                        }
            
                        return isEqual;
            

            【讨论】:

            • 我认为不会编译。
            • -1 过度设计,未优化(大 n 且 str1[0] 不等于 str2[0])
            猜你喜欢
            • 2011-03-27
            • 1970-01-01
            • 2021-08-05
            • 1970-01-01
            • 2013-05-06
            • 1970-01-01
            • 2011-07-06
            • 1970-01-01
            相关资源
            最近更新 更多