我有以下字段和构造函数:
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中有一些实用工具?
答案 0 :(得分:13)
使用putAll()
很棒......如果你需要留在Properties
。它运行在O(number of elements)
并且开销很小。我建议的唯一区别是出于性能原因远离Properties
,除非您需要它,因为它继承自Hashtable
。另外,不要使用Properties
,因为它实际上并不符合任何接口,只是Dictionary
这是一个抽象类;这将限制您的选择。请参阅:What does it mean to "program to an interface"?
从Java 2平台v1.2开始,该类被改进以实现
Map
接口,使其成为Java Collections Framework的成员。与新的集合实现不同,Hashtable
是同步的。如果不需要线程安全实现,建议使用HashMap
代替Hashtable
。如果需要线程安全的高度并发实现,则建议使用ConcurrentHashMap
代替Hashtable。
无论您做什么,都不要使用clone()
,它不安全且不具备效果。请参阅:Java: Why shouldn't clone() be used for defensive copying?
你编辑了你的问题,询问关于番石榴和apache-commons的问题。如果它纯粹是防御性副本,并且它是不可变的,我建议使用Map<String, String> map = ImmutableMap.copyOf(properties)
。注意:同样,这不会使用实际的Properties
对象,因为除非您需要Hashtable
,否则不建议使用"test. 456. CREATED-BY-joe".partition("CREATED-BY-").last # => "joe"
。来自the wiki
当您不希望修改集合或期望集合保持不变时,将其防御性地复制到不可变集合中是一种很好的做法。
重要说明:每个Guava不可变集合实现都拒绝空值。我们对Google的内部代码库进行了详尽的研究,结果表明,大约5%的时间内,null元素在集合中被允许,而其他95%的情况最好是在空值上快速失败。如果需要使用空值,请考虑在允许null的集合实现上使用Collections.unmodifiableList及其朋友。更详细的建议可以在这里找到。
答案 1 :(得分:2)
属性实现Cloneable,因此如果您愿意,您可以执行以下操作。
this.properties = (Properties) properties.clone();
将此添加到您的班级
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
或者如果你担心使用clone,你的类也实现了serializable,所以你可以这样做。
import org.apache.commons.lang.SerializationUtils;
this.properties = SerializationUtils.clone(properties);
答案 2 :(得分:2)
试试这个:
Properties newProps = new Properties();
properties.forEach((key, value) -> {
newProps.setProperty((String) key, (String) value);
});
答案 3 :(得分:1)
或者你可以做到&#34; long&#34;方式:
Iterator i = properties.keySet().iterator();
while(i.hasNext()){
this.properties.put(i.next(), properties.get(i));
}
Iterator来自与属性相同的java.util包,因此没有外部依赖项。
如果关于未经检查的类型的编译器警告困扰您,您可以简单地将其更改为(假设您的属性键是字符串):
Iterator<Object> i = properties.keySet().iterator();
while(i.hasNext()){
this.properties.put(i.next().toString(), properties.get(i));
}
答案 4 :(得分:0)
以下程序将一个属性文件复制到另一个属性文件,并且还将删除重复的文件。源属性文件可能具有重复的属性,但是它将创建没有任何重复属性的新文件。
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();
}
}
}