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

Michal Kordas picture Michal Kordas · Aug 6, 2015 · Viewed 13.7k times · Source

I have the following field and constructor:

private final Properties properties;

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

The good practice is to make copy of every mutable collection in constructor. I want to make a shallow, independent copy. How can I achieve that?

My first idea was to use putAll() method:

private final Properties properties = new Properties();

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

Is there any simpler, more performant or more idiomatic way of doing that? Maybe there are some utils for that in Guava or Apache Commons?

Answer

durron597 picture durron597 · Aug 6, 2015

Using putAll() is great... if you need to stay with Properties. It runs in O(number of elements) and has very little overhead. The only difference I would recommend is to stay away from Properties for performance reasons unless you need it, because it inherits from 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.

Whatever you do, do not use clone(), it is not secure and not performant. See: Java: Why shouldn't clone() be used for defensive copying?


You edited your question to ask about Guava and apache-commons. If it's purely a defensive copy, and it's immutable, I would recommend using 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.