Java SimpleDateFormat不可设置为static final 悠悠 2021-06-24 14:34 243阅读 0赞 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 》,想用上面的思路应用到项目中造成的错误也不会有上面这些说辞,不过遇到问题探究一下总归是不错的。
还没有评论,来说两句吧...