Согласно моим испытаниям, существует нет существенной разницы в производительности.
Каждый пробег пробует десять миллионов каждого сценария, а затем сравнивает время выполнения в наносекундах, а также округлые секунды. Это на самом деле противоречит моей первоначальной гипотезе, поскольку я думал, что поймать Throwable
продемонстрирует заметное улучшение.
Я также начал понимать, что часть этого может быть связана с влиянием оптимизатора, и поэтому я создал более запутанный пример, который включает в себя псевдослучайные числа ниже, полагая, что это уменьшит любое потенциальное влияние, которое оптимизатор имеет по коду.
(я не буду читать лекции вам о правильном использовании catch
блоков, поскольку речь идет именно о производительности, не лучшие практики.)
Много данных ниже этой точки!
Выполнить 1 Результаты:
Exception: 7196141955 (7.196s)
NumberFormatException: 7736401837 (7.736s)
Throwable: 6818656505 (6.819s)
Run 2 Результаты:
Exception: 7262897545 (7.263s)
NumberFormatException: 7056116050 (7.056s)
Throwable: 7108232206 (7.108s)
Выполнить 3 Результаты:
Exception: 7088967045 (7.089s)
NumberFormatException: 7020495455 (7.020s)
Throwable: 7192925684 (7.193s)
Run 4 Результаты:
Exception: 6916917328 (6.917s)
NumberFormatException: 7690084994 (7.690s)
Throwable: 6906011513 (6.906s)
Run 5 Результаты:
Exception: 7247571874 (7.248s)
NumberFormatException: 6818511040 (6.819s)
Throwable: 6813286603 (6.813s)
Код
import java.math.BigDecimal;
import java.math.RoundingMode;
public class Test {
private static final int TRIALS = 10000000;
private static final int NANOS_IN_SECOND = 1000000000;
private static final int DECIMAL_PRECISION = 3;
private static final RoundingMode ROUNDING_MODE = RoundingMode.HALF_UP;
public static void main(String[] args) {
long firstStart = System.nanoTime();
for(int i = 0; i < TRIALS; i++) {
try {
throw new NumberFormatException();
}
catch(Exception e) {
}
}
long firstEnd = System.nanoTime();
long secondStart = System.nanoTime();
for(int i = 0; i < TRIALS; i++) {
try {
throw new NumberFormatException();
}
catch(NumberFormatException e) {
}
}
long secondEnd = System.nanoTime();
long thirdStart = System.nanoTime();
for(int i = 0; i < TRIALS; i++) {
try {
throw new NumberFormatException();
}
catch(Throwable e) {
}
}
long thirdEnd = System.nanoTime();
long exception = firstEnd - firstStart;
long numberFormatException = secondEnd - secondStart;
long throwable = thirdEnd - thirdStart;
BigDecimal exceptionSeconds = new BigDecimal((double)exception/(double)NANOS_IN_SECOND);
BigDecimal numberFormatExceptionSeconds = new BigDecimal((double)numberFormatException/(double)NANOS_IN_SECOND);
BigDecimal throwableSeconds = new BigDecimal((double)throwable/(double)NANOS_IN_SECOND);
exceptionSeconds = exceptionSeconds.setScale(DECIMAL_PRECISION, ROUNDING_MODE);
numberFormatExceptionSeconds = numberFormatExceptionSeconds.setScale(DECIMAL_PRECISION, ROUNDING_MODE);
throwableSeconds = throwableSeconds.setScale(DECIMAL_PRECISION, ROUNDING_MODE);
System.out.println("Exception: " + exception + " (" + exceptionSeconds + "s)");
System.out.println("NumberFormatException: " + numberFormatException + " (" + numberFormatExceptionSeconds + "s)");
System.out.println("Throwable: " + throwable + " (" + throwableSeconds + "s)");
}
}
более запутанным, псевдослучайный код
Я создал это, чтобы оптимизатор не просто «игнорировал» весь процесс броска/захвата, понимая, что кодовый блок всегда будет проходить до catch
. Путем попытки Integer.parseInt()
на случайно выбранном String
(но всегда недействительном) это означает, что компилятор не может знать до тех пор, пока не будет выполняться заданный пробег через петли for()
или нет.
Как и ожидалось в первом эксперименте, между тремя сценариями нет существенной разницы.
Выполнить 1 Результаты:
Exception: 10988431371 (10.988s)
NumberFormatException: 11360698958 (11.361s)
Throwable: 10539041505 (10.539s)
Run 2 Результаты:
Exception: 12468860076 (12.469s)
NumberFormatException: 11852429194 (11.852s)
Throwable: 11859547560 (11.860s)
Выполнить 3 Результаты:
Exception: 10618082779 (10.618s)
NumberFormatException: 10718252324 (10.718s)
Throwable: 10327709072 (10.328s)
Run 4 Результаты:
Exception: 11031135405 (11.031s)
NumberFormatException: 10689877480 (10.690s)
Throwable: 10668345685 (10.668s)
Run 5 Результаты:
Exception: 11513727192 (11.514s)
NumberFormatException: 11581826079 (11.582s)
Throwable: 12488301109 (12.488s)
Код
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Random;
public class Test {
private static final int TRIALS = 10000000;
private static final int NANOS_IN_SECOND = 1000000000;
private static final int DECIMAL_PRECISION = 3;
private static final RoundingMode ROUNDING_MODE = RoundingMode.HALF_UP;
private static final String[] TEST_STRINGS = {
"lawl",
"rofl",
"trololo",
"foo",
"bar"
};
private static final Random RANDOM = new Random();
public static void main(String[] args) {
long firstStart = System.nanoTime();
for(int i = 0; i < TRIALS; i++) {
try {
Integer.parseInt(TEST_STRINGS[RANDOM.nextInt(TEST_STRINGS.length)]);
}
catch(Exception e) {
}
}
long firstEnd = System.nanoTime();
long secondStart = System.nanoTime();
for(int i = 0; i < TRIALS; i++) {
try {
Integer.parseInt(TEST_STRINGS[RANDOM.nextInt(TEST_STRINGS.length)]);
}
catch(NumberFormatException e) {
}
}
long secondEnd = System.nanoTime();
long thirdStart = System.nanoTime();
for(int i = 0; i < TRIALS; i++) {
try {
Integer.parseInt(TEST_STRINGS[RANDOM.nextInt(TEST_STRINGS.length)]);
}
catch(Throwable e) {
}
}
long thirdEnd = System.nanoTime();
long exception = firstEnd - firstStart;
long numberFormatException = secondEnd - secondStart;
long throwable = thirdEnd - thirdStart;
BigDecimal exceptionSeconds = new BigDecimal((double)exception/(double)NANOS_IN_SECOND);
BigDecimal numberFormatExceptionSeconds = new BigDecimal((double)numberFormatException/(double)NANOS_IN_SECOND);
BigDecimal throwableSeconds = new BigDecimal((double)throwable/(double)NANOS_IN_SECOND);
exceptionSeconds = exceptionSeconds.setScale(DECIMAL_PRECISION, ROUNDING_MODE);
numberFormatExceptionSeconds = numberFormatExceptionSeconds.setScale(DECIMAL_PRECISION, ROUNDING_MODE);
throwableSeconds = throwableSeconds.setScale(DECIMAL_PRECISION, ROUNDING_MODE);
System.out.println("Exception: " + exception + " (" + exceptionSeconds + "s)");
System.out.println("NumberFormatException: " + numberFormatException + " (" + numberFormatExceptionSeconds + "s)");
System.out.println("Throwable: " + throwable + " (" + throwableSeconds + "s)");
}
}
Мое предположение заключается в том, что производительность одинакова, за исключением случаев, когда вы ловите «Throwable», поскольку что-то более конкретное, чем это потребует от программы проверки типа «Throwable». Однако это всего лишь предположение. – asteri
Почему бы вам не попробовать сравнить себя и опубликовать результаты здесь. – anubhava
@anubhava Потому что каждый раз, когда я пытаюсь проверить что-то, мне говорят, что я не тестирую должным образом. Ха-ха :) – asteri