调用静态java.text.DateFormat的方法不可取吗?

set*_*ora 43 java static

我收到一个Find Bugs错误 - 调用静态java.text.DateFormat的方法,我不知道为什么在下面做这些事情不好/可取的原因.

private static final Date TODAY = Calendar.getInstance().getTime();
private static final DateFormat yymmdd = new SimpleDateFormat("yyMMdd"); 

private String fileName = "file_" + yymmdd.format(TODAY);
Run Code Online (Sandbox Code Playgroud)

Rob*_*ska 82

DateFormats不是线程安全的,这意味着它们维护状态的内部表示.如果多个线程同时访问同一个实例,在静态上下文中使用它们会产生一些非常奇怪的错误.

我的建议是将变量置于您使用它们的位置,而不是使它们成为类的静态属性.在初始化类时,您可能正在执行此操作,因此您可以在构造函数中执行此操作:

public class MyClass {
    private String fileName;

    public MyClass() {
        final Date today = Calendar.getInstance().getTime();
        final DateFormat yymmdd = new SimpleDateFormat("yyMMdd"); 

        this.fileName = "file_" + yymmdd.format(TODAY);
    }
    ...
}
Run Code Online (Sandbox Code Playgroud)

如果您需要在多个位置使用格式化程序,您可以在需要时static final创建模式并创建新的本地化DateFormat:

public class MyClass {
    private static final String FILENAME_DATE_PATTERN = "yyMMdd";

    public void myMethod() {
        final DateFormat format = new SimpleDateFormat(FILENAME_DATE_PATTERN);
        // do some formatting
    }
}
Run Code Online (Sandbox Code Playgroud)

该问题的FindBugs文档说:

正如JavaDoc所述,DateFormats对于多线程使用本质上是不安全的.检测器找到了一个通过静态字段获得的DateFormat实例的调用.这看起来很可疑.

有关这方面的更多信息,请参阅Sun Bug#6231579和Sun Bug#6178997.

DateFormatjavadoc建议:

日期格式未同步.建议为每个线程创建单独的格式实例.如果多个线程同时访问格式,则必须在外部进行同步.

Jack Leow的答案对于静态使用"TODAY"的语义也有一个很好的观点.

另外,我实际上已经看到这种情况发生在高流量的生产环境中,最初调试是一件非常令人困惑的事情.所以根据我的经验,FindBugs警告实际上是一个有用的建议(不像其他一些静态分析规则,有时似乎是挑剔的).

  • `final`只表示*reference*不能被重新分配 - 引用指向的对象的内容不能保证"final"的存在. (6认同)
  • 我不太确定,我认为每次调用 myMethod() 时都创建 SimpleDateFormat 太昂贵了。 (2认同)

ScA*_*er2 15

Commons Lang有一个线程安全的FastDateFormat对象.它只进行格式化,而不是解析.

如果你可以使用commons-lang,这可能适合你.

private static final Date TODAY = Calendar.getInstance().getTime();
private static final FastDateFormat yymmdd = FastDateFormat.getInstance("yyMMdd");

private String fileName = "file_" + yymmdd.format(TODAY);
Run Code Online (Sandbox Code Playgroud)


Wim*_*uwe 5

尚未提及的替代方案是使用 ThreadLocal。有关更多信息以及 3 个选项之间的性能比较,请参阅http://www.javacodegeeks.com/2010/07/java-best-practices-dateformat-in.html :

  • 每次创建一个实例
  • 同步访问
  • 使用ThreadLocal

使用 ThreadLocal 的示例:

private static final ThreadLocal<SimpleDateFormat> DATE_FORMAT = new ThreadLocal<SimpleDateFormat>() {
    @Override
    protected SimpleDateFormat initialValue() {
        return new SimpleDateFormat("yyMMdd");
    }
};
Run Code Online (Sandbox Code Playgroud)

用法:

DATE_FORMAT.get().format( TODAY )
Run Code Online (Sandbox Code Playgroud)