Как измерить производительность метода?
Если вы собираетесь оптимизировать код, или же выбрать лучшее с точки зрения производительности готовое решение, выбор необходимо подтвердить тестом производительности до и после. Такие тесты называются benchmark.
Первый вариант который приходит в голову – измерить время до, выполнить метод, посмотреть сколько времени прошло. У такого подхода есть ряд нюансов. Каждый последующий замер может случайным образом сильно отличаться от предыдущего. В реальном приложении результат будет совсем отличным от тестового, потому что виртуальная машина будет «прогретой»: заполнятся различные системные кэши, произойдут JIT-оптимизации горячего кода, память наполнится мусором.
Наивный подход может показать приблизительную производительность долгих операций: ввода-вывода, системных вызовов, или пользовательских сценариев на развернутом тестовом стенде. При тестировании кусков Java кода (в микробенчмарках) время выполнения очень мало, поэтому упомянутые нюансы вносят значительный вклад в результат.
Самое правильное решение – использовать готовый инструмент из JDK, JMH. Для этого его библиотеки добавляются в зависимости, а тестовый метод помечается аннотацией @Benchmark . Тесты можно запускать в виде исполняемого jar-файла, либо вызовом специальных программных методов библиотеки. Итоги тестирования будут выведены в виде таблицы в консоль.
Для дальнейшего погружения в особенности использования JMH рекомендуется к просмотру доклад автора инструмента.
Учебное задание: отображение текущего времени

Задача заключается в разработке программы, которое показывает текущее время в GMT (Greenwich Mean Time, т.е. среднее время по Гринвичу) в формате часы:минуты:секунды, т.е. 13:19:8.
Метод currentTimeMillis в классе System возвращает текущее время в миллисекундах, истёкшее с полуночи 1 января 1970 GMT, как показано на следующем рисунке:

Это время известно как Эра UNIX (UNIX epoch). Эра – это точка, когда началось время, а 1970 – это год, когда официально представлена операционная система UNIX.
Вы можете использовать этот метод для получения текущего времени, а затем вычисления текущих секунд, минут, часов следующим образом:
- Получить общее число миллисекунд с полуночи 1 января 1970 в totalMilliseconds вызовом System.currentTimeMillis() (к примеру, 1203183068328 миллесекунд).
- Получить общее число секунд totalSeconds разделив totalMilliseconds на 1000 (например, 1203183068328 миллисекунд / 1000 = 1203183068 секунд).
- Вычислить текущую секунд из totalSeconds % 60 (например, 1203183068 секунд % 60 = 8, что будет текущей секундой).
- Получить общее количество минут totalMinutes разделив totalSeconds на 60 (к примеру, 1203183068 секунд / 60 = 20053051 минут).
- Вычислить текущее время из totalMinutes % 60 (к примеру, 20053051 минут % 60 = 31, это будет текущая минута).
- Получить общее количество часов totalHours разделив totalMinutes на 60 (например, 20053051 минут / 60 = 334217 часов).
- Вычислить текущий час из totalHours % 24 (например, 334217 часов % 24 = 17, это будет текущий час).
public class ShowCurrentTime < public static void main(String[] args) < // Получить общее количество миллисекунд с полночи 1 января 1970 long totalMilliseconds = System.currentTimeMillis(); // Получить общее количество миллисекунд с полночи 1 января 1970 long totalSeconds = totalMilliseconds / 1000; // Рассчитать текущую секунду этой минуты и этого часа long currentSecond = totalSeconds % 60; // Получить общее количество минут long totalMinutes = totalSeconds / 60; // Рассчитать текущую минуту этого часа long currentMinute = totalMinutes % 60; // Получить общее количество часов long totalHours = totalMinutes / 60; // Рассчитать текущий час long currentHour = totalHours % 24; // Отобразить результаты System.out.println("Текущее время " + currentHour + ":" + currentMinute + ":" + currentSecond + " GMT"); >>

Строка 4 вызывает System.currentTimeMillis() для получения текущего времени в миллисекундах, как величину long. Поэтому все переменные в этой программе объявлены как тип long. Секунды, минуты и часы извлекаются из текущего времени используя операторы / и % (строки 6–22).
Проверь себя:
- Как вы получаете текущую секунду, минуту и час?
Дата и время
Встречайте новый встроенный объект: Date. Он содержит дату и время, а также предоставляет методы управления ими.
Например, его можно использовать для хранения времени создания/изменения, для измерения времени или просто для вывода текущей даты.
Создание
Для создания нового объекта Date нужно вызвать конструктор new Date() с одним из следующих аргументов:
Без аргументов – создать объект Date с текущими датой и временем:
let now = new Date(); alert( now ); // показывает текущие дату и время
new Date(milliseconds)
Создать объект Date с временем, равным количеству миллисекунд (тысячная доля секунды), прошедших с 1 января 1970 года UTC+0.
// 0 соответствует 01.01.1970 UTC+0 let Jan01_1970 = new Date(0); alert( Jan01_1970 ); // теперь добавим 24 часа и получим 02.01.1970 UTC+0 let Jan02_1970 = new Date(24 * 3600 * 1000); alert( Jan02_1970 );
Целое число, представляющее собой количество миллисекунд, прошедших с начала 1970 года, называется таймстамп (англ. timestamp).
Это – легковесное численное представление даты. Из таймстампа всегда можно получить дату с помощью new Date(timestamp) и преобразовать существующий объект Date в таймстамп, используя метод date.getTime() (см. ниже).
Датам до 1 января 1970 будут соответствовать отрицательные таймстампы, например:
// 31 декабря 1969 года let Dec31_1969 = new Date(-24 * 3600 * 1000); alert( Dec31_1969 );
new Date(datestring)
Если аргумент всего один, и это строка, то из неё «прочитывается» дата. Алгоритм разбора – такой же, как в Date.parse , который мы рассмотрим позже.
let date = new Date("2017-01-26"); alert(date); // Время не указано, поэтому оно ставится в полночь по Гринвичу и // меняется в соответствии с часовым поясом места выполнения кода // Так что в результате можно получить // Thu Jan 26 2017 11:00:00 GMT+1100 (восточно-австралийское время) // или // Wed Jan 25 2017 16:00:00 GMT-0800 (тихоокеанское время)
new Date(year, month, date, hours, minutes, seconds, ms)
Создать объект Date с заданными компонентами в местном часовом поясе. Обязательны только первые два аргумента.
- year должен состоять из четырёх цифр. Для совместимости также принимаются 2 цифры и рассматриваются как 19xx , к примеру, 98 здесь это тоже самое, что и 1998 , но настоятельно рекомендуется всегда использовать 4 цифры.
- month начинается с 0 (январь) по 11 (декабрь).
- Параметр date здесь представляет собой день месяца. Если параметр не задан, то принимается значение 1 .
- Если параметры hours/minutes/seconds/ms отсутствуют, их значением становится 0 .
new Date(2011, 0, 1, 0, 0, 0, 0); // // 1 Jan 2011, 00:00:00 new Date(2011, 0, 1); // то же самое, так как часы и проч. равны 0
Максимальная точность – 1 мс (до 1/1000 секунды):
let date = new Date(2011, 0, 1, 2, 3, 4, 567); alert( date ); // 1.01.2011, 02:03:04.567
Получение компонентов даты
Существуют методы получения года, месяца и т.д. из объекта Date :
getFullYear() Получить год (4 цифры) getMonth() Получить месяц, от 0 до 11. getDate() Получить день месяца, от 1 до 31, что несколько противоречит названию метода. getHours(), getMinutes(), getSeconds(), getMilliseconds() Получить, соответственно, часы, минуты, секунды или миллисекунды.
Никакого getYear() . Только getFullYear()
Многие интерпретаторы JavaScript реализуют нестандартный и устаревший метод getYear() , который порой возвращает год в виде двух цифр. Пожалуйста, обходите его стороной. Если нужно значение года, используйте getFullYear() .
Кроме того, можно получить определённый день недели:
getDay() Вернуть день недели от 0 (воскресенье) до 6 (суббота). Несмотря на то, что в ряде стран за первый день недели принят понедельник, в JavaScript начало недели приходится на воскресенье.
Все вышеперечисленные методы возвращают значения в соответствии с местным часовым поясом.
Однако существуют и их UTC-варианты, возвращающие день, месяц, год для временной зоны UTC+0: getUTCFullYear(), getUTCMonth(), getUTCDay(). Для их использования требуется после «get» подставить «UTC» .
Если ваш местный часовой пояс смещён относительно UTC, то следующий код покажет разные часы:
// текущая дата let date = new Date(); // час в вашем текущем часовом поясе alert( date.getHours() ); // час в часовом поясе UTC+0 (лондонское время без перехода на летнее время) alert( date.getUTCHours() );
Помимо вышеприведённых методов, существуют два особых метода без UTC-варианта:
Для заданной даты возвращает таймстамп – количество миллисекунд, прошедших с 1 января 1970 года UTC+0.
Возвращает разницу в минутах между UTC и местным часовым поясом:
// если вы в часовом поясе UTC-1, то выводится 60 // если вы в часовом поясе UTC+3, выводится -180 alert( new Date().getTimezoneOffset() );
Установка компонентов даты
Следующие методы позволяют установить компоненты даты и времени:
- setFullYear(year, [month], [date])
- setMonth(month, [date])
- setDate(date)
- setHours(hour, [min], [sec], [ms])
- setMinutes(min, [sec], [ms])
- setSeconds(sec, [ms])
- setMilliseconds(ms)
- setTime(milliseconds) (устанавливает дату в виде целого количества миллисекунд, прошедших с 01.01.1970 UTC)
У всех этих методов, кроме setTime() , есть UTC-вариант, например: setUTCHours() .
Как мы видим, некоторые методы могут устанавливать сразу несколько компонентов даты, например: setHours . Если какая-то компонента не указана, она не меняется.
let today = new Date(); today.setHours(0); alert(today); // выводится сегодняшняя дата, но значение часа будет 0 today.setHours(0, 0, 0, 0); alert(today); // всё ещё выводится сегодняшняя дата, но время будет ровно 00:00:00.
Автоисправление даты
Автоисправление – это очень полезная особенность объектов Date . Можно устанавливать компоненты даты вне обычного диапазона значений, а объект сам себя исправит.
let date = new Date(2013, 0, 32); // 32 Jan 2013 . alert(date); // . 1st Feb 2013!
Неправильные компоненты даты автоматически распределяются по остальным.
Предположим, нам требуется увеличить дату «28 февраля 2016» на два дня. В зависимости от того, високосный это год или нет, результатом будет «2 марта» или «1 марта». Нам об этом думать не нужно. Просто прибавляем два дня. Объект Date позаботится об остальном:
let date = new Date(2016, 1, 28); date.setDate(date.getDate() + 2); alert( date ); // 1 Mar 2016
Эту возможность часто используют, чтобы получить дату по прошествии заданного отрезка времени. Например, получим дату «спустя 70 секунд с текущего момента»:
let date = new Date(); date.setSeconds(date.getSeconds() + 70); alert( date ); // выводит правильную дату
Также можно установить нулевые или даже отрицательные значения. Например:
let date = new Date(2016, 0, 2); // 2 Jan 2016 date.setDate(1); // задать первое число месяца alert( date ); date.setDate(0); // первый день месяца -- это 1, так что выводится последнее число предыдущего месяца alert( date ); // 31 Dec 2015
Преобразование к числу, разность дат
Если объект Date преобразовать в число, то получим таймстамп по аналогии с date.getTime() :
let date = new Date(); alert(+date); // количество миллисекунд, то же самое, что date.getTime()
Важный побочный эффект: даты можно вычитать, в результате получаем разность в миллисекундах.
Этот приём можно использовать для измерения времени:
let start = new Date(); // начинаем отсчёт времени // выполняем некоторые действия for (let i = 0; i < 100000; i++) < let doSomething = i * i * i; >let end = new Date(); // заканчиваем отсчёт времени alert( `Цикл отработал за $ миллисекунд` );
Date.now()
Если нужно просто измерить время, объект Date нам не нужен.
Существует особый метод Date.now() , возвращающий текущую метку времени.
Семантически он эквивалентен new Date().getTime() , однако метод не создаёт промежуточный объект Date . Так что этот способ работает быстрее и не нагружает сборщик мусора.
Данный метод используется из соображений удобства или когда важно быстродействие, например, при разработке игр на JavaScript или других специализированных приложений.
Вероятно, предыдущий пример лучше переписать так:
let start = Date.now(); // количество миллисекунд с 1 января 1970 года // выполняем некоторые действия for (let i = 0; i < 100000; i++) < let doSomething = i * i * i; >let end = Date.now(); // заканчиваем отсчёт времени alert( `Цикл отработал за $ миллисекунд` ); // вычитаются числа, а не даты
Бенчмаркинг
Будьте внимательны, если хотите точно протестировать производительность функции, которая зависит от процессора.
Например, сравним две функции, вычисляющие разницу между двумя датами: какая сработает быстрее?
Подобные вычисления, замеряющие производительность, также называют «бенчмарками» (benchmark).
// есть date1 и date2, какая функция быстрее вернёт разницу между ними в миллисекундах? function diffSubtract(date1, date2) < return date2 - date1; >// или function diffGetTime(date1, date2)
Обе функции делают буквально одно и то же, только одна использует явный метод date.getTime() для получения даты в миллисекундах, а другая полагается на преобразование даты в число. Результат их работы всегда один и тот же.
Но какая функция быстрее?
Для начала можно запустить их много раз подряд и засечь разницу. В нашем случае функции очень простые, так что потребуется хотя бы 100000 повторений.
function diffSubtract(date1, date2) < return date2 - date1; >function diffGetTime(date1, date2) < return date2.getTime() - date1.getTime(); >function bench(f) < let date1 = new Date(0); let date2 = new Date(); let start = Date.now(); for (let i = 0; i < 100000; i++) f(date1, date2); return Date.now() - start; >alert( 'Время diffSubtract: ' + bench(diffSubtract) + 'мс' ); alert( 'Время diffGetTime: ' + bench(diffGetTime) + 'мс' );
Вот это да! Метод getTime() работает ощутимо быстрее! Всё потому, что не производится преобразование типов, и интерпретаторам такое намного легче оптимизировать.
Замечательно, это уже что-то. Но до хорошего бенчмарка нам ещё далеко.
Представьте, что при выполнении bench(diffSubtract) процессор параллельно делал что-то ещё, также потребляющее ресурсы. А к началу выполнения bench(diffGetTime) он это уже завершил.
Достаточно реалистичный сценарий в современных многопроцессорных операционных системах.
В итоге у первого бенчмарка окажется меньше ресурсов процессора, чем у второго. Это может исказить результаты.
Для получения наиболее достоверных результатов тестирования производительности весь набор бенчмарков нужно запускать по нескольку раз.
function diffSubtract(date1, date2) < return date2 - date1; >function diffGetTime(date1, date2) < return date2.getTime() - date1.getTime(); >function bench(f) < let date1 = new Date(0); let date2 = new Date(); let start = Date.now(); for (let i = 0; i < 100000; i++) f(date1, date2); return Date.now() - start; >let time1 = 0; let time2 = 0; // bench(diffSubtract) и bench(diffGetTime) поочерёдно запускаются 10 раз for (let i = 0; i < 10; i++) < time1 += bench(diffSubtract); time2 += bench(diffGetTime); >alert( 'Итоговое время diffSubtract: ' + time1 ); alert( 'Итоговое время diffGetTime: ' + time2 );
Современные интерпретаторы JavaScript начинают применять продвинутые оптимизации только к «горячему коду», выполняющемуся несколько раз (незачем оптимизировать то, что редко выполняется). Так что в примере выше первые запуски не оптимизированы должным образом. Нелишним будет добавить предварительный запуск для «разогрева»:
// добавляем для "разогрева" перед основным циклом bench(diffSubtract); bench(diffGetTime); // а теперь тестируем производительность for (let i = 0; i
Будьте осторожны с микробенчмарками
Современные интерпретаторы JavaScript выполняют множество оптимизаций. Они могут повлиять на результаты «искусственных тестов» по сравнению с «нормальным использованием», особенно если мы тестируем что-то очень маленькое, например, работу оператора или встроенной функции. Поэтому если хотите серьёзно понять производительность, пожалуйста, изучите, как работают интерпретаторы JavaScript. И тогда вам, вероятно, уже не понадобятся микробенчмарки.
Отличный набор статей о V8 можно найти на https://mrale.ph.
Разбор строки с датой
Метод Date.parse(str) считывает дату из строки.
Формат строки должен быть следующим: YYYY-MM-DDTHH:mm:ss.sssZ , где:
- YYYY-MM-DD – это дата: год-месяц-день.
- Символ «T» используется в качестве разделителя.
- HH:mm:ss.sss – время: часы, минуты, секунды и миллисекунды.
- Необязательная часть ‘Z’ обозначает часовой пояс в формате +-hh:mm . Если указать просто букву Z , то получим UTC+0.
Возможны и более короткие варианты, например, YYYY-MM-DD или YYYY-MM , или даже YYYY .
Вызов Date.parse(str) обрабатывает строку в заданном формате и возвращает таймстамп (количество миллисекунд с 1 января 1970 года UTC+0). Если формат неправильный, возвращается NaN .
let ms = Date.parse('2012-01-26T13:51:50.417-07:00'); alert(ms); // 1327611110417 (таймстамп)
Можно тут же создать объект new Date из таймстампа:
Подсчёт времени выполнения метода через аннотацию
Во многих проектах требуется посчитать время, которое затратил тот или иной метод. Для этого можно вручную сохранять значение System.currentTimeMillis() и после метода вычислять затраченное время. Когда методов много это становится не очень удобным.
Поэтому я решил написать простенькую аннотацию, которая бы считала время выполнения метода. Попытавшись найти информацию в интернете, понял, что её по данной теме очень мало. Придётся как-то выкручиваться, собирая информацию по крупицам.
Наша аннотация будет помечать методы, для которых мы хотим посчитать время выполнения в миллисекундах или наносекундах и выводить результат через System.out.println.
Для начала создадим саму аннотацию:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target()
@Retention(RetentionPolicy.SOURCE)
public @ interface Time public enum TimeInterval < MILLISECOND, NANOSECOND >;
annotations.time.Time.TimeInterval interval() default annotations.time.Time.TimeInterval.MILLISECOND;
String format() default «Elapsed %s» ;
>
* This source code was highlighted with Source Code Highlighter .
Поле interval служит для указания интервала времени (миллисекунды или наносекунды), поле format задаёт формат вывода результата.
Теперь, чтобы данная аннотация сработала как надо, нужно создать класс-обработчик расширяющий AbstractProcessor. В данном классе добавляется сохранение времени перед кодом метода, сам код метода копируется в блок try-finally, а блоке finally вычисляется затраченное методом время и выводится в консоль:
import com.sun.tools.javac.code.Flags;
import com.sun.tools.javac.code.TypeTags;
import com.sun.tools.javac.model.JavacElements;
import com.sun.tools.javac.processing.JavacProcessingEnvironment;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.JCTree.JCBlock;
import com.sun.tools.javac.tree.JCTree.JCCatch;
import com.sun.tools.javac.tree.JCTree.JCExpression;
import com.sun.tools.javac.tree.JCTree.JCExpressionStatement;
import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
import com.sun.tools.javac.tree.JCTree.JCStatement;
import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
import com.sun.tools.javac.tree.TreeMaker;
import com.sun.tools.javac.util. List ;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.Elements;
@SupportedAnnotationTypes( value = )
@SupportedSourceVersion(SourceVersion.RELEASE_6)
public class TimeAnnotationProcessor extends AbstractProcessor
public static final String ANNOTATION_TYPE = «annotations.time.Time» ;
private JavacProcessingEnvironment javacProcessingEnv;
private TreeMaker maker;
@Override
public void init(ProcessingEnvironment procEnv) super.init(procEnv);
this .javacProcessingEnv = (JavacProcessingEnvironment) procEnv;
this .maker = TreeMaker.instance(javacProcessingEnv.getContext());
>
@Override
public boolean process(Set annotations, RoundEnvironment roundEnv) if (annotations == null || annotations.isEmpty()) return false ;
>
final Elements elements = javacProcessingEnv.getElementUtils();
final TypeElement annotation = elements.getTypeElement(ANNOTATION_TYPE);
if (annotation != null ) // Выбираем все элементы, у которых стоит наша аннотация
final Set methods = roundEnv.getElementsAnnotatedWith(annotation);
JavacElements utils = javacProcessingEnv.getElementUtils();
for (final Element m : methods) Time time = m.getAnnotation(Time. class );
if (time != null ) JCTree blockNode = utils.getTree(m);
// Нам нужны только описания методов
if (blockNode instanceof JCMethodDecl) // Получаем содержимое метода
final List statements = ((JCMethodDecl) blockNode).body.stats;
// Новое тело метода
List newStatements = List .nil();
// Добавляем в начало метода сохранение текущего времени
JCVariableDecl var = makeTimeStartVar(maker, utils, time);
newStatements = newStatements.append( var );
// Создаём тело блока try, копируем в него оригинальное содержимое метода
List tryBlock = List .nil();
for (JCStatement statement : statements) tryBlock = tryBlock.append(statement);
>
// Создаём тело блока finally, добавляем в него вывод затраченного времени
JCBlock finalizer = makePrintBlock(maker, utils, time, var );
JCStatement stat = maker.Try(maker.Block(0, tryBlock), List .nil(), finalizer);
newStatements = newStatements.append(stat);
// Заменяем старый код метода на новый
((JCMethodDecl) blockNode).body.stats = newStatements;
>
>
>
private JCExpression makeCurrentTime(TreeMaker maker, JavacElements utils, Time time) // Создаём вызов System.nanoTime или System.currentTimeMillis
JCExpression exp = maker.Ident(utils.getName( «System» ));
String methodName;
switch (time.interval()) case NANOSECOND:
methodName = «nanoTime» ;
break ;
default :
methodName = «currentTimeMillis» ;
break ;
>
exp = maker.Select(exp, utils.getName(methodName));
return maker.Apply( List .nil(), exp, List .nil());
>
protected JCVariableDecl makeTimeStartVar(TreeMaker maker, JavacElements utils, Time time) // Создаём финальную переменную для хранения времени старта. Имя переменной в виде time_start_
JCExpression currentTime = makeCurrentTime(maker, utils, time);
String fieldName = fieldName = «time_start_» + ( int ) ( Math .random() * 10000);
return maker.VarDef(maker.Modifiers(Flags.FINAL), utils.getName(fieldName), maker.TypeIdent(TypeTags.LONG), currentTime);
>
protected JCBlock makePrintBlock(TreeMaker maker, JavacElements utils, Time time, JCVariableDecl var ) // Создаём вызов System.out.println
JCExpression printlnExpression = maker.Ident(utils.getName( «System» ));
printlnExpression = maker.Select(printlnExpression, utils.getName( «out» ));
printlnExpression = maker.Select(printlnExpression, utils.getName( «println» ));
// Создаём блок вычисления затраченного времени (currentTime — startTime)
JCExpression currentTime = makeCurrentTime(maker, utils, time);
JCExpression elapsedTime = maker.Binary(JCTree.MINUS, currentTime, maker.Ident( var .name));
// Форматируем результат
JCExpression formatExpression = maker.Ident(utils.getName( «String» ));
formatExpression = maker.Select(formatExpression, utils.getName( «format» ));
// Собираем все кусочки вместе
List formatArgs = List .nil();
formatArgs.append(maker.Literal(time.format()));
formatArgs.append(elapsedTime);
JCExpression format = maker.Apply( List .nil(), formatExpression, formatArgs);
List printlnArgs = List .nil();
printlnArgs.append(format);
JCExpression print = maker.Apply( List .nil(), printlnExpression, printlnArgs);
JCExpressionStatement stmt = maker.Exec(print);
List stmts = List .nil();
stmts.append(stmt);
return maker.Block(0, stmts);
>
>
* This source code was highlighted with Source Code Highlighter .
Для того чтобы компилятор java использовал наш управляющий класс, нужно создать файл META-INF/javax.annotation.processing.Processor, в котором должна быть прописана следующая строка:
annotations.time.TimeAnnotationProcessor
После этого собираем все наши файлы в annotations.jar и добавляем его в classpath к любому проекту.
Теперь, чтобы посчитать время выполнения метода, достаточно добавить к этому методу аннотацию Time и после его выполнения в консоль будет выведено затраченное методом время:
@Time(format= «method time: %s ms» )
public void start() Thread.sleep(1000);
>* This source code was highlighted with Source Code Highlighter .
В результате в консоли увидим:
method time: 1000 ms
UPD: добавил немного комментариев в код
UPD2: Так же можно переработать пример, чтобы он выводил время затраченное методом в System.err только если оно больше заданного в параметрах аннотации. Это могло бы быть полезно для production серверов, где пользоваться профайлером не всегда удобно.