使用Java系统属性的最佳实践

我们的代码使用了很多系统属性,例如’java.io.tmpdir’,’user.home’,’user.name’等。我们没有为这些定义任何常量(我认为也不是java)或者处理它们的任何其他聪明之处,因此它们在整个代码中都是乱七八糟的文本。

String tempFolderPath = System.getProperty("java.io.tmpdir"); 

每个人如何使用系统属性?

我会像处理代码中的任何其他字符串常量一样对待它,并为它定义一个常量变量。 当然,在这种情况下,“java.io.tmpdir”不太可能改变,但你永远不会知道。 (我并不是说Sun可能会改变“java.io.tmpdir”的含义,或者它指向的系统属性,但是您可能会改变您对需要阅读的系统属性的看法。)

如果您只在一个类中使用特定属性,那么我将在该类中定义常量。

 private final String TEMPDIR = "java.io.tmpdir"; 

如果您在不同的类中使用相同的属性,则可能需要定义自己的静态类来保存最常用的常量。

 public final Class Prop { public static final String TEMPDIR = "java.io.tmpdir"; ... } 

然后,无论您需要使用该常量,只需使用它即可

 System.getProperty(Prop.TEMPDIR); 

Apache Commons Lang包提供的SystemUtils解决了这个问题。

SystemUtils为大多数系统属性定义了常量,可以通过查找获得,例如:

 import org.apache.commons.lang3.SystemUtils; class Something { public static void main(String[] args){ System.out.println(SystemUtils.JAVA_IO_TMPDIR); } } 

也许,这是一种更清洁的方式。

如果你在多个地方使用它,那么编写一个类来封装读取属性和其他属性可能是个好主意。

所以可能是这样的:Configuration.getTemporaryDirectory()

我认为在面向对象的软件中,您可能有一个对象(或方法)依赖于必须完成作业的目录。 因此,您可以certificate这种依赖于构造函数或方法。 之后,如果您需要该目录的默认值并且默认值来自系统属性,则可以简单地创建一个工厂方法或构造函数/方法,将较少的参数传递给另一个costrunctor /方法a:

 new File(System.getProperty("java.io.tmpdir"); 

您不需要创建“依赖磁体”仅包含配置参数。

由于问题标题非常广泛,我将在使用系统属性时考虑另一个好的做法。 SecurityManager可以拒绝访问系统属性,因此您可能需要通过PrivilegedAction访问它们,如下所示:

 String tmpdir = AccessController.doPrivileged(new PrivilegedAction() { public String run() { return System.getProperty("java.io.tmpdir"); } }); 

当您的代码约束敏感操作时使用特权操作,以便即使恶意代码调用它也是安全的。

例如,在诸如OutputStream open(File file)类的方法中使用特权操作是不安全的。 不受信任的代码可以调用它,并使用您的代码的权限在任何地方编写任何内容。

但是,如果您有一个方法将应用程序的用户首选项保存到您选择的文件中,那么这可能是安全的。 恶意呼叫者无法选择文件位置或其内容; 这些是由您的代码指定的。 因此,您的方法可以使用特权操作来允许由非特权代码调用它。

我将它们视为任何其他常量,可能带有P_PROP_前缀,并将它们放在适当的常量类中。

如果你使用了很多,我甚至会考虑将它们拆分为PropertyNames常量类:

 public final class PropertyNames { private PropertyNames() { // no instantiation } public static final String P_VAR_DIRECTORY = "org.acme.app.varDir"; public static final String P_TMP_DIRECTORY = "java.io.tmpDir"; } 

最后,我会认真考虑使用用于包的标准反向域名来命名属性名称本身。 这只是为了避免与第三方属性消费者发生冲突。

在Java中,字符串是不可变的,这意味着内存空间中的相同对象不会被覆盖; 每次都会创建一个新的String。 目前投票最高的建议是使用常数:

 System.getProperty(Prop.TEMPDIR); 

不幸的是,使用的常量是实际的属性键。 这意味着每次进行此调用时,您将创建一个新的String对象来保存该值。 在我看来,你应该使调用本身的结果为常量:

 public static final String SYS_PROP_TEMP_DIR = System.getProperty("java.io.tmpdir");