我有一个像这样的属性文件 -
emailFrom=hello@abc.com
emailTo=world@abc.com
# can be separated by comma
whichServer=UserServer,GuestServer
maxTestInSec=120
numberOfUsers=1000
现在我正在 Java 中读取这个属性文件,如果一切设置正确,它就可以工作 -
private static final Properties prop = new Properties();
private static String emailFrom;
private static String emailTo;
private static List<String> whichServer;
private static String maxTestInSec;
private static String numberOfUsers;
public static void main(String[] args) {
readConfig(args);
}
private void readConfig(String[] args) throws FileNotFoundException, IOException {
if (!TestUtils.isEmpty(args) && args.length != 0) {
prop.load(new FileInputStream(args[0]));
} else {
prop.load(TestTask.class.getClassLoader().getResourceAsStream("config.properties"));
}
emailFrom = prop.getProperty("emailFrom").trim();
emailTo = prop.getProperty("emailTo").trim();
whichServer = Arrays.asList(prop.getProperty("whichServer").trim().split(","));
maxTestInSec = prop.getProperty("maxTestInSec").trim();
numberOfUsers = prop.getProperty("numberOfUsers").trim();
}
问题陈述:-
我需要确保如果缺少任何属性值,那么我想使用默认值,如果有任何机会该属性被注释掉,那么我也想使用默认值,但我会记录一个警告消息指出该属性丢失或为空,因此使用默认值。我试图涵盖读取文件的所有极端情况 -
- 现在假设,如果我没有为上述文件中的任何属性指定值,那么我想使用我未提供的属性的默认值,并记录为警告,指出没有值已为此属性提供,因此使用默认值。例如:假设我没有为
emailFrom
字段提供任何值,那么我想使用默认值hello@abc.com
来实现类似的功能为他人。所有属性的默认值为:
emailFrom=hello@abc.com
emailTo=world@abc.com
whichServer=UserServer
maxTestInSec=30
numberOfUsers=500
- 此外,如果任何属性被注释掉,则上述代码将通过 NPE 异常。在这种情况下如何使用默认值?
我应该开始使用命令行解析器吗?处理这些东西的最佳且干净的方法是什么?
我不想有很多 if block 来添加检查,然后设置默认值。
最佳答案
从 Java 8 开始,最简单的事情就是使用 getOrDefault()
它允许您在 get-site 指定默认值。例如:
String email = properties.getOrDefault("emailFrom", "hello@abc.com");
这简洁明了,但确实意味着您需要在访问该属性的任何地方指定默认值。
如果这对您不起作用(即您将多次从属性对象中读取值),您可以使用对默认值的内置支持 - 请注意 constructor它采用 default
Properties
对象。这使您可以构造一个包含默认值的 Properties
对象,然后当您加载用户的属性文件时,如果用户未指定值,它将回退到默认值。
private static final Properties DEFAULTS = new Properties();
static {
DEFAULTS.setProperty("emailFrom", "hello@abc.com");
}
public Properties getProperties() {
Properties props = new Properties(DEFAULTS);
props.load(...);
return props;
}
请注意,这与 Map
的构造函数的工作方式不同 - 默认值保留为单独的映射,并且只有 .getProperty()
也会查询默认值; Map
中定义的方法(如 .get()
)则不然。 Properties
扩展 Hashtable
是一个糟糕的决定,这是众多原因之一,但这就是生活......
这些选项有效,但它们都容易出错,因为 a) Properties
是可变的,b) 只有它的一些公共(public)方法会回退到 default
实例。我宁愿永远不要直接公开 Properties
对象,而是使用类型安全的方法创建一个包装类,该方法公开我的应用程序将关心的值。这需要更多的打字,但使用起来更安全。它看起来像这样:
public class ApplicationSettings {
private final Properties properties = new Properties();
public ApplicationSettings() {
properties.load(...);
}
public String emailFrom() {
// simple methods are concise, and encode the default right inline
return properties.getOrDefault("emailFrom", "hello@abc.com");
}
public int getMaxTestSeconds() {
// You can do more complex validation if you want, too
String value = properties.get("maxTestInSec");
if (value == null) {
return 30;
}
int maxTestSeconds = Integer.parseInt(value);
if (maxTestSeconds <= 0) {
// could instead log a warning and return the default if you want
throw new IllegalStateException(
"maxTestInSec must be positive - was " + maxTestSeconds);
}
return maxTestSeconds;
}
}
如果需要,您还可以公开 setter ,在将值添加到 Properties
对象之前以类似方式验证值,不过默认情况下将所有内容设置为只读通常是一个很好的做法。
关于java - 如何安全地读取Java中的属性文件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27812810/