如何复制 java.util.Properties 对象?

How do I make a copy of java.util.Properties object?

我有以下字段和构造函数:

private final Properties properties;

public PropertiesExpander(Properties properties) {
    this.properties = properties;
}

好的做法是在构造函数中复制每个可变集合。我想做一个浅的、独立的副本。我怎样才能做到这一点?

我的第一个想法是使用 putAll() 方法:

private final Properties properties = new Properties();

public PropertiesExpander(Properties properties) {
    this.properties.putAll(properties);
}

有没有更简单、更高效或更惯用的方法来做到这一点?也许在 Guava 或 Apache Commons 中有一些实用程序?

使用 putAll() 很棒...如果您需要继续使用 Properties。它在 O(number of elements) 中运行并且开销很小。我建议的唯一区别是出于性能原因远离 Properties 除非你需要它,因为它继承自 Hashtable. Also, don't use Properties because it doesn't actually conform to any interface, just Dictionary which is an abstract class; this will limit your options. See: What does it mean to "program to an interface"?

As of the Java 2 platform v1.2, this class was retrofitted to implement the Map interface, making it a member of the Java Collections Framework. Unlike the new collection implementations, Hashtable is synchronized. If a thread-safe implementation is not needed, it is recommended to use HashMap in place of Hashtable. If a thread-safe highly-concurrent implementation is desired, then it is recommended to use ConcurrentHashMap in place of Hashtable.

无论你做什么,都不要使用 clone() 它既不安全也不高效。参见:


您编辑了问题以询问有关 Guava 和 apache-commons 的问题。如果是纯粹的防御副本,而且是不可变的,我会推荐使用Map<String, String> map = ImmutableMap.copyOf(properties). Note: again, this doesn't use an actual Properties object because Hashtable is not recommended unless you need it. From the wiki

When you don't expect to modify a collection, or expect a collection to remain constant, it's a good practice to defensively copy it into an immutable collection.

Important: Each of the Guava immutable collection implementations rejects null values. We did an exhaustive study on Google's internal code base that indicated that null elements were allowed in collections about 5% of the time, and the other 95% of cases were best served by failing fast on nulls. If you need to use null values, consider using Collections.unmodifiableList and its friends on a collection implementation that permits null. More detailed suggestions can be found here.

Properties 实现了 Cloneable,因此您可以根据需要执行以下操作。

this.properties = (Properties) properties.clone();

将此添加到您的 class

protected Object clone() throws CloneNotSupportedException {
    return super.clone();
}

或者,如果您担心使用克隆,您的 class 也实现了可序列化,因此您可以这样做。

import org.apache.commons.lang.SerializationUtils;

this.properties = SerializationUtils.clone(properties);

Properies

Cloneable

或者您可以按 "long" 方式进行:

    Iterator i = properties.keySet().iterator();
    while(i.hasNext()){
        this.properties.put(i.next(), properties.get(i));
    }

迭代器与属性来自同一个 java.util 包,因此没有外部依赖性。

如果编译器关于未检查类型的警告困扰您,您可以简单地将其更改为(假设您的 属性 键是字符串):

    Iterator<Object> i = properties.keySet().iterator();
    while(i.hasNext()){
        this.properties.put(i.next().toString(), properties.get(i));
    }

试试这个:

Properties newProps = new Properties();
properties.forEach((key, value) -> {
    newProps.setProperty((String) key, (String) value);
});

下面的程序将一个 属性 文件复制到另一个文件,并且还会删除重复项。源 属性 文件可能有重复的属性,但它会创建没有任何重复属性的新文件。

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Properties;
import java.util.Set;

public class App2 {

    public static void main(String[] args) {

        try (InputStream input = new FileInputStream("config.properties")) {

            Properties prop = new Properties();

            // load a properties file
            prop.load(input);

            writeToNewProperties(prop);
        } catch (IOException ex) {
            ex.printStackTrace();
        }

    }

    private static void writeToNewProperties(Properties prop) {
        Properties outPutProp = new Properties();
        // get the property value and print it out
        Set<String> stringPropertyNames = prop.stringPropertyNames();
        for (String propertyName : stringPropertyNames) {
            outPutProp.put(propertyName, prop.get(propertyName));
        }

        try (OutputStream output = new FileOutputStream("out-config.properties")) {
            // save properties to project root folder
            outPutProp.store(output, null);
            System.out.println(outPutProp);
        } catch (IOException io) {
            io.printStackTrace();
        }
    }

}

另一种方法就是

Properties newVersion = new Properties(originalVersion);

它将表现为最初作为originalVersion的副本,除非newVersion中的键被删除,它将恢复为originalVersion 中存储的值。实际上,originalVersion 表现为默认的 key/value 集。