【问题标题】:Java: same strings got with StringBuilder are not equals in the endJava:使用 StringBuilder 获得的相同字符串最终不相等
【发布时间】:2018-04-16 16:21:26
【问题描述】:

Out 产品与 Drools 集成,用户可以通过在一个简单的长滚动 JTextArea 中加载整个包并直接编辑一些 DRools 函数来从/向包添加/编辑/删除 Drools 函数;或者,更好的是,在使用其他工具(如 Notepad++)编辑后复制并粘贴整个包。 当新包被持久化时,我必须用它之前存储在数据库中的版本来解析它,并审计现有函数中的差异,或者插入/删除的函数。我已经有一个将 Drools 函数拆分为其组件的类,我在其中添加了这个方法来恢复要存储的函数的快照:

public String getFunctionCode() {
    StringBuilder strBld = new StringBuilder("function ");

    if (this.returnType == null)
        strBld.append("void");
    else
        strBld.append(this.returnType);

    strBld.append(" ");
    strBld.append(this.name);
    strBld.append("(");

    if (this.paramNames != null && !this.paramNames.isEmpty()) {
        int parametersSize = this.paramTypes.size();
        for (int i = 0; i < parametersSize; i++) {
            strBld.append(this.paramTypes.get(i).getName());
            strBld.append(" ");
            strBld.append(this.paramNames.get(i).getName());
            if (i < parametersSize - 1)
                strBld.append(",");
        }
    }

    strBld.append(") {");

    if (this.text == null || this.text.trim().isEmpty())
        strBld.append(" ");
    else
        strBld.append(this.text);

    strBld.append("}\r\n");

    return strBld.toString();
}

其中paramNamesparamTypes 只是一个包含函数签名的List&lt;String&gt;,而text 包含签名后两个主要{ } 之间的函数体。 即使用户添加或删除了另一个功能,有时也会检测到包的所有其他功能已编辑。为什么这个?这是因为一些不可打印的字符吗? 如果我将存储在 DB 上的两个快照与文本差异工具进行比较,则没有检测到任何内容。 为了获得改变的功能,我在一个 for 循环中做:

for (FunctionInfo functionInfo : updatedFunctions) {
    FunctionInfo oldFunction = oldPackageInfo.getFunction(functionInfo.getName());

    String oldFunctionBody = oldFunction.getFunctionCode();
    String newFunctionBody = functionInfo.getFunctionCode();

    if (!newFunctionBody.equals(oldFunctionBody)) {
      /* persist an audit record */
    }
}

其中updatedFunctionsList&lt;FunctionInfo&gt;,它是通过检索旧的持久包和从前端到达的包之间的所有共同函数,在按名称排序后得到的。 可能是什么原因?

更新 我在调试模式下启动了 Wildfly,并在 Eclipse 上在前一个循环的 if 语句中设置了一个断点。然后,使用this online tool 进行文本差异我比较了oldFunctionBodynewFunctionBody 的一个我没有从前端窗口编辑的函数。 事实证明,来自前端的旧未触及函数添加了一些不可打印的字符,总体上有许多\r。为什么会这样?

旧功能:

