dene / yakala, istisna atar


117

Bu kod ifadeleri eşdeğer mi? Aralarında bir fark var mı?

private void calculateArea() throws Exception {
    ....do something
}

private void calculateArea() {
    try {
        ....do something
    } catch (Exception e) {
        showException(e);
    }
}

3
Aslında bir cevap değil, ancak Ned Batchelder'ın , bir stilin diğerinin tercih edileceği genel durumları açıklamaya yardımcı olan Yağmur Ormanındaki İstisnalar makalesi ilginizi çekebilir .
Daniel Pryden

1
catch'te "showException (e)" yerine, yakalama yerine "e atışı" olup olmadığını mı soruyordunuz (yoksa deneme / yakalamaya sahip değil miydiniz)?
MacGyver

Yanıtlar:


146

Evet, büyük bir fark var - ikincisi istisnayı yutuyor (kuşkusuz göstererek), oysa ilki yayılmasına izin veriyor. (Bunun showExceptiononu yeniden atmadığını varsayıyorum .)

Dolayısıyla, ilk yöntemi çağırırsanız ve "bir şeyler yap" başarısız olursa, arayanın istisnayı halletmesi gerekir. Eğer ikinci yöntemini çağırın ve başarısız "bir şey yapmak" Eğer sürece, o arayan, genellikle kötü bir şey olduğunu hiç bir istisna ... görmez showExceptionoldu gerçekten yanlış ne olursa olsun sabit istisna, ele ve genellikle emin oldum bu calculateAreaamacına ulaşmıştır.

Sen olmadan ilk yöntemini çağırın gelmediğinden dolayı bunu söylemek mümkün olacak ya alıcı Exceptionkendinizi ya da yöntem de bunu atmak olabileceğini açıkladılar.


12
"İstisnayı gerçekten ele almadığı sürece" dediğinizde, bu harika bir nokta. Sadece "İstisna" nın yakalanmasının kendisinin nadiren gerçek istisnayı akıllıca "ele almasına" yol açtığını eklemeyi düşündüm, bu da insanların mümkün olan en spesifik istisnayı yakalamanızı tavsiye etmelerinin sebebidir.
Bill K

17
+1. Çünkü Jon Skeet'in daha fazla itibara ihtiyacı var. Oh, cevap da güzeldi.
Jonathan Spiller

20

Birincisi throws Exception, bu yüzden arayanın Exception. İkincisi Exceptiondahili olarak yakalar ve idare eder , böylece arayanın herhangi bir istisna işlemi yapması gerekmez.


Kısacası, her zaman ikincisini kullanmalıyım. Haklı mıyım İlki aslında programın farklı noktalarında kullanılan bir yöntemdir. Bu yüzden daha fazla kullanım için talimatları bir araya getirmeye karar verdim ama bunu yaptıktan sonra T'nin büyük bir hata yaptığını anladım ..
carlos

9
Hayır, her iki desene de ihtiyaç vardır. Yönteminiz istisnayı ele alabiliyorsa, ikinci kalıbı kullanın, değilse, arayan kişiye haber vermek için ilkini kullanın.
Andreas Dolk

Hangi sürümü kullanacağınız gereksinimlerinize bağlıdır - temelde bu istisnayı hangi düzeyde ele almanız gerekir? Arayanın buna göre kodlanması gerekir. Bir arayan ilk sürümü arıyorsa ve yöntem tanımını ikinci sürümle değiştirirseniz, arayan kodunuz istisnayı işlemeye zorlanır, çünkü bu kontrol edilmiş bir istisnadır.
samitgaur

16

Evet. Bildiren sürüm throws Exception, istisnayı işlemek için çağıran kod gerektirirken, bunu açıkça işleyen sürüm bunu yapmayacaktır.

yani, basitçe:

performCalculation();

istisnayı ele alma yükünü arayan kişiye taşımak yerine:

