Java 数据结构——Properties
前面我们介绍了各种各样的Map ,今天我们介绍一个我们常用来保存程序运行配置参数的一个类,Properties 它的操作和Map 非常像,不一样的是它提供了和文件的交互操作,也就是说我们的配置可以保存到文件里或者是从文件里加载。
源代码
首先我们看一下这个类的继承关系,我们看到它继承的是Hashtable,也就是说这个类是线程安全的,这是因为继承自Hashtable 的方法是线程安全的,而且它自定义的方法也是安全的
这个类的方法也比较多,但是都很简单,我们重点关注几个常用的
Properties 基本操作
其实作为一个系统属性存储的这样一个类而言,我们关注的属性的设置、获取、以及保存和加载即可
@Test
public void test(){
Properties capitals = new Properties();
capitals.put("Illinois", "Springfield");
capitals.put("Missouri", "Jefferson City");
capitals.put("Washington", "Olympia");
capitals.put("California", "Sacramento");
capitals.put("Indiana", "Indianapolis");
// 可以提供默认值
String str = capitals.getProperty("Florida", "Not Found");
System.out.println(str);
// 保存
try (OutputStream outputStream = new FileOutputStream("program.properties")){
capitals.store(outputStream,"program properties");
} catch (IOException e) {
e.printStackTrace();
}
// 清空
capitals.clear();
System.out.println(capitals);
// 加载
try( InputStream inputStream = new FileInputStream("program.properties")) {
capitals.load(inputStream);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(capitals);
}
下面是我们保存到文件里的内容
其实我们还可以保存为XML 文件或者从XML 文件里加载
系统属性
我们知道Java程序运行时是有一些系统属性的,Java也给我们提供了相关的Api 获取
@Test
public void test2(){
Properties properties = System.getProperties();
System.out.println(properties);
//
System.out.println(properties.getProperty("user.home"));
}
这个里面的东西是比较多的,我们可以将这个信息打印出来自行查看
{java.runtime.name=OpenJDK Runtime Environment, sun.boot.library.path=/Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home/jre/lib, java.vm.version=25.275-b01, gopherProxySet=false, jdk.vendor.version=Zulu 8.50.0.1017-CA-macos-aarch64, java.vm.vendor=Azul Systems, Inc., java.vendor.url=http://www.azulsystems.com/, path.separator=:, java.vm.name=OpenJDK 64-Bit Server VM, file.encoding.pkg=sun.io, user.country=CN, sun.java.launcher=SUN_STANDARD, sun.os.patch.level=unknown, java.vm.specification.name=Java Virtual Machine Specification, user.dir=/Users/kingcall/workspace/idea/interview/algorithm, java.runtime.version=1.8.0_275-b01, java.awt.graphicsenv=sun.awt.CGraphicsEnvironment, java.endorsed.dirs=/Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home/jre/lib/endorsed, os.arch=aarch64, java.io.tmpdir=/var/folders/n_/jzy4cp_144n2tvbf7d1b34qh0000gn/T/, line.separator=
, java.vm.specification.vendor=Oracle Corporation, os.name=Mac OS X, sun.jnu.encoding=UTF-8, java.library.path=/Users/kingcall/Library/Java/Extensions:/Library/Java/Extensions:/Network/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java:., java.specification.name=Java Platform API Specification, java.class.version=52.0, sun.management.compiler=HotSpot 64-Bit Tiered Compilers, os.version=12.5, http.nonProxyHosts=192.168.0.0/16|*.192.168.0.0/16|10.0.0.0/8|*.10.0.0.0/8|172.16.0.0/12|*.172.16.0.0/12|127.0.0.1|localhost|*.localhost|local|*.local, user.home=/Users/kingcall, user.timezone=, java.awt.printerjob=sun.lwawt.macosx.CPrinterJob, file.encoding=UTF-8, java.specification.version=1.8, java.class.path=...}
Properties 的操作建议
Properties 提供的关于文件的操作我们直接使用即可,但是关于属性的设置和获取还是建议通过setProperty 和getProperty 这是为什么呢?
因为put 和get 是map 提供的方法,但是这两个方法我们可以放任何值进去,但是setProperty 和getProperty由于是自定义实现的所以只能操作字符串。
Preferences
Properties提供的应用程序解决方案主要存在两个问题:
- 配置文件不能放在主目录中,因为某些OS(如Win9X)没有主目录的概念;
- 没有标准的文件命名规则,存在文件名冲突的可能性。
Java中的Preferences类可以解决这些问题。Preferences提供一个存储配置信息的中心知识库,与平台无关。在Windows系统中,它存储在注册表中,在Linux中存储在本地文件系统中。它的实现是透明的,程序员无需深究它的底层是如何实现的。
Preferences本身是个抽象类,它有三个不同的工厂类,可以根据不同平台生产对应的Preferences类。Java源码如下
// 3. Use platform-specific system-wide default
String osName = System.getProperty("os.name");
String platformFactory;
if (osName.startsWith("Windows")) {
platformFactory = "java.util.prefs.WindowsPreferencesFactory";
} else if (osName.contains("OS X")) {
platformFactory = "java.util.prefs.MacOSXPreferencesFactory";
} else {
platformFactory = "java.util.prefs.FileSystemPreferencesFactory";
}
Preferences的中心知识库是树状结构,因此可以避免文件名冲突。每个用户都有一棵树,存放与本用户有关的配置;还有一个系统树,存放全体用户的公共信息。内部的配置信息仍然以key-value的结构进行存储。
Preferences的使用步骤如下:
1.获得根节点
Preferences root = Preferences.userRoot();
Preferences root = Preferences.systemRoot();
如果配置信息位于用户树,则获取用户树的根节点,否则获取系统树根节点;
2.获取配置节点
preferences = root.node("path");
path是配置节点相对于根节点的路径;
如果节点的路径名与类的包名相同,则可通过类的对象直接获得配置节点:
Preferences node = Preferences.userNodeForPackage(this.getClass()); Preferences node = Preferences.systemNodeForPackage(this.getClass());
3.读取配置项
String title = preferences.get("title", "default title");
Preferences要求读取配置项时必须指定默认值。因为在实际环境中总会有各种不如意,比如系统中还没有中心知识库,或者网络暂时不可用等等。
4.设置配置项
preferences.put(key, value);
5.同步配置项
preferences.flush();
flush()方法用于立即将配置项写入到文件中。
总结
Properties 在我们写代码中还是比较常用的,所以我们知道有这个东西就行了,在我们需要一些配置选项的时候就可以使用Properties 来完成需求。