【问题标题】:How "contains()" method really work on List<string>?“contains()”方法如何在 List<string> 上真正起作用?
【发布时间】:2020-01-07 10:02:22
【问题描述】:

我正在尝试检查两个列表是否包含相同的值,但我无法弄清楚为什么这个特定值会触发我的 FileException

private static void checkFileHeaders(List<ColumnDefinition> columnsDefinitions, ArrayList<String> columnsName) throws FileException {
    for (ColumnDefinition cd : columnsDefinitions) {
        if(!columnsName.contains(cd.getFieldNameInFile())) {
            throw new FileException("Parameter "+cd.getFieldNameInFile() +" missing ");
        }
    }
}

正如我们在调试器中看到的那样,我的值存在于列表中,它可能与编码有关吗?它适用于其他值,但不适用于这个特定的值。

我知道 contains() 像 equals() 一样工作,所以这里有什么问题

如果我查看单个字符:

cd.getFieldNameInFile() : [90, 66, 75, 80, 70, 45, 66, 85, 75, 82, 83]

columnsName[0] : [-1, -2, 90, 0, 66, 0, 75, 0, 80, 0, 70, 0, 45, 0, 66, 0, 85, 0, 75, 0 , 82, 0, 83, 0]

如何解决这种差异,原因是什么?

【问题讨论】:

  • 根据文档,“返回 true 当且仅当此列表包含至少一个元素 e 使得 (o==null ? e==null : o.equals(e))。”您确定返回的表达式没有尾随空格吗?
  • 您在比较相同的数据类型吗?如果将 ColumnDefinition 与 String 进行比较,它们永远不会相等(检查 equals 协定),但调试器将使用它们的 toString 方法来显示值,因此它们看起来相等。
  • 列名可能来自带有 BOM 的文件(Windows?UTF-8/UTF-16 编码) - 可能您只需要更改该值的读取/(但因为我们没有 minimal reproducible example这只是一个疯狂的猜测)
  • @KevinCruijssen 不,这绝对是 UTF-16 ; 2 个第一个字节是 FF FE(BOM - 字节顺序标记);每个字符后跟 2 个字节(因为 ASCII 高阶为零)
  • 可能与stackoverflow.com/a/57726475/85421 类似的问题,即文件以UTF-8 BOM 开头(我只是想知道equals 没有正确处理这个问题,可能是因为读取错误的字符集......)

标签: java contains


【解决方案1】:

它检查每个元素,如果它是您正在测试的元素的equal()。意思是,如果两个元素通过equals() 方法测试,contains() 方法将为它们返回 true,如果equals() 方法返回 false,contains() 方法也是如此。

来自 Java 文档:

布尔包含(对象o)

如果此列表包含指定元素,则返回 true。更多的 正式地,当且仅当此列表包含至少一个时才返回 true 元素 e 使得 (o==null ? e==null : o.equals(e))。

文档链接

https://docs.oracle.com/javase/8/docs/api/java/util/List.html#contains-java.lang.Object-

【讨论】:

    【解决方案2】:

    显然getFieldNameInFile 不是字符串。所以应该采取toString

    private static void checkFileHeaders(List<ColumnDefinition> columnsDefinitions,
            List<String> columnsName) throws FileException {
        for (ColumnDefinition cd : columnsDefinitions) {
            if(!columnsName.contains(cd.getFieldNameInFile().toString()) {
                throw new FileException("Parameter "+cd.getFieldNameInFile() +" missing ");
            }
        }
    }
    

    使用流:

    private static void checkFileHeaders(List<ColumnDefinition> columnsDefinitions,
            Set<String> columnsName) throws FileException {
        if (columnsDefinitions.streams
                .map(ColumnDefinition::getFieldNameInFile)
                .map(Object::toString)
                .anyMatch(nm -> !columnsName.contains(nm)) {
            throw new FileException("Parameter " + cd.getFieldNameInFile() + " missing ");
        }
    }
    

    此外ArrayList 太具体了,请使用接口List,因为此方法适用于任何类型的 List 实现。

    对于containsSet&lt;String&gt; 会更快,例如HashSet&lt;&gt;

    【讨论】:

    • 是字符串 --
    • 为什么不应该是字符串?仅使用 UTF-16LE(显然)
    • 调试器中缺少双引号的差异导致我产生了这个想法。我想到了一个表达式之类的
    • Eclipse 中的表达式视图(我的猜测)没有为字符串表达式显示它们(有点不一致
    • @CarlosHeuberger 对(现在支持 IntelliJ IDEA)。
    【解决方案3】:

    我们忽略了考虑的是,即使为类定义了 equals() 方法,hashCode() 方法仍然值得关注(即使在这里您打算比较字符串也可能不是?)。

    为什么?

    contains 依赖于 equals 并且 equals 与 hashCode 一起工作,以判断我们在此处谈论的是否是同一个对象。

    equals-hashCode合同基础上恢复contains()工作 More documentation

    【讨论】:

      猜你喜欢
      • 2012-04-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多