function void disableTestOnDevice(SampleBuilder sample,String devices,String[] devTestCode) {\r\n\t\t   if(devices == null)\r\n\t\t\t   return;\r\n\t       if(sample.getListTransc() != null && sample.getListTransc().size() > 0){\t\r\n\t\t\t\tfor(int i = sample.getListTransc().size()-1; i >= 0; i--){\r\n\t\t\t\t\tViewWorklistBuilder j = (ViewWorklistBuilder)sample.getListTransc().get(i);\r\n\t\t\t\t\tif(j.getDeviceId() == null || j.getDeviceTestCode() == null || j.getDeviceSpecimenCode() == null){\r\n\t\t\t\t\t\tcontinue;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif(j.getDeviceId().equals(devices)){\r\n\t\t\t\t\t\tif(devTestCode != null){\r\n\t\t\t\t\t\t\tfor(int k = 0;  k < devTestCode.length; k++){\r\n\t\t\t\t\t\t\t\tif(j.getDeviceTestCode().equals(devTestCode[k])){\r\n\t\t\t\t\t\t\t\t\tj.setEnabled(0);\r\n\t\t\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\t\t\r\n\t\t\t\t}\r\n\t       }\r\n\t\r\n

新功能:

function void disableTestOnDevice(SampleBuilder sample,String devices,String[] devTestCode) {\n\t\t   if(devices == null)\n\t\t\t   return;\n\t       if(sample.getListTransc() != null && sample.getListTransc().size() > 0){\t\n\t\t\t\tfor(int i = sample.getListTransc().size()-1; i >= 0; i--){\n\t\t\t\t\tViewWorklistBuilder j = (ViewWorklistBuilder)sample.getListTransc().get(i);\n\t\t\t\t\tif(j.getDeviceId() == null || j.getDeviceTestCode() == null || j.getDeviceSpecimenCode() == null){\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tif(j.getDeviceId().equals(devices)){\n\t\t\t\t\t\tif(devTestCode != null){\n\t\t\t\t\t\t\tfor(int k = 0;  k < devTestCode.length; k++){\n\t\t\t\t\t\t\t\tif(j.getDeviceTestCode().equals(devTestCode[k])){\n\t\t\t\t\t\t\t\t\tj.setEnabled(0);\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t}\n\t       }\n\t\r\n

【问题讨论】:

  • 当您的代码检测到错误(错误)更改时,您能否尝试调试实例,它实际上比较了哪两个函数?
  • 我试过了,功能完全一样。相同的名字和相同的签名。此外,如果我在 DB 表中打开 OLD_SNAPSHOT 和 NEW_FUNCTIONS 字段,它们包含与该函数名称相同的字符串
  • 我不知道这是否可能,但如果这种情况有时会像您在问题中提到的那样发生,您可能会尝试找出对函数的哪种类型的更改会对其他人造成错误的更改检测。它可以提示进一步解决您的问题。
  • 在比较字符串之前回答类似this的问题可能会有所帮助。
  • @EmreDalkiran :感谢您的建议,我刚刚开始考虑在比较函数体之前删除所有不可打印的字符......我希望它有所帮助。明天早上我会告诉你的

标签: java string drools stringbuilder string-comparison


【解决方案1】:

如果默认比较不适合您,您需要重写默认的.equals() 方法,以指定您认为在比较对象的类中它是如何相等的。

编辑:请参阅documentation for Java 7tutorial for javase 了解更多信息。另请参阅 this post 了解何时使用 StringBuilder。

【讨论】:

  • 我不应该这样做,因为我比较的是普通字符串,所以没有必要重写 .equals() 方法...
  • 您看过文档吗? StringBuilder 不一定会返回普通字符串。
  • 不...我不知道。你到底是什么意思?我只读过默认情况下 String 和 StringBuilder 是 unicode-16 ...
  • 没关系。 StringBuilder 字符串与常规字符串不同。你需要重写一个 .equals 方法来比较它们。
  • 好的,我会试着看看文档。他们总是说我使用 StringBuilder 因为它非常快而且你不会浪费内存......没有人提到与经典 String 有任何区别。而且我不知道如何重写和 .equals() 方法......
【解决方案2】:

根据您的上次更新。 “旧函数”和“新函数”结果之间的主要区别在于进位返回字符(我认为那里也缺少一个制表符)。无论如何,为避免此类问题,我建议您使用 JDK7 中引入的 System.lineSeparator():

返回系统相关的行分隔符字符串。它总是返回相同的值——系统属性 line.separator 的初始值。 在 UNIX 系统上,它返回 "\n";在 Microsoft Windows 系统上,它返回“\r\n”。 参考:https://docs.oracle.com/javase/7/docs/api/java/lang/System.html#lineSeparator()

此外,我建议您使用固定空间大小而不是 \t,因为不同的应用程序以不同的方式替换它。我的意思是在不同的标签大小。因此,例如,一个干净的解决方案可以创建一个名为 TAB : " " 的常量,并在您使用 \t 的任何地方替换它。

final String TAB = "  ";

最后,我注意到您将 StringBuilder 的值作为字符串返回,然后,我猜当您进行比较时,您将文本存储在某个 String 变量中。如果您初始化为 UTF-8 编码(仅举一个),这可能很有用。

【讨论】:

  • 感谢克里斯蒂安的友好回答。我知道缺少一个\r。问题是,当旧函数从数据库表中恢复时,以某种方式在每个 \n\t 组之前添加了一个 \r。我真的不知道为什么会发生这种情况,因为当函数从前端到达时,我们只有\n\t,但是在它被存储和恢复之后(可能是第一次),我们还有更多的\r,这会有所不同......为什么要添加?目前看来,比较之前的唯一解决方案是做if (!newFunctionBody.replaceAll("\\p{C}", "").equals(oldFunctionBody.replaceAll("\\p{C}", "")))
  • 我明白了,我忘记了你问题的第一部分,抱歉。您使用的数据库是什么,您现在使用的数据库是什么(名称、版本、SO)。他们是否在不同的 SO 中运行? .我想这可能是一个问题,因为在 unix 和窗口之间进行返回变化。我没有其他想法。
  • 我在 LINUX 机器上使用 Oracle DB 12(如果我没记错的话,它们是 Linux Red Hat 发行版)。然后,我正在 Windows 10 中开发和运行我们产品的 Swing 客户端
  • 但是问题只在第一次加载函数时出现...如果我在第一次之后添加/删除/编辑一个,其他的会按预期被忽略...那个该死的东西添加\r 字符似乎只出现一次...
  • 我猜这与 SO 有关,因为一个(UNIX)使用 \n 和其他(Win) \r\n 。但是,我不知道它只发生了一次,可能是因为加载函数时它们来自 db?。无论如何,这只是我的假设......对不起,我无法为您提供更多帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-01-29
  • 2014-07-15
  • 1970-01-01
  • 2021-01-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多