Zgodnie z moimi testami istnieje brak znaczącej różnicy w wydajności.
Każda próba próbuje dziesięć milionów każdego scenariusza, a następnie porównuje czasy działania w nanosekundach i zaokrąglonych sekundach. Jest to faktycznie sprzeczne z moją pierwotną hipotezą, ponieważ sądziłem, że złapanie numeru Throwable
spowoduje wyraźną poprawę.
Zacząłem również zdawać sobie sprawę, że część tego może wynikać z wpływu optymalizatora, dlatego stworzyłem bardziej skomplikowany przykład, który zawiera poniżej liczby pseudolosowe, myśląc, że to złagodzi potencjalny wpływ optymalizatora na kodzie.
(nie będę pouczać o właściwym wykorzystaniu catch
bloków, a pytanie brzmi konkretnie o wydajność, nie najlepszych praktyk.)
wiele danych poniżej tego punktu!
przejazd 1 Wyniki:
Exception: 7196141955 (7.196s)
NumberFormatException: 7736401837 (7.736s)
Throwable: 6818656505 (6.819s)
trwającej 2 Wyniki:
Exception: 7262897545 (7.263s)
NumberFormatException: 7056116050 (7.056s)
Throwable: 7108232206 (7.108s)
prowadzony 3 Wyniki:
Exception: 7088967045 (7.089s)
NumberFormatException: 7020495455 (7.020s)
Throwable: 7192925684 (7.193s)
Run 4 Wyniki:
Exception: 6916917328 (6.917s)
NumberFormatException: 7690084994 (7.690s)
Throwable: 6906011513 (6.906s)
Run 5 Wyniki:
Exception: 7247571874 (7.248s)
NumberFormatException: 6818511040 (6.819s)
Throwable: 6813286603 (6.813s)
Kod
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)");
}
}
Więcej zawiłe, pseudolosowych kod
Stworzyłem to, aby upewnić się, że optymalizator nie po prostu "ignoruje" cały proces rzutowania/wychwytywania, zdając sobie sprawę, że blok kodu będzie zawsze przepływał do catch
. Podejmując próbę wykonania Integer.parseInt()
losowo wybranego String
(ale zawsze niepoprawnego), oznacza to, że kompilator nie może wiedzieć do czasu wykonania, czy dany przebieg przez pętle for()
jest ważny, czy też nie.
Zgodnie z oczekiwaniami z pierwszego eksperymentu nie ma znaczącej różnicy między tymi trzema scenariuszami.
przejazd 1 Wyniki:
Exception: 10988431371 (10.988s)
NumberFormatException: 11360698958 (11.361s)
Throwable: 10539041505 (10.539s)
trwającej 2 Wyniki:
Exception: 12468860076 (12.469s)
NumberFormatException: 11852429194 (11.852s)
Throwable: 11859547560 (11.860s)
prowadzony 3 Wyniki:
Exception: 10618082779 (10.618s)
NumberFormatException: 10718252324 (10.718s)
Throwable: 10327709072 (10.328s)
Run 4 Wyniki:
Exception: 11031135405 (11.031s)
NumberFormatException: 10689877480 (10.690s)
Throwable: 10668345685 (10.668s)
Run 5 Wyniki:
Exception: 11513727192 (11.514s)
NumberFormatException: 11581826079 (11.582s)
Throwable: 12488301109 (12.488s)
Kod
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)");
}
}
Domyślam się, że wydajność jest taka sama, z wyjątkiem przypadku złapania 'Throwable', ponieważ wszystko bardziej szczegółowe niż to będzie wymagało od programu sprawdzenia typu' Throwable'. To tylko zgadnij. – asteri
Dlaczego nie spróbować samemu przeprowadzić testu porównawczego i opublikować wyników tutaj. – anubhava
@anubhava Ponieważ za każdym razem, gdy próbuję coś przetestować, powiedziano mi, że nie testuję poprawnie. Haha :) – asteri