![](/img/trans.png)
[英]Should Java JDBC Select statements always be in a Try-Catch block?
[英]How deep should a try-catch block be in Java?
由於我的新工作,我在Java方面做了很多工作,現在我開始研究一些微小的細節。 顯然,Java代碼在某種程度上與異常有關。 我在想:
調用堆棧是否會對try-catch塊的性能產生很大影響? 即我應該避免嘗試調用一個函數的方法,而該函數又太深了?
我讀到try-catch塊只會影響異常情況下的性能。 但是,它們冒了多遠呢?
我們來衡量一下吧?
package tools.bench;
import java.math.BigDecimal;
public abstract class Benchmark {
final String name;
public Benchmark(String name) {
this.name = name;
}
abstract int run(int iterations) throws Throwable;
private BigDecimal time() {
try {
int nextI = 1;
int i;
long duration;
do {
i = nextI;
long start = System.nanoTime();
run(i);
duration = System.nanoTime() - start;
nextI = (i << 1) | 1;
} while (duration < 1000000000 && nextI > 0);
return new BigDecimal((duration) * 1000 / i).movePointLeft(3);
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
@Override
public String toString() {
return name + "\t" + time() + " ns";
}
enum ExceptionStrategy {
none {
@Override void run() {
// do nothing
}
},
normal {
@Override void run() {
throw new RuntimeException();
}
},
withoutStackTrace {
@Override void run() {
throw new RuntimeException() {
public synchronized Throwable fillInStackTrace() {
return this;
};
};
}
};
abstract void run();
}
private static Benchmark tryBenchmark(final int depth, final ExceptionStrategy strat) {
return new Benchmark("try, depth = " + depth + ", " + strat) {
@Override int run(int iterations) {
int x = 0;
for (int i = 1; i < iterations; i++) {
try {
x += recurseAndThrow(depth);
} catch (Exception e) {
x++;
}
}
return x;
}
private int recurseAndThrow(int i) {
if (i > 0) {
return recurseAndThrow(i - 1) + 1;
} else {
strat.run();
return 0;
}
}
};
}
public static void main(String[] args) throws Exception {
int[] depths = {1, 10, 100, 1000, 10000};
for (int depth : depths) {
for (ExceptionStrategy strat : ExceptionStrategy.values()) {
System.out.println(tryBenchmark(depth, strat));
}
}
}
}
在我的(相當陳舊的)筆記本上,將打印:
try, depth = 1, none 5.153 ns
try, depth = 1, normal 3374.113 ns
try, depth = 1, withoutStackTrace 602.570 ns
try, depth = 10, none 59.019 ns
try, depth = 10, normal 9064.392 ns
try, depth = 10, withoutStackTrace 3528.987 ns
try, depth = 100, none 604.828 ns
try, depth = 100, normal 49387.143 ns
try, depth = 100, withoutStackTrace 27968.674 ns
try, depth = 1000, none 5388.270 ns
try, depth = 1000, normal 457158.668 ns
try, depth = 1000, withoutStackTrace 271881.336 ns
try, depth = 10000, none 69793.242 ns
try, depth = 10000, normal 2895133.943 ns
try, depth = 10000, withoutStackTrace 2728533.381 ns
顯然,具體結果將隨您的硬件以及JVM的實現和配置而變化。 但是,一般模式可能保持不變。
結論:
Recommendatations:
例外很昂貴。 使用時,將創建堆棧跟蹤。 如果可以檢查異常,請執行此操作。 不要使用try..catch進行流量控制。 當您無法檢查/驗證時,請使用try..catch ; 一個示例是進行IO操作。
當我看到帶有大量try..catch塊的代碼時,我立即想到的是“這是一個糟糕的設計!”。
1.-調用堆棧深度無需擔心,Java即時編譯器將對代碼進行優化,例如方法內聯,以在代碼上提供最佳性能。
2.-捕獲塊確實會影響性能,這是因為捕獲異常可能意味着JVM內部有幾種不同的操作,例如遍歷異常表,堆棧展開和常見陷阱(對JIT的優化代碼進行優化)。
3.-作為一項建議,不要擔心封裝代碼並最終遇到可能導致巨大堆棧深度的多個方法調用,JVM會進行優化以在編譯應用程序並從中獲得最佳性能時進行優化當它運行時,始終要着眼於代碼的可讀性和良好的設計模式,因為這將有助於使您的代碼更易於維護和更容易修改,以防萬一必須進行性能修復。關於catch塊,請評估其必要性引發或捕獲的異常,如果要捕獲,請嘗試捕獲最通用的異常,這樣可以避免使用大量異常表。
在調用.printStackTrace或.getStackTrace之前,不會加載堆棧跟蹤。 如果在catch塊的開頭放置一個斷點,您會注意到Exception對象的堆棧跟蹤為空。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.