我需要将大量java.util.Date对象转换为String, 现在我正在使用
String dateString = new SimpleDateFormat(dateFormat).format(value);
,但是每次都需要创建一个新的SimpleDateFormat对象。
以大格式解析所需格式的字符串的最快方法是什么 数量而不创建新的SimpleDateFormat对象,例如java.util.Date中的yyyy-MM-dd模式?
我正在使用Java7。Java8的解决方案对我来说不可接受
答案 0 :(得分:2)
java.time 类的后端口要花费一毫秒以内,以您期望的方式从String
生成LocalDate
String output = myLocalDate.toString() ; // Takes less than a microsecond.
使用该库,我不必担心日期时间字符串会成为瓶颈。
现代方法使用 java.time 类代替了可怕的旧日期时间类,例如Date
和Calendar
。对于Java 6和7,大多数功能都是使用几乎相同的API在ThreeTen-Backport项目中向后移植的。添加库并导入:import org.threeten.bp.*;
您的示例格式YYYY-MM-DD是LocalDate
类在解析/生成文本时使用的默认格式。
示例代码。
设置LocalDate
个对象的列表。
long years = 1000;
LocalDate today = LocalDate.now();
LocalDate lastDate = today.plusYears( years );
int initialCapacity = ( int ) ( ( years + 1 ) * 366 );
List < LocalDate > dates = new ArrayList <>( initialCapacity );
LocalDate localDate = today;
System.out.println( "From: " + today + " to: " + lastDate );
while ( localDate.isBefore( lastDate ) ) {
dates.add( localDate );
// Setup next loop.
localDate = localDate.plusDays( 1 );
}
运行测试。
long start = System.nanoTime();
for ( LocalDate date : dates ) {
String output = date.toString(); // Generate text in standard ISO 8601 format.
}
long stop = System.nanoTime();
long elapsed = ( stop - start );
long nanosEach = elapsed / dates.size();
System.out.println( "nanosEach: " + nanosEach );
当在IntelliJ 2018.3中使用基于OpenJDK的Java 10.0.2在MacBook Pro(Retina,15英寸,2013年末),2.3 GHz Intel Core i7、16 GB 1600 MHz DDR3上运行时, Zulu JVM来自Azul Systems…
运行100年后,每个时间大约为650纳秒。那大约是微秒的三分之二。
运行1000年后,每个时间大约为260纳秒。那大约是四分之一秒。
我怀疑使用此库处理日期字符串是否会成为应用程序性能的瓶颈。
java.time 类被设计为固有的thread-safe,包括使用immutable objects。
您可以缓存单个DateTimeFormatter
对象,甚至在线程之间也可以重复使用。
由ISO 8601标准定义的所需格式在 java.time 和 ThreeTen-Backport 库中均已预定义为常量。 :DateTimeFormatter .ISO_LOCAL_DATE
。
DateTimeFormatter f = DateTimeFormatter.ofPattern( "uuuu-MM-dd" ) ; // Or just use the pre-defined constant for that particular pattern, `DateTimeFormatter .ISO_LOCAL_DATE`, also used by default in `LocalDate::toString`.
…
String output = localDate.format( f ) ;
java.time框架已内置在Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.Date
,Calendar
和SimpleDateFormat
。
目前位于Joda-Time的maintenance mode项目建议迁移到java.time类。
要了解更多信息,请参见Oracle Tutorial。并在Stack Overflow中搜索许多示例和说明。规格为JSR 310。
您可以直接与数据库交换 java.time 对象。使用符合JDBC driver或更高版本的JDBC 4.2。不需要字符串,不需要java.sql.*
类。
在哪里获取java.time类?
答案 1 :(得分:1)
一种更快的方法是不要每次都重新创建SimpleDateFormat
SimpleDateFormat df = new SimpleDateFormat(dateFormat); // outside loop or a field
....
String dateString = df.format(value);
答案 2 :(得分:1)
要将许多日期转换为字符串,可以使用相同的SimpleDateFormat
,但只能在一个线程中执行,因为SimpleDateFormat
并不是线程安全的。但是,作为一种可能的变体,您可以创建util类并将SimpleDateFormat
保留在ThreadLocal
变量中,并在任何地方使用它。
慢: SimpleDateFormat
被多次创建:
for(Date date : hugeDateList)
String str = new SimpleDateFormat("yyyy-MM-dd").format(date);
快速:SimpleDateFormat
仅创建一次并使用多次
DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
for(Date date : hugeDateList)
String str = df.format(date);
更快::每个线程一次声明SimpleDateFormat
,使用多个线程格式化日期列表(例如10个线程,每个线程占所有日期的10%):
public final class TimeUtils {
private static final ThreadLocal<DateFormat> THREAD_LOCAL_DATE_FORMAT = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd"));
public static String format(Date date) {
return date != null ? THREAD_LOCAL_DATE_FORMAT.get().format(date) : null;
}
}
// TODO this is Java8 only for example, in Java7 ther're lines to create and run threads (not related to the question)
hugeDateList.parallelStream().map(TimeUtils::format).collect(Collectors.toList())
答案 3 :(得分:1)
解析和格式化是计算密集型任务,如果您的计算机具有多个处理器,我建议您将任务设置为多线程。
例如:
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
class MyCallable implements Callable<String> {
Date date;
public MyCallable(Date date) {
this.date = date;
}
@Override
public String call() throws Exception {
return new SimpleDateFormat(your pattern).format(date);
}
}
public class Example {
public static void main(String[] args) {
// thread pool
ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
// your date objects
List<Date> dates = ...
List<Future<String>> futureList = new ArrayList<>();
// let the thread poll run tasks
for (Date date : dates) {
MyCallable myCallable = new MyCallable(date);
futureList.add(executorService.submit(myCallable));
}
// collect result
List<String> results = new ArrayList<>();
for (Future<String> future : futureList) {
try {
results.add(future.get());
} catch (Exception e) {
//
}
}
}
}