Язык и JVM — Примеры
Пример 1 — Бенчмарк, который измеряет интерпретатор
Команда замеряет изменение одним прогоном на несколько тысяч итераций, а потом спорит о результате, который между прогонами меняется вдвое. Перепишите измерение так, чтобы оно выходило на устойчивый режим.
public class Bench {
public static void main(String[] args) {
long start = System.nanoTime();
long total = 0;
for (int i = 0; i < 10_000; i++) total += work(i);
System.out.println((System.nanoTime() - start) / 1_000_000 + " ms");
}
static long work(int i) { return i % 7; }
}
Решение
public class Bench {
static final int BATCHES = 20;
static final int PER_BATCH = 100_000;
public static void main(String[] args) {
long total = 0;
for (int b = 0; b < BATCHES; b++) {
long start = System.nanoTime();
for (int i = 0; i < PER_BATCH; i++) total += work(i);
long ms = (System.nanoTime() - start) / 1_000_000;
if (b >= 3) System.out.println("batch " + b + ": " + ms + " ms");
}
System.out.println(total);
}
static long work(int i) { return i % 7; }
}
Код начинает исполняться интерпретатором, а горячие пути компилируются, как только среда выполнения их увидит. Поэтому ранние партии измеряют интерпретатор, а поздние — программу, и печать каждой партии показывает, где числа перестают улучшаться. Обычная ошибка — усреднять прогрев в результат или сравнивать два числа, которые оба ещё падают. Числа в примере условны; измеряйте свою нагрузку.
Пример 2 — Зависимость, которой не хватает только во время работы
Проект компилируется на сборочной машине, однако classpath артефакта собирается отдельно; один путь использует класс из библиотеки, нужной только для компиляции, и падает внутри запроса спустя долгое время после чистого запуска. Определите, чего не хватает и почему отказ пришёл именно тогда.
import com.example.payments.PaymentClient; // только для компиляции, нет во время работы
public class OrderService {
private final PaymentClient client = new PaymentClient();
Receipt place(Order order) {
return client.charge(order.total());
}
}
Подставьте координаты своей библиотеки вместо условной выше.
Решение
java.lang.NoClassDefFoundError: com/example/payments/PaymentClient
at OrderService.<init>(OrderService.java:4)
# классы загружаются при первом использовании, поэтому отсутствующий или
# несовместимый класс отказывает здесь, а не при запуске
Ошибка называет класс, и это весь диагноз: она указывает на объявление, которое должно было принести класс в рабочий classpath. Зависимость времени компиляции служит обработчиком аннотаций или заглушкой API; всё остальное должно присутствовать при запуске программы. Ошибка в том, чтобы считать, будто всё, что компилируется, есть и во время работы. Дерево при этом оставляют непроверенным до первого отказа запроса.