之前在项目代码中使用的都是SimpleDateFormat来解析和格式化时间,后来看到阿里巴巴Java技术手册中说SimpleDateFormat类是线程不安全的,不应该用static来定义。
阿里巴巴Java开发手册
然后看了看自己的代码,竟然有用static定义的SimpleDateFormat,好了,有事干了,重构,重构!
SimpleDateFormat的替代方案网上有很多,我这里就是包装了Java8的DateTimeFormatter做了一个DateUtils工具类。
既然DateTimeFormatter是不可变的,线程安全的,项目中使用到的时间格式也无非就是有限的几种,所以可以将时间格式的创建集中在DateUtils中并且整个代码运行周期只创建一次。所以这里利用枚举来创建单例模式。
enum class FormatterEnum(val format: DateTimeFormatter) {
YYYY_MM_DD(DateTimeFormatter.ofPattern("yyyy-MM-dd")),
YYYYMMDD(DateTimeFormatter.ofPattern("yyyyMMdd")),
YYYY_MM_DD__HH_MM(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")),
YYYY_MM_DD__HH_MM_SS(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")),
YYYYMMDD__HH_MM(DateTimeFormatter.ofPattern("yyyyMMdd HH:mm")),
YYYYMMDD__HH_MM_SS(DateTimeFormatter.ofPattern("yyyyMMdd HH:mm:ss")),
HH_MM_SS(DateTimeFormatter.ofPattern("HH:mm:ss"))
}
如下是parse函数。因为LocalDate不能parse "2019-01-01 11:11"这种带time的时间串,LocalTime也不能parse带Date的时间串,所以这里用when来进行模式匹配。parse函数也要求两个参数dateStr、formatter格式相匹配。
fun parse(dateStr: String, formatter: FormatterEnum): Timestamp {
when (formatter) {
FormatterEnum.YYYY_MM_DD,
FormatterEnum.YYYYMMDD
-> return LocalDate.parse(dateStr, formatter.format).getTimestamp()
FormatterEnum.YYYY_MM_DD__HH_MM,
FormatterEnum.YYYYMMDD__HH_MM,
FormatterEnum.YYYYMMDD__HH_MM_SS,
FormatterEnum.YYYY_MM_DD__HH_MM_SS
-> return LocalDateTime.parse(dateStr, formatter.format).getTimestamp()
FormatterEnum.HH_MM_SS
-> return LocalTime.parse(dateStr, formatter.format).getTimestamp()
}
}
format函数
fun format(timestamp: Timestamp, formatter: FormatterEnum): String {
return timestamp.toLocalDateTime().format(formatter.format)
}
main测试函数。这里创建了200个线程同时进行时间的解析和格式化。结果表明确实可以做到线程安全。
@JvmStatic
fun main(args: Array<String>) {
for (i in 1..200) {
thread(start = true) {
println(DateUtils.parse("2019-01-01 11:12", FormatterEnum.YYYY_MM_DD__HH_MM))
println(DateUtils.parse("2019-01-01", FormatterEnum.YYYY_MM_DD))
println(DateUtils.format(LocalDateTime.now().getTimestamp(), FormatterEnum.YYYY_MM_DD__HH_MM_SS))
println(DateUtils.format(LocalDateTime.now().getTimestamp(), FormatterEnum.YYYY_MM_DD))
}
}
}
完整的DateUtils
package ewhine.tools
import java.sql.Timestamp
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.LocalTime
import java.time.format.DateTimeFormatter
import kotlin.concurrent.thread
enum class FormatterEnum(val format: DateTimeFormatter) {
YYYY_MM_DD(DateTimeFormatter.ofPattern("yyyy-MM-dd")),
YYYYMMDD(DateTimeFormatter.ofPattern("yyyyMMdd")),
YYYY_MM_DD__HH_MM(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")),
YYYY_MM_DD__HH_MM_SS(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")),
YYYYMMDD__HH_MM(DateTimeFormatter.ofPattern("yyyyMMdd HH:mm")),
YYYYMMDD__HH_MM_SS(DateTimeFormatter.ofPattern("yyyyMMdd HH:mm:ss")),
HH_MM_SS(DateTimeFormatter.ofPattern("HH:mm:ss"))
}
object DateUtils {
fun parse(dateStr: String, formatter: FormatterEnum): Timestamp {
when (formatter) {
FormatterEnum.YYYY_MM_DD,
FormatterEnum.YYYYMMDD
-> return LocalDate.parse(dateStr, formatter.format).getTimestamp()
FormatterEnum.YYYY_MM_DD__HH_MM,
FormatterEnum.YYYYMMDD__HH_MM,
FormatterEnum.YYYYMMDD__HH_MM_SS,
FormatterEnum.YYYY_MM_DD__HH_MM_SS
-> return LocalDateTime.parse(dateStr, formatter.format).getTimestamp()
FormatterEnum.HH_MM_SS
-> return LocalTime.parse(dateStr, formatter.format).getTimestamp()
}
}
fun format(timestamp: Timestamp, formatter: FormatterEnum): String {
return timestamp.toLocalDateTime().format(formatter.format)
}
@JvmStatic
fun main(args: Array<String>) {
for (i in 1..200) {
thread(start = true) {
println(DateUtils.parse("2019-01-01 11:12", FormatterEnum.YYYY_MM_DD__HH_MM))
println(DateUtils.parse("2019-01-01", FormatterEnum.YYYY_MM_DD))
println(DateUtils.format(LocalDateTime.now().getTimestamp(), FormatterEnum.YYYY_MM_DD__HH_MM_SS))
println(DateUtils.format(LocalDateTime.now().getTimestamp(), FormatterEnum.YYYY_MM_DD))
}
}
}
}
对了,上面的代码还使用了几个扩展函数
fun LocalDateTime.getTimestamp(): Timestamp {
return Timestamp.valueOf(this)
}
fun LocalDate.getTimestamp(): Timestamp {
return Timestamp.valueOf(this.atStartOfDay())
}
fun LocalTime.getTimestamp(): Timestamp {
return Timestamp.valueOf(this.atDate(LocalDate.now()))
}
网友评论