try {
    performCalculation();
catch (Exception e) {
    // handle exception
}

6

Evet, aralarında büyük fark var. İlk kod bloğunda, istisnayı arama koduna iletirsiniz. İkinci kod bloğunda bunu kendiniz halledersiniz. Hangi yöntemin doğru olduğu tamamen ne yaptığınıza bağlıdır. Bazı durumlarda, kodunuzun istisnayı işlemesini istersiniz (örneğin, bir dosya bulunamazsa ve onu oluşturmak istiyorsanız), ancak diğerlerinde, çağıran kodun istisnayı işlemesini istersiniz (bir dosya bulunamadı ve yenisini belirtmeleri veya oluşturmaları gerekir).

Genel olarak konuşursak, genel bir istisna yakalamak istemezsiniz. Bunun yerine, örneğin sadece özel olanları yakalamak isteyeceksiniz FileNotFoundExceptionya IOExceptionda farklı anlamlara gelebilir çünkü.


3

Atışları kullanamadığımız belirli bir senaryo var, try-catch kullanmalıyız. "Geçersiz kılınan bir yöntem, ana sınıfının attığından başka herhangi bir ekstra istisna atamaz" kuralı vardır. Try-catch kullanılarak ele alınması gereken ekstra bir istisna varsa. Bu kod parçacığını düşünün. Basit bir temel sınıf var

package trycatchvsthrows;

public class Base {
    public void show()
    {
        System.out.println("hello from base");
    }
}

ve türetilmiş sınıf:

package trycatchvsthrows;

public class Derived extends Base {

    @Override
    public void show()   {
        // TODO Auto-generated method stub
        super.show();

        Thread thread= new Thread();
        thread.start();
        try {
            thread.sleep(100);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        // thread.sleep(10);
        // here we can not use public void show() throws InterruptedException 
        // not allowed
    }
}

Thread.sleep () 'yi çağırmamız gerektiğinde, try-catch kullanmak zorunda kalıyoruz, burada kullanamayız:

 public void show() throws InterruptedException

çünkü geçersiz kılınan yöntem ekstra istisnalar atamaz.


Herkesin bu uyarıdan haberdar olmadığına inanıyorum. İyi sivri uçlu.
ivanleoncz

1

"Özdeş" derken davranıştan bahsettiğinizi varsayıyorum.

Bir fonksiyonun davranışı şu şekilde belirlenebilir:

1) Dönen değer

2) Atılan istisnalar

3) Yan etkiler (yani yığın, dosya sistemi vb. Değişiklikler)

Bu durumda, ilk yöntem herhangi bir istisnayı yayarken, ikincisi hiçbir kontrol edilmiş istisnayı atmaz ve kontrol edilmeyen istisnaların çoğunu da yutar, dolayısıyla davranış farklıdır.

Bununla birlikte, "bir şey yap" ın asla bir istisna atmayacağını garanti ederseniz, davranış aynı olacaktır (ancak derleyici ilk sürümde, arayanın istisnayı işlemesini isteyecektir)

--Düzenle--

API tasarımı açısından, yöntemler sözleşmelerinde tamamen farklıdır. Ayrıca, sınıf istisnası atılması önerilmez. Arayanın istisnayı daha iyi idare etmesini sağlamak için daha spesifik bir şey atmayı deneyin.


1

Bir istisna atarsanız, alt yöntem (bunu geçersiz kılan) istisnayı işlemelidir.

misal:

class A{
public void myMethod() throws Exception{
 //do something
}
}

A a=new A();
try{
a.myMethod();
}catch Exception(e){
//handle the exception
}

0

Çoğu zaman arayanın istisnayı halletmesini istersiniz. Arayanın, her yöntemin istisnayı ele almasını sağlamak yerine, başka bir yöntemi çağıran başka bir yöntemi çağıran bir yöntemi çağırdığınızı varsayalım, bunu yalnızca çağırıcıda halledebilirsiniz. Bu yöntem başarısız olduğunda yöntemlerden birinde bir şeyler yapmak istemediğiniz sürece.


0

Bu yöntemin çağıranının ya bu istisnayı yakalaması ya da yöntem imzasında yeniden ifade edileceğini bildirmesi gerekecektir.

private void calculateArea() throws Exception {
    // Do something
}

Aşağıdaki try-catch blok örneğinde. Bu yöntemi arayan kişinin halihazırda halihazırda halledildiği için istisnayı ele alma konusunda endişelenmesine gerek yoktur.

private void calculateArea() {
    try {
        // Do something

    } catch (Exception e) {
        showException(e);
    }
}

0
private void calculateArea() throws Exception {
    ....do something
}

Bu, istisnayı atar, böylece arayan bu istisnayı ele almaktan sorumludur, ancak arayan istisnayı işlemezse, jvm'ye verilebilir ve bu da programın anormal sonlandırılmasına neden olabilir.

İkinci durumda ise:

private void calculateArea() {
    try {
        ....do something
    } catch (Exception e) {
        showException(e);
    }
}

Burada istisna, aranan uç tarafından ele alınır, bu nedenle programın anormal sonlandırma şansı yoktur.

Try-catch , önerilen yaklaşımdır.

IMO,

  • Derleyiciyi ikna etmek için çoğunlukla Denetlenen istisnalarla kullanılan anahtar sözcüğü atar, ancak programın normal sonlandırılmasını garanti etmez.

  • Çağrı yapana
    (JVM veya başka bir yöntem) istisna işleme sorumluluğu temsilcisi atar .

  • Throws anahtar kelimesi yalnızca kontrol edilen istisnalar için gereklidir, kontrol edilmeyen istisnalar için throws anahtar kelimesi kullanılmaz.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.