Самый быстрый способ разобрать строку из java.util.Date - PullRequest
0 голосов
/ 16 октября 2018

Мне нужно преобразовать большое количество объектов java.util.Date в строку, сейчас я использую

String dateString = new SimpleDateFormat(dateFormat).format(value);

, но для этого требуется каждый раз создавать новый объект SimpleDateFormat.

Какой самый быстрый способ разбирать строку в нужном формате в больших количествах без создания новых объектов SimpleDateFormat, например, шаблон yyyy-MM-dd из java.util.Date?

IЯ использую Java 7. Решения от Java 8 не подходят для меня

Ответы [ 4 ]

0 голосов
/ 17 октября 2018

tl; dr

Back-порт классов java.time занимает за микросекунду для генерации String из LocalDate вВаш желаемый шаблон.

String output = myLocalDate.toString() ;  // Takes less than a microsecond.

Используя эту библиотеку, я не стал бы беспокоиться о узких местах строк даты и времени.

ThreeTen-Backport

Современный подход использует классы java.time , которые вытеснили ужасные старые классы даты и времени, такие как Date & Calendar.Для Java 6 и 7 большая часть этой функциональности перенесена в проект ThreeTen-Backport с использованием почти идентичного API.Добавьте библиотеку и импортируйте: 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 );

Результаты: по микросекунде каждый

При работе на MacBook Pro (Retina, 15-дюймовый, конец 2013 г.), 2,3 ГГц Intel Core i7, 16 ГБ 1600 МГц DDR3, в IntelliJ 2018.3, с использованием Java 10.0.2 из OpenJDK * на базе *1047* JVM Zulu от Azul Systems ...

При выполнении 100-летней партии я получаю около 650 наносекунд каждая.Это примерно две трети микросекунды.

При выполнении серии из 1000 лет я получаю около 260 наносекунд каждая.Это примерно четверть микросекунды.

Я сомневаюсь, что обработка строк с датами в этой библиотеке окажется узким местом в производительности вашего приложения.

Потоковая безопасность

Классы java.time разработаны для обеспечения поточной безопасности , включая использование неизменяемых объектов .

Вы можете кэшироватьодин 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.time встроен в Java 8 и более поздние версии.Эти классы вытесняют проблемные старые устаревшие классы даты и времени, такие как java.util.Date, Calendar, & SimpleDateFormat.

Проект Joda-Time , теперь в режиме обслуживания , рекомендует перейти на классы java.time .

Чтобы узнать больше, см. Oracle Tutorial .И поиск переполнения стека для многих примеров и объяснений.Спецификация: JSR 310 .

Вы можете обмениваться java.time объектами напрямую с вашей базой данных.Используйте драйвер JDBC , совместимый с JDBC 4.2 или более поздней версии.Нет необходимости в строках, нет необходимости в java.sql.* классах.

Где получить классы java.time?

  • Java SE 8 , Java SE 9 , Java SE 10, Java SE 11 и более поздних версий - часть стандартного Java API с связанной реализацией.
    • Java 9 добавляет некоторые незначительные функции и исправления.
  • Java SE 6 и JavaSE 7
    • Большинство функций java.time перенесено в Java 6 & 7 в ThreeTen-Backport .
  • Android
    • Более поздние версии реализации связки Android java.time классы.
    • Для более ранних версий Android (<26) проект <a href="https://github.com/JakeWharton/ThreeTenABP" rel="nofollow noreferrer"> ThreeTenABP адаптируется ThreeTen-Backport (упомянуто выше).См. Как использовать ThreeTenABP… .
0 голосов
/ 16 октября 2018

Чтобы преобразовать много дат в строку, вы можете использовать тот же SimpleDateFormat, но делать это только в одном потоке, потому что SimpleDateFormat не является поточно-ориентированным.Но, как один из возможных вариантов, вы можете создать класс утилит и удерживать SimpleDateFormat в переменной ThreadLocal и использовать его где угодно.

Медленно: SimpleDateFormat создано несколько раз:

for(Date date : hugeDateList)
    String str = new SimpleDateFormat("yyyy-MM-dd").format(date);

Fast: 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())
0 голосов
/ 16 октября 2018

синтаксический анализ и форматирование - это задачи, требующие большого объема вычислений. Если на вашем компьютере установлено несколько процессоров, я бы предложил сделать вашу задачу многопоточной.

Например:

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) {
                // 
            }
        }
    }
}
0 голосов
/ 16 октября 2018

более быстрый способ - не создавать заново SimpleDateFormat каждый раз

SimpleDateFormat df = new SimpleDateFormat(dateFormat);  // outside loop or a field 
....
String dateString = df.format(value);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...