Как стать автором
Обновить

Комментарии 22

Нет, не сравнивал. Моих же собственных преобразований практически нет. Все основные преобразования делаются классом SimpleDateFormat. Устаревший или не устаревший этот класс ? Это определяется целью его использования. На мой взгляд, пользоваться им очень удобно при использовании JDBC.

А Вы сравнивали производительность вашего решения и форматирования посредством "современных" вариантов (например, через Instant или LocalDateTime)?
Интересно было бы увидеть такое сравнение в статье, ибо может и не быть смысла в разработке к устаревшим SimpleDateFormat

см комментарий выше, не правильно ответил на ваш вопрос

Дополню. Лучший способ повышения производительности - исключить лишние преобразования. При преобразовании Timestamp это легко можно сделать без потери качества данных. Передавать Timestamp как число.

Решил все же сравнить производительность двух подходов преобразования. Запустил в цикле (код выше и ниже) без вывода прямое и обратное преобразование

Предложенное мной решение работает быстрее примерно в 2 раза
63 мс - 1000 циклов, вариант предложенный мной
105 мс - 1000 циклов, вариант предложенный foal

Результат многократного запуска стабилен (хоть цифры и меняются)


	public static void main(String[] args) {
		long start = System.currentTimeMillis();
		Timestamp t = new Timestamp(System.currentTimeMillis());
		
		for (int index = 0; index < 1000; index++ ) {
			t.setNanos(345012000); // устанавливать наносекунды
			TimestampFormatter f = new TimestampFormatter();
			String s = f.format(t);
			try {
	            // обратное преобразование для проверки
				Timestamp n = f.parse(s);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		System.out.println(System.currentTimeMillis() - start);
		
		start = System.currentTimeMillis();
		
		for (int index = 0; index < 1000; index++ ) {
			t.setNanos(345012000);
			DateTimeFormatter f = DateTimeFormatter
	          .ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSSXXX")
	          .withZone(ZoneId.systemDefault());
			String s = f.format(t.toInstant());
			try {
				// обратное преобразование для проверки
				Timestamp n = Timestamp.from(f.parse(s, Instant::from));
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		System.out.println(System.currentTimeMillis() - start);
	}


Создание DateTimeFormatter'а нужно вынести из цикла. И мерить производительность нормальным инструментом типа jmh с прогревом и т.п.

Оба варианта работают в одинаковых циклах. Цикл ввел, чтобы измерить и сравнить "одиночное" выполнение без "прогрева" и прочих "привилегированных" условий. При разовом выполнении разницу в производительности просто не зафиксировать.

А в чём улучшение по сравнению со стандартным кодом?

    public static void main(String[] args) {
		Timestamp t = new Timestamp(System.currentTimeMillis());
		// устанавливать наносекунды
		t.setNanos(345012000);
		DateTimeFormatter f = DateTimeFormatter
          .ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSSXXX")
          .withZone(ZoneId.systemDefault());
		String s = f.format(t.toInstant());
		System.out.println(s);
		try {
			// обратное преобразование для проверки
			Timestamp n = Timestamp.from(f.parse(s, Instant::from));
			System.out.println(f.format(n.toInstant()));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

Если очень хочется, то спрячьте инициализацию DateTimeFormatter, t.toInstant() и Timestamp.from(f.parse(s, Instant::from)) внутрь своего TimestampFormatter, например

    public Timestamp parse(String source) {
		return Timestamp.from(f.parse(source, Instant::from));
	}
    public String format(Timestamp timestamp) {
		return f.format(t.toInstant());
	}
    public TimestampFormatter(String pattern, Locale locale, ZoneId tz) {
		f = DateTimeFormatter
          .ofPattern(pattern)
          .withLocale(locale)
          .withZone(tz);
	}

Плюс еще, конечно, проверка на null, но, для упрощения, я постарался придерживаться авторской нотации.

Бонусом то что DateTimeFormatter -- thread safe и может спокойно лежать в final поле. SDF нужно оборачивать в ThreadLocal со всеми развлечениями в случае ротации тредов в пуле в управляемой среде.

Ну или создавать на каждый чих, как у автора, но за такое даже джунов бьют линейкой по пальцам

Не нужно относится к своим коллегам с пренебрежением, впросак можете попасть, как коллега
foal

Я, честно говоря, очень старался не переходить на оценку вашей профессиональности, как программиста, но видимо у меня получилось плохо, и вы что-то почувствовали. Да, тут я точно попал впросак, каюсь.

Остальные ваши замечания:

  • спасибо за похвалу, мне так лестно, что сам Архитектор, Руководитель проекта обратил на меня внимание. Кстати, "проект" лучше тоже написать с большой буквы.

  • Да, но я бы использовал Optional или Objects.requireNonNull.

  • Только NPE - скорее просто мой персональный больной вопрос. Хотя вот авторы Котлина, тоже его выделили - видимо у нас было похожее трудное детство :)

  • "NPE никогда не будет", "никто не передаст туда null" - да, да, продолжайте жить в мире розовых пони. Ну или научитесь писать Unit тесты.

Знаете выражение, "Не судите и не судимы будете", Не я Вас начал учить, но раз Вы начали, почему бы мне заняться тем же самым в отношении Вас.

Значит не справились с домашним заданием. Хотя попробовали мыслить в нужном направлении. Хвалю, но ответ не верный. Значит не гуру!

Ответ на поверхности. Где используется класс Timestamp? В JDBC. Нужно преобразование, которое выполняется в этом классе в связке приложение - база? Нет!. В этой связке все прекрасно работает и без этого преобразования. А где нужно? В REST, SOAP и прочих подобных протоколах. И действительно, при значении null, дело не дойдет до вызова метода format. Не верите, можете проверить. А если даже допустить, что вызов с null значением все же произойдет, то оно успешно будет обработано в одном из методов стека вызова, где есть возможность записать ошибку в лог и вернуть ошибку в протоколе взаимодействия.

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

Очень жаль, что не успел попользоваться выданным званием, но постараюсь долго не плакать.

Завидую я вам. Вам, наверное, очень легко жить.

А теперь можно перейти к предложенному вами решению.

На мой взгляд, пакет java.time очень узко специализированный и, как я понимаю, назначение у него совсем другое чем предложенное Вами решение. Предполагаю, что и в производительности ваше решение проиграет - логика классов более сложная, соответственно, и время на преобразование должно тратиться больше. Да и использовать классы из этого пакета только чтобы получить микро/нано секунды у класса Timestamp, на мой взгляд, как то не оправдано. Избавит ваше решение от использования "устаревшего" класса SimpleDateFormat? Нет! Этот класс используется во многих библиотеках. Поведение этого класса предсказуемо в разных реализациях JVM и разных производителей, "сюрпризов" не ожидается. А то что одни и те же "базовые" класса JVM ведут себя по разному в реализациях JVM разных производителей это факт, что может если и не нарушать работу вашего кода, то сказываться на его логике.

И снова вы чертовски правы маэстро! Долой все эти новомодные штучки! Пещеры — вот она стабильность. Зачем, жить в доме с унитазом, если это не избавит всех остальных от туалетов во дворе?!

В общем, как я уже говорил, в мире розовых пони при тех граничных условиях, что вы здесь расписали ваше решение идеально.

Я хочу извинится еще раз, что сразу не понял его монументальность и крутизну.

Кроме как глупостью аргументировать свою позицию видать Вы не в состоянии.

А надо? Я вообще с вами не спорю. Все могут посмотреть на ваш код и на мой. И решить для себя чей подход им нравится больше. Или просто пройти мимо :)

Хорошая точка зрения

Мое решение примерно 2 раза быстрее вашего, как я и предполагал выше

Отвечу Вам той же монетой.

Ваше решение лишь только подтверждает мое утверждение, что и в пакете java.time нет удобного способа преобразования микро/нано секунд для Timestamp.

Молодец, предложили альтернативное решение. Коллеги могут выбирать, чем пользоваться.

И вишенка на торте - NullPointerException. У меня к Вам три вопроса.

  1. Очень любопытно, а что Вы собрались или предполагаете делать с NullPointerException в моем коде, когда пишите "проверка на null"? Могу предположить такой вариант

if (source == null) return null;

Угадал?

  1. Почему у Вас возник вопрос только про NullPointerException? ParseException ведь тоже не обрабатывается в предложенном мной варианте решения, если, как Вы пишите, придерживаться вашей "авторской нотации". В чем в данном случае разница между этими два исключениями?

  2. А если все же немножко подумать? А если подумать, то NullPointerException в этом участке кода никогда не возникнет и любая проверка на null будет мертвым кодом. Спросите почему? А это я Вам оставлю в качестве домашнего задания, Вы же гуру, думаю, справитесь. Так как, справитесь?

Мой комментарий на Вашу реплику ниже, не обновил страницу при ответе и он из за этого похоже попал не туда

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории