Java SimpleDateFormat不可设置为static final

简介: Java SimpleDateFormat不可设置为static final

Java SimpleDateFormat不可设置为static final,否则将会出现“ java.lang.NumberFormatException: multiple points”错误,那么究竟是为什么呢?


首先,请随小编来看看一个用到SimpleDateFormat的日期转换类。

package com.mwq.format;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateUtils {
    /**
     * yyyy-MM-dd formatter
     */
    private static final SimpleDateFormat YMD_DASH_FORMATTER = new SimpleDateFormat("yyyy-MM-dd");
    public static long getTimeMillisSpecifyDaysBaseOnToday(int days) {
        long millis = 0l;
        try {
            Date dateTomorrow = new Date();
            String tomorrow = YMD_DASH_FORMATTER.format(dateTomorrow);
//          System.out.println(tomorrow);
            Date tomorrownew = YMD_DASH_FORMATTER.parse(tomorrow);
            millis = tomorrownew.getTime();
        } catch (ParseException e) {
        }
        return millis;
    }
}

内容很简单,静态初始化一个SimpleDateFormat,然后用它来转换一个凌晨的时间戳,用到了SimpleDateFormat的format和parse方法。

类看起来似乎没什么问题,反正我是没找出什么理由来证明它写的有问题!(小编的编程水平有限啊!)


其次,我们写个测试类调用一下。

package com.mwq.format;
public class Test {
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            Thread thread1 = new Thread() {
                public void run() {
                    System.out.println(DateUtils.getTimeMillisSpecifyDaysBaseOnToday(0));
                }
            };
            thread1.start();
        }
    }
}


主类循环10此而已,创造线程来调用getTimeMillisSpecifyDaysBaseOnToday方法,也仅此而已。


然后,我们来看看结果。


1436544000000
1436544000000
835200000
1436544000000
1436544000000
835200000
Exception in thread "Thread-2" java.lang.NumberFormatException: multiple points
    at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1084)
    at java.lang.Double.parseDouble(Double.java:510)
    at java.text.DigitList.getDouble(DigitList.java:151)
    at java.text.DecimalFormat.parse(DecimalFormat.java:1303)
    at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1538)
    at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1263)
    at java.text.DateFormat.parse(DateFormat.java:335)
    at com.mwq.format.DateUtils.getTimeMillisSpecifyDaysBaseOnToday(DateUtils.java:20)
    at com.mwq.format.Test$1.run(Test.java:10)
Exception in thread "Thread-9" java.lang.NumberFormatException: multiple points
1436544000000
    at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1084)
    at java.lang.Double.parseDouble(Double.java:510)
    at java.text.DigitList.getDouble(DigitList.java:151)
    at java.text.DecimalFormat.parse(DecimalFormat.java:1303)
    at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1538)
    at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1263)
    at java.text.DateFormat.parse(DateFormat.java:335)
1436544000000
    at com.mwq.format.DateUtils.getTimeMillisSpecifyDaysBaseOnToday(DateUtils.java:20)
    at com.mwq.format.Test$1.run(Test.java:10)

什么?输出了一大推错误!


查看一下源码吧!


/**
     * Returns a new <code>double</code> initialized to the value
     * represented by the specified <code>String</code>, as performed
     * by the <code>valueOf</code> method of class
     * <code>Double</code>.
     *
     * @param      s   the string to be parsed.
     * @return the <code>double</code> value represented by the string
     *         argument.
     * @exception NumberFormatException if the string does not contain
     *            a parsable <code>double</code>.
     * @see        java.lang.Double#valueOf(String)
     * @since 1.2
     */
    public static double parseDouble(String s) throws NumberFormatException {
    return FloatingDecimal.readJavaFormatString(s).doubleValue();
    }


如果这个字符串没有包含一个可转换的double,那么就会抛出NumberFormatException 异常。

当然这个解释对于上面出现错误,似乎没有什么好解释的。


那么,我们再来看看SimpleDateFormat的API doc解释。


parse

public Date parse(String text,

                 ParsePosition pos)解析字符串的文本,生成 Date。

此方法试图解析从 pos 给定的索引处开始的文本。如果解析成功,则将 pos 的索引更新为所用最后一个字符后面的索引(不必对直到字符串结尾的所有字符进行解析),并返回解析得到的日期。更新后的 pos 可以用来指示下次调用此方法的起始点。如果发生错误,则不更改 pos 的索引,并将 pos 的错误索引设置为发生错误处的字符索引,并且返回 null。



指定者:

类 DateFormat 中的 parse

参数:

text - 应该解析其中一部分的 String。

pos - 具有以上所述的索引和错误索引信息的 ParsePosition 对象。

返回:

从字符串进行解析的 Date。如果发生错误,则返回 null。

抛出:

NullPointerException - 如果 text 或 pos 为 null。

另请参见:

DateFormat.setLenient(boolean)

也就是说,String tomorrow = YMD_DASH_FORMATTER.format(dateTomorrow);

// System.out.println(tomorrow);

Date tomorrownew = YMD_DASH_FORMATTER.parse(tomorrow);

产生了空指针引用。


其实,再回看我们的日志信息,我们其实可以发现一些端倪。


835200000

1436544000000

1436544000000

835200000

如果一切正常的话,都应该输出“1436544000000”才对的,为什么出现了“835200000”?

再看看


此方法试图解析从 pos 给定的索引处开始的文本。如果解析成功,则将 pos 的索引更新为所用最后一个字符后面的索引(不必对直到字符串结尾的所有字符进行解析),并返回解析得到的日期。更新后的 pos 可以用来指示下次调用此方法的起始点。如果发生错误,则不更改 pos 的索引,并将 pos 的错误索引设置为发生错误处的字符索引,并且返回 null。

这段话,你也许就恍然大悟了,在多线程并发情况下,SimpleDateFormat显然不够安全!

当然,这样的解释是我杜撰的!


那么,怎么来避免这样的错误呢?

     1.DateUtils类中getTimeMillisSpecifyDaysBaseOnToday方法中打印一下tomorrow,或者随便输出一些东西就好了。


package com.mwq.format;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateUtils {
    /**
     * yyyy-MM-dd formatter
     */
    private static final SimpleDateFormat YMD_DASH_FORMATTER = new SimpleDateFormat("yyyy-MM-dd");
    public static long getTimeMillisSpecifyDaysBaseOnToday(int days) {
        long millis = 0l;
        try {
            Date dateTomorrow = new Date();
            String tomorrow = YMD_DASH_FORMATTER.format(dateTomorrow);
            System.out.println(tomorrow);
//          System.out.println("111111111111");
            Date tomorrownew = YMD_DASH_FORMATTER.parse(tomorrow);
            millis = tomorrownew.getTime();
        } catch (ParseException e) {
        }
        return millis;
    }
}


     2.DateUtils类中的YMD_DASH_FORMATTER放错了位置,换成以下这样话,就不会有问题了。


package com.mwq.format;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateUtils {
    /**
     * yyyy-MM-dd formatter
     */
    public static long getTimeMillisSpecifyDaysBaseOnToday(int days) {
        long millis = 0l;
        try {
            SimpleDateFormat YMD_DASH_FORMATTER = new SimpleDateFormat("yyyy-MM-dd");
            Date dateTomorrow = new Date();
            String tomorrow = YMD_DASH_FORMATTER.format(dateTomorrow);
//          System.out.println(tomorrow);
//          System.out.println("");
            Date tomorrownew = YMD_DASH_FORMATTER.parse(tomorrow);
            millis = tomorrownew.getTime();
        } catch (ParseException e) {
        }
        return millis;
    }
}


总结:其实这个时候,我不知道该说些什么?一则因为自己从来都没有对Java深入浅出过,二则因为如果不是读《effective Java 》,想用上面的思路应用到项目中造成的错误也不会有上面这些说辞,不过遇到问题探究一下总归是不错的。


相关文章
|
11月前
|
存储 IDE Java
java设置栈内存大小
在Java应用中合理设置栈内存大小是确保程序稳定性和性能的重要措施。通过JVM参数 `-Xss`,可以灵活调整栈内存大小,以适应不同的应用场景。本文介绍了设置栈内存大小的方法、应用场景和注意事项,希望能帮助开发者更好地管理Java应用的内存资源。
566 4
|
11月前
|
数据采集 算法 Java
如何在Java爬虫中设置动态延迟以避免API限制
如何在Java爬虫中设置动态延迟以避免API限制
|
12月前
|
存储 安全 Java
探索 Java 静态变量(static)的奥秘
本文深入探讨了Java中的静态变量(`static`),从初印象、使用场景、访问方式、初始化、线程安全、优缺点到最佳实践,全面解析其特性和应用场景。静态变量属于类而非实例,适用于共享数据、定义全局常量和工具类中的变量。它在类加载时初始化,生命周期贯穿整个程序运行。然而,多线程环境下需注意线程安全问题,可通过`synchronized`或原子类解决。优点包括共享数据方便和提高性能,但也存在线程安全和代码耦合度增高的缺点。最佳实践建议谨慎使用、保证线程安全、遵循命名规范并封装访问。掌握静态变量的正确用法,能让你的代码更加高效简洁。
779 11
|
12月前
|
Java Linux iOS开发
如何配置 Java 环境变量:设置 JAVA_HOME 和 PATH
本文详细介绍如何在Windows和Linux/macOS系统上配置Java环境变量。
14353 12
|
存储 缓存 安全
除了变量,final还能修饰哪些Java元素
在Java中,final关键字不仅可以修饰变量,还可以用于修饰类、方法和参数。修饰类时,该类不能被继承;修饰方法时,方法不能被重写;修饰参数时,参数在方法体内不能被修改。
176 3
|
Java
final 在 java 中有什么作用
在 Java 中,`final` 关键字用于限制变量、方法和类的修改或继承。对变量使用 `final` 可使其成为常量;对方法使用 `final` 禁止其被重写;对类使用 `final` 禁止其被继承。
244 2
|
设计模式 JavaScript 前端开发
java中的static关键字
欢迎来到瑞雨溪的博客,博主是一名热爱JavaScript和Vue的大一学生,致力于全栈开发。如果你从我的文章中受益,欢迎关注我,将持续分享更多优质内容。你的支持是我前进的动力!🎉🎉🎉
302 8
|
安全 Java API
告别SimpleDateFormat:Java 8日期时间API的最佳实践
在Java开发中,处理日期和时间是一个基本而重要的任务。传统的`SimpleDateFormat`类因其简单易用而被广泛采用,但它存在一些潜在的问题,尤其是在多线程环境下。本文将探讨`SimpleDateFormat`的局限性,并介绍Java 8引入的新的日期时间API,以及如何使用这些新工具来避免潜在的风险。
220 5
|
存储 Java
Java 中的静态(static)
【10月更文挑战第15天】静态是 Java 语言中一个非常重要的特性,它为我们提供了一种方便、高效的方式来管理和共享资源。然而,在使用过程中,我们需要谨慎考虑其优缺点,以确保代码的质量和可维护性。
|
存储 安全 Java
了解final关键字在Java并发编程领域的作用吗?
在Java并发编程中,`final`关键字不仅用于修饰变量、方法和类,还在多线程环境中确保对象状态的可见性和不变性。本文深入探讨了`final`关键字的作用,特别是其在final域重排序规则中的应用,以及如何防止对象的“部分创建”问题,确保线程安全。通过具体示例,文章详细解析了final域的写入和读取操作的重排序规则,以及这些规则在不同处理器上的实现差异。
295 0
了解final关键字在Java并发编程领域的作用吗?