【问题标题】:What happens when there are duplicate keys in Java properties file?当 Java 属性文件中有重复键时会发生什么?
【发布时间】:2012-09-15 12:14:39
【问题描述】:

当 Java .properties 文件中存在重复键时,定义的行为是什么?

thing.valueA = 1
thing.valueB = 2

thing.valueA = 99

保证thing.valueA 使用哪个值? 1、99 还是未定义?这种行为是否记录在任何地方?

注意。我不是在问重复键是否被认为是最佳实践。

【问题讨论】:

标签: java properties configuration


【解决方案1】:

根据我对Properties 的理解,加载方法的工作方式与此类似:

  1. 将文件分成几行,
  2. 看下一行,
  3. 使用一些规则确定键值对(参见here
  4. 以类似于put() 方法的方式将键值对放入 Properties 实例中

这意味着您的示例将显示99

load 方法的基本设计就像您坐下来打字一样

propInstance.put("Key", "Value");
propInstance.put("Other", "Thing");
etc etc

要了解此行为,请参阅Hashtable.put() 的文档,该文档指定它使用新值更新所有重复项。由于 Hashtable 是 Properties 的超类,Properties 也复制了这种行为。

【讨论】:

  • 这很有帮助,很有见地,jozefg。我希望有一些更直接和明确的东西,但这太棒了!合理地,这个答案假设属性文件是从头到尾按顺序读取的。我很高兴能接受这种假设......
  • @aaaidan 对其进行了编辑,使其更简洁明了
  • 我想我实际上更喜欢你以前的答案,但是好吧!关于继承自 HashTable 的属性的部分有助于我接受这种行为可能是一致的(因为认为Reader 会以除自上而下之外的任何方式遍历列表是很疯狂的)。
【解决方案2】:

因为这在类的规范中没有定义,我想说这个问题的最正确答案是结果是未定义的,并且可能因实现而异。

但是,因为 java.util.Properties 继承自 java.utils.Hashtable,所以最有可能的实现与@jozefg 所描述的完全一样,您可以在 OpenJDK 源代码中看到 Sun 实现以这种方式工作 (Properties.java:345截至撰写本文时)。读取每一行,解析它以确定是否需要附加其他行,分离键和值,将键/值放入 Hashtable。

没有:

  • 检查密钥是否存在
  • 基于键的存在引发异常
  • 避免覆盖值
  • 乱序处理

这一切都非常简单,基本上假设你没有使用重复的键,或者如果你有,那就是你的问题要解决。

现在,当然,要完全确定您想要查看所有可能的 JVM 或至少查看代码的目标 JVM,以确保实现没有差异,但我认为这个实现是最可能是一个。

【讨论】:

  • 当我遇到这个问题时,这个问题已经很老了,但我很好奇答案是什么,并且由于没有一个答案涉及实际的实现,因此似乎值得检查,并且这样做了,记录下一个人的答案。
  • 谢谢。我更喜欢您的回答,因为它承认重复行为是未定义的,但是由于实施(以及文件的从头到尾读取),重复行为在实践中可能非常可靠。干杯。
【解决方案3】:

这对我有用。我没有使用属性,而是实例化了一个 NaehasProperties,并覆盖了 HashTable put()。

/**
 *  Purpose:  Properties doesn't detect duplicate keys.  So this exists.
 *  @author shaned
 */
package com.naehas.tests.configs;

import java.util.Properties;

import org.apache.log4j.Logger;

public class NaehasProperties extends Properties
{
   private static final long   serialVersionUID = 1L;

   private static final Logger log              = Logger.getLogger(NaehasProperties.class);

   public NaehasProperties()
   {
      super();
   }

   /**
    * @param defaults
    */
   public NaehasProperties(Properties defaults)
   {
      super(defaults);
   }

   /**
    * Overriding the HastTable put() so we can check for duplicates
    * 
    */
   public synchronized Object put(Object key, Object value)
   {
      // Have we seen this key before?
      //
      if (get(key) != null)
      {
         StringBuffer message = new StringBuffer("Duplicate key found: " + key + " with value: " + value);
         message.append(". Original value is: " + (String) get(key));

         log.error(message.toString());

         // Setting key to null will generate an exception and cause an exit.
         // Can not change the signature by adding a throws as it's not compatible
         // with HashTables put().
         //
         key = null;
      }

      return super.put(key, value);
   }
}

【讨论】:

  • 这是剖析当前实现的绝佳方式。我想知道的是覆盖行为是否指定。换句话说,我是否可以指望它总是以这种方式运行,或者 Java 的未来实现可能会改变这一点?
  • "将密钥设置为null 将产生异常并导致退出。无法通过添加throws 来更改签名,因为它与HashTable 的put() 不兼容" 实际上,如果您确实需要在不添加throws 的情况下抛出异常,您可以抛出RuntimeException 或其任何子类。我特别喜欢IllegalStateExceptionIllegalArgumentException,但在这种情况下,UnsupportedOperationExceptionArrayStoreException 可能更合适[使用java.lang 包]。
  • 为了在单元测试中使用,我没有将键设置为 null 或抛出异常。相反,我将密钥保存在 duplicateKeys 字符串集合中。然后单元测试可以测试 this 是否为空,并获取所有重复键的名称。如果抛出异常,则单元测试的处理可能会停止,您只会得到 first 重复键。
【解决方案4】:

它通常取最后一个值,在你的情况下它将是 99。

谢谢, 拉格万

【讨论】:

  • “通常”部分是问题所在......我在问我是否可以保证永远都是这种情况。谢谢!
猜你喜欢
  • 2013-04-29
  • 2010-12-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-08
  • 2014-11-13
  • 2016-04-05
  • 2020-08-17
相关资源
最近更新 更多