Etkili deneme / yakalama blok kullanımı?


21

Yakalama blokları mantık yazmak için mi kullanılmalıdır, yani akış kontrolü vb. Yoksa sadece istisnalar atmak için mi? Kodun verimliliğini veya sürdürülebilirliğini etkiler mi?

Yakalama bloğunda mantık yazmanın yan etkileri (varsa) nelerdir?

DÜZENLE:

Yakalama bloğu içinde mantık yazdıkları bir Java SDK sınıfı gördüm. Örneğin (snippet java.lang.Integersınıftan alınmıştır ):

        try {
            result = Integer.valueOf(nm.substring(index), radix);
            result = negative ? new Integer(-result.intValue()) : result;
        } catch (NumberFormatException e) {
            String constant = negative ? new String("-" + nm.substring(index))
                                       : nm.substring(index);
            result = Integer.valueOf(constant, radix);
        }

EDIT2 :

Ben istisnalar içinde istisnai durumlarda mantık yazma avantajı olarak saymak bir öğretici geçiyordu :

İstisnalar, kodunuzun ana akışını yazmanıza ve başka yerlerdeki istisnai durumlarla başa çıkmanıza olanak tanır.

Yakalama bloğuna ne zaman mantık yazılır ve ne zaman girilmez?


12
@Coder Sanırım biraz fazla genelleştiriyorsunuz. Özellikle mevcut API'ların çoğunda bundan kaçınamazsınız.
CodesInChaos

8
@Coder: Java'da istisnalar genellikle yasal kod akışının bir parçası olan sorunları bildirmek için bir mekanizma olarak kullanılır. Örneğin, bir dosyayı açmaya çalışırsanız ve başarısız olursa, Java kitaplığı bunu bir istisna atarak söyler, çünkü bir dosyayı açmaya neden olan API'larda hata döndürmek için başka bir mekanizma yoktur.
JeremyP

4
@Coder Bağlıdır. IO yaparken veya neredeyse her zaman doğru biçimlendirilmiş karmaşık verileri ayrıştırırken, bir hatayı belirtmek için bir istisna atmak kodu çok daha temiz yapar düşünüyorum.
CodesInChaos

1
@Coded Evet, yürütme, kendisine sorulan şeyi yapamadığını söyleyen yöntem için var. Ancak akış kontrolü için istisnalar kullanılmamalıdır, bu yüzden C # da atmayan bir int.TryParse yöntemine sahiptir.
Andy

1
@Coder: Bu çok saçma. Bir kod düzeyinde istisnai olan şeyler başka bir kodda istisnai olmayabilir veya devam etmeden önce örneğin hata veya hata ayıklama bilgileri sunmak veya eklemek isteyebilirsiniz.
DeadMG

Yanıtlar:


46

Alıntı yaptığınız örnek, zayıf API tasarımından kaynaklanmaktadır (bir String'in ayrıştırmaya çalışmak ve istisnayı yakalamak dışında geçerli bir tam sayı olup olmadığını kontrol etmenin temiz bir yolu yoktur).

Teknik düzeyde, atma ve deneme / yakalama , çağrı yığınını yukarı atlamanıza izin veren kontrol akışı yapılarıdır , daha fazla ve daha az bir şey değildir. Çağrı yığınını yukarı atlamak, kaynakta birbirine yakın olmayan ve korunma açısından kötü olan kodu dolaylı olarak bağlar . Bu yüzden sadece bunu yapmanız gerektiğinde kullanılmalı ve alternatifler daha da kötüdür. Alternatifler kötüdür yaygın olarak kabul vaka hata işleme olan (gerek kontrol ve manuel çağrı yığınının her düzey yukarı geçirilecek bu özel dönüş kodları).

Alternatiflerin daha kötü olduğu bir durumunuz varsa (ve hepsini gerçekten dikkatlice düşündüyseniz), o zaman kontrol akışı için atma ve dene / yakala işlevinin iyi olduğunu söyleyebilirim . Dogma yargılamanın yerine geçmez.


1
+1, iyi puanlar verildi. Bazı işlemlerin bir hata iletisinin hazırlanması ve hata günlüğü gibi yakalamada geçerli olabileceğini düşünüyorum. Db bağlantıları ve (.NET) COM başvuruları gibi pahalı kaynakların serbest bırakılması, Nihayet bloğuna eklenebilir.
NoChance

@EmmadKareem Kaynakları serbest bırakmayı düşündüm, ancak genellikle bunları hata durumunda bile olsa bir noktada serbest bırakmanız gerekir. Böylece kendinizi tekrarlayabilirsiniz. Bir günlük mesajı hazırlamak elbette kabul edilebilir.
scarfridge

@MichaelBorgwardt Bence API tasarımı çok zayıf değil (daha iyi olabilir). Geçersiz bir dizeyi ayrıştırmaya çalışmak açıkça bir hata koşulu ve dolayısıyla tam olarak bahsettiğiniz "yaygın olarak kabul edilen durum" dur. Kabul edildi, bir dizenin sözdizimsel olarak doğru olup olmadığını belirlemek için bir yöntem kullanışlı geliyor (bu daha iyi olabilir nerede). Ancak, gerçek ayrıştırmadan önce herkesi bu yöntemi çağırmaya zorlamak mümkün değildir ve hatayı ele almamız gerekir. Gerçek sonucu ve hata kodunu karıştırmak rahatsız edicidir ve bu nedenle istisnayı atmaya devam edersiniz. Ama belki de bir çalışma zamanı istisnası.
scarfridge

3
Bu son cümle için +1.
SinirliWithFormsDesigner

2
@scarfridge: Seninle tamamen aynı fikirdeyim :) Boole döndüren isInteger (String) yönteminin olmaması "kötü API tasarımı" ile kastettiğim tek şey
Michael

9

Bu, dile ve paradigmaya bağımlı olma eğiliminde olan bir şeydir.

İşlerimin çoğu Java'da (ve bazen C ++) yapılır. Eğilim istisnaları yalnızca istisnai durumlar için kullanma eğilimindedir. Orada Java istisnalar performans yükü hakkında Yığın taşması bazı sorular ve gördüğünüz gibi, tam olarak önemsiz değil. Kodun okunabilirliği ve sürdürülebilirliği gibi başka endişeler de vardır. Düzgün kullanıldığında, istisnalar hata işlemeyi uygun bileşenlere devredebilir.

Ancak Python'da affetmenin, izin istemekten daha kolay olduğu fikri. Python topluluğunda, bu C tarzı dillerde "sıçramadan önce bak" ( LBYL ) yaklaşımının aksine EAFP olarak bilinir .


2
İstisnalar hariç genel giderlerden bahsettiği için +1. .NET ve (en azından makinemde) yapıyorum, bazı durumlarda diğer normal işlemlerle karşılaştırıldığında bir istisna gerçekleşmek üzereyken bile hissedebiliyordum.
NoChance

2
@EmmadKareem Yalnızca bağlı bir hata ayıklayıcı varsa. Bir hata ayıklayıcı olmadan saniyede birkaç bin atabilirsiniz.
CodesInChaos

@CodeInChaos, haklısın. Nasıl bilebilirim ki, çalışma zamanında hiçbir zaman alamayacak kadar temiz bir kod
yazarım

@EmmadKareem Bir ağ uygulamasının nasıl yazıldığına bağlı olarak, bağlantı veya protokol hataları bir istisna ile işlenir. Önemsiz DoS saldırılarını önlemek için böyle bir uygulamada istisnaların oldukça hızlı olması gerekir.
CodesInChaos

@CodeInChaos, bunu bilmek güzel. Son yorumda şaka yapıyordum.
NoChance

9

Bu, try / catch bloklarını düşünmenin en iyi yolu değildir. Deneme / yakalama blokları hakkında düşünmenin yolu şudur: Bir başarısızlık meydana geldi, BU spesifik başarısızlıkla başa çıkmak için en iyi yer nerede. Bu bir sonraki kod satırı olabilir, çağrı zincirinin yirmi seviyesi kadar olabilir. Nerede olursa olsun, olması gereken yer burası.

Catch bloğunun yaptığı hataya ve bu konuda neler yapabileceğinize bağlıdır. Bazen göz ardı edilebilir (içinde önemli veri bulunmayan bir sıfırdan dosya silinemedi), bazen bir işlevlerin dönüş değerini true veya false olarak ayarlamak için kullanılır (java'nın int ayrıştırma yöntemi), bazen programdan çıkacaksınız . Bütün bunlar hataya bağlıdır.

Anlaşılması gereken önemli kısım: catch block == Bununla nasıl başa çıkacağımı biliyorum.


6

Yakalama blokları sadece istisnaları işlemek için kullanılmalıdır, başka hiçbir şey ve asla kontrol akışı için kullanılmamalıdır. Akışı yönetmek için istisnalar kullanmak istediğiniz her durumda, ön koşulları kontrol etmek daha iyi olur.

İstisnalar dışında akışı işleme yavaş ve anlamsal olarak yanlıştır.


4
Ne dediğini biliyorum, ancak istisnaların yaptığı tek şeyin program akışını işlemek olduğunu belirtmek gerekir - sadece istisnai hata akışını kontrol etmek için kullanılmalıdır ...
Max

Yakalama bloğuna ne zaman mantık yazılacağı ve ne zaman yapılamayacağına dair özel kurallar yok mu?
HashimR

4
Java'nın Numara ayrıştırıcıları ve Metin formatlayıcıları, sorunlu istisna kullanımının ünlü örnekleridir: bir ön koşulu (bir dizenin ayrıştırılabilir bir sayıyı temsil ettiği) kontrol etmenin tek makul yolu, onu ayrıştırmayı denemektir ve bir istisna ile başarısız olursa, seçenekleriniz nelerdir uygulamada? Anlamsal olarak yanlış görünse de, istisnayı yakalamalı ve onunla akışı yönetmelisiniz.
Joonas Pulakka

@JoonasPulakka Bence yorumunuz wrt Sayı ayrıştırıcıları ve Metin formatlayıcıları bu soruya tam boyutlu bir cevap olarak nitelendirilir
gnat

5

Yakalama blokları mantık yazmak için mi kullanılmalıdır, yani akış kontrolü vb. Yoksa sadece istisnalar atmak için mi? Kodun verimliliğini veya sürdürülebilirliğini etkiler mi?

İlk olarak, "istisnai durumlar için istisnalar kullanılmalıdır" fikrini unutun. Ayrıca, kabul edilemez şekilde çalışan bir kodunuz olana ve sorunun nerede olduğunu bilmek için ölçünceye kadar verimlilik konusunda endişelenmeyi bırakın.

Kod, eylemlerin koşulsuz olarak basit bir sırayla takip edildiğini anlamanın en kolay yoludur. İstisnalar, hata kontrolünü normal akıştan kaldırarak sürdürülebilirliği artırır. Yürütmenin normal akışı zamanın% 99.9'u veya zamanın% 50'si veya zamanın% 20'si izlemesi önemli değildir.

Bir işlev bir değer döndüremediğinde, bir prosedür beklenen eylemi tamamlayamadığında veya bir kurucu kullanılabilir bir nesne üretemediğinde bir istisna atın. Bu, programcıların bir işlevin her zaman kullanılabilir bir sonuç döndürdüğünü, bir yordam her zaman istenen eylemi tamamladığını, yapılandırılmış bir nesnenin her zaman kullanılabilir bir durumda olduğunu varsaymasını sağlar.

İstisna işleme kodu ile gördüğüm en büyük sorun, programcıların yapmamaları durumunda try / catch blokları yazmalarıdır. Örneğin, çoğu web uygulamasında, bir veritabanı isteği bir istisna atarsa, denetleyicide yapılabilecek hiçbir şey yoktur. En üst düzeyde bir genel yakalama maddesi yeterlidir. Daha sonra denetleyici kodu, diskin çökme veya veritabanının çevrimdışı veya başka bir şey olma olasılığını göz ardı edebilir.


1

Yakalama blokları kod mantığı yazmak için kullanılmamalıdır. Yalnızca hataları işlemek için kullanılmalıdır. Bir örnek (1) tahsis edilen kaynakları temizlemek, (2) faydalı bir mesaj yazdırmak ve (3) zarif bir şekilde çıkmaktır.

İstisnaların kötüye kullanılabileceği ve istenmeyen gotoetkilere neden olabileceği doğrudur . Ama bu onları işe yaramaz yapmaz. Ne zaman doğru kullanıldığında , bunlar kod birçok yönünü geliştirebilir.

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.