Prestazioni di prova / cattura Java, è consigliabile mantenere al minimo ciò che è contenuto nella clausola try?

Considerando che hai un codice come questo:

doSomething() // this method may throw a checked a exception //do some assignements calculations doAnotherThing() //this method may also throw the same type of checked exception //more calls to methods and calculations, all throwing the same kind of exceptions. 

Ora so che, quando si costruisce l’eccezione, si verifica effettivamente un problema di prestazioni, in particolare durante lo svolgimento dello stack. E ho anche letto diversi articoli che indicano un leggero calo di prestazioni quando si inseriscono i blocchi try / catch, ma nessuno degli articoli sembra concludere nulla.

La mia domanda è, si consiglia di mantenere le linee all’interno del try catch al minimo indispensabile ?, cioè SOLO avere all’interno della clausola try le linee che possono effettivamente lanciare l’eccezione che si sta intercettando. Il codice all’interno della clausola try viene eseguito più lentamente o causa un qualsiasi calo di prestazioni ?.

Ma più importante di quello che è la soluzione migliore / soluzione più leggibile considerando questo:

 try { doSomething() // this method may throw a checked a exception //do some assignements calculations doAnotherThing() //this method may also throw the same type of checked exception //more calls to methods and calculations, all throwing the same kind of exceptions. } catch (MyCheckedException e) { //handle it } 

o :

 try { doSomething() // this method may throw a checked a exception } catch (MyCheckedException e) { //Store my exception in a Map (this is all running in a loop and I want it to continue running, but I also want to know which loops didn't complete and why) continue; } //do some assignements calculations try { doAnotherThing() // this method may throw a checked a exception } catch (MyCheckedException e) { //Store my exception in a Map (this is all running in a loop and I want it to continue running, but I also want to know which loops didn't complete and why) continue; } 

Questo sta considerando che gestirai TUTTE queste eccezioni controllate esattamente allo stesso modo, naturalmente.

Nell’esempio qui riportato, il vero risultato in termini di prestazioni è se sia doSomething () che doAnotherThing () generano eccezioni. L’immissione di un try-block è veloce, finché non genera un’eccezione.

Si riduce davvero a ciò che è la tua situazione. Se hai bisogno di fare la stessa cosa quando MyCheckedException viene lanciato in entrambi i casi, lo considererei più leggibile e più performante per averli entrambi nello stesso blocco try, ma se hai bisogno di gestire le due diverse situazioni in modo diverso allora ovviamente ha più senso separarli.

Edit: ho letto la fine del tuo commento, stai assumendo la gestione allo stesso modo, nel qual caso li metterei entrambi nello stesso try-block.

È consigliabile mantenere le linee all’interno del fermo di prova al minimo?

No. Non riesco ad immaginare come si possa pensare che la lunghezza di un blocco try o di qualsiasi blocco possa avere un impatto sulle prestazioni.

Il codice all’interno della clausola try viene eseguito più lentamente o causa un qualsiasi calo di prestazioni ?.

No.

Come hai osservato, le eccezioni comportano solo costi di performance quando vengono lanciate.

Se sei preoccupato di “provare” le prestazioni, sicuramente la cosa da fare è mantenere il codice all’interno al massimo?

Non sono sicuro quale sia più lento, ma non dimenticare che un blocco try è il controllo del stream. Dovresti far corrispondere il stream di controllo a ciò che stai cercando di ottenere. Per me, la scelta tra

 try { // op 1. // op 2. / ... // op n. } catch ( MyCheckedException error ) { // handle any `MyException` in op 1, 2 ... n. } 

e catch blocchi di catch separati per ciascuno sono principalmente una decisione se voglio fare una gestione diversa per ogni operazione, continuare a eseguire fino a quando n prescindere dagli errori o tentare di eseguirli tutti e fallire al primo errore.

Scrivi un codice pulito e leggibile, quindi cerca i colli di bottiglia. Se gli esperimenti esistenti non possono portare a delle linee guida di base, allora sospetto che non sia il caso in cui troverai comunque i colli di bottiglia.

Avere blocchi di prova dovrebbe avere praticamente zero effetti sulle prestazioni in qualsiasi JVM decente. Il vero colpo arriva quando viene effettivamente lanciata un’eccezione.

Puoi leggere questo articolo per avere un’idea di come la JVM implementa la gestione delle eccezioni in bytecode: crea “tabelle di eccezioni” che mappano le regioni del codice per catturare / infine i blocchi, quindi:

  • Il bytecode per un try-block è lo stesso di un blocco standard {}
  • L’unico costo aggiuntivo nel caso di non lancio è quello di avere la “tabella delle eccezioni” caricata in memoria.

Ovviamente, quando viene lanciata un’eccezione c’è un sacco di stack in corso, quindi avrà un costo. Comunque, non è così male come con SEH (eccezioni .NET).

Il tuo codice dovrebbe gestire solo le eccezioni alle quali può fare qualcosa, gli altri dovrebbero essere ri-lanciati.

La quantità di codice nel blocco try non causa rallentamenti, colpendo il blocco catch. Ma a meno che tu non stia cercando di scrivere codice ad alte prestazioni, non me ne preoccuperei.

Mantenere il numero di blocchi try / catch al minimo migliorerà leggermente le prestazioni, ma lo spostamento del lavoro non farà realmente la differenza, ad eccezione del lavoro che verrebbe saltato a causa di un’eccezione generata.

C’è un sovraccarico per ogni blocco di eccezioni. Quindi, vuoi massimizzare la quantità di tempo in cui stai in un blocco.

Tuttavia, devi anche considerare la differenza nella semantica. Nel tuo primo esempio, se doSomething() genera un’eccezione, quindi non verrà eseguito un altro doAnotherThing() . Nel secondo esempio (supponendo che il gestore di catch non ritorni), verrà eseguito un altro doAnotherThing() .

Le eccezioni costano molto perché ogni volta che viene lanciata un’eccezione, la traccia dello stack deve essere creata e popolata.

Immagina un’operazione di trasferimento di equilibrio che non riesce nell’1% dei casi a causa della mancanza di fondi. Anche con questa percentuale relativamente bassa di guasti, le prestazioni potrebbero essere gravemente compromesse.

Vedi i codici sorgente e i risultati dei benchmark qui .

Non sono sicuro che all’interno del blocco try le prestazioni potrebbero essere lente, ma quello che so è che le prestazioni di ex.getStackTrace() sono molto lente perché rivelano tutto lo stack dei comandi e dovresti stare attento a questo.