Aynı işlev / yöntemde istisnalar atma ve yakalama


10

Kullanıcı bir pozitif tamsayı (doğal bir sayı) girene kadar bir kullanıcı giriş için soran bir işlev yazdım. Birisi fonksiyonumda istisnalar atmamalı ve yakalamamam gerektiğini ve fonksiyonumun arayanının onları idare etmesine izin vermesi gerektiğini söyledi.

Diğer geliştiricilerin bu konuda ne düşündüğünü merak ediyorum. Ayrıca muhtemelen işlevdeki istisnaları kötüye kullanıyorum. Java kodu:

private static int sideInput()
{
    int side = 0;
    String input;
    Scanner scanner = new Scanner(System.in);

    do {
        System.out.print("Side length: ");
        input = scanner.nextLine();
        try {
            side = Integer.parseInt(input);
            if (side <= 0) {
                // probably a misuse of exceptions
                throw new NumberFormatException();
            }
        }
        catch (NumberFormatException numFormExc) {
            System.out.println("Invalid input. Enter a natural number.");
        }
    } while (side <= 0);

    return side;
}

İki şeyle ilgileniyorum:

  1. Arayanın istisnalar hakkında endişelenmesine izin vermeli miyim? İşlevin amacı, kullanıcı doğal bir sayı girene kadar kullanıcıyı sektirmesidir. İşlevin noktası kötü mü? Kullanıcı arabirimi (kullanıcı doğru girdi olmadan döngüden çıkamıyorum) hakkında değil, istisnalar işlenen döngüsel girdi hakkında konuşmuyorum.
  2. Fırlatma ifadesinin (bu durumda) istisnaların kötüye kullanılması olduğunu söyleyebilir misiniz? Numaranın geçerliliğini kontrol etmek için kolayca bir bayrak oluşturabilir ve bu bayrağa göre uyarı mesajı verebilirim. Ama bu koda daha fazla satır eklemek istiyorum ve ben olduğu gibi mükemmel okunabilir düşünüyorum.

Mesele şu ki ayrı bir giriş fonksiyonu yazıyorum. Kullanıcı birden çok kez bir sayı girmek zorundaysa, girdi için tüm biçimlendirme istisnalarını ve sınırlamalarını işleyen ayrı bir işlev oluştururum.


Yüksek oranda dile bağlıdır. Bazı diller istisnaları diğerlerinden daha özgürce kullanır.
Martin York

Yanıtlar:


11

İstisnaların amacı, bir yöntemin sizi arayan değere normal bir şekilde devam edemediği bir duruma giren, sizi dönüş değerine bir hata kodu gömmeye zorlamadan söylemesine izin vermesidir.

Sizin durumunuzda, yönteminiz giriş 0'dan büyük olmadığında ne yapacağınızı tam olarak bilir. Burada satır kaydetmenin tek nedeni, giriş bir sayı olmasaydı alacağınız istisnayı atmanızdır. Ancak, attığınız istisna, kodunuzun neden girişi sevmediğini doğru bir şekilde göstermiyor. Başka biri gelip bu kodu görseydi, işlerin tam olarak nasıl çalıştığını görmek için fazladan zaman harcamak zorunda kalacaklardı.


Evet, bu yüzden bunun bir yanlış kullanım olduğunu düşündüm. Yani, bu throw ifadesini göz ardı ederek, arayanın onları yakalamasına izin vermek yerine, bir işlev içindeki böyle bir döngüde istisnaları işlemenin uygun olduğunu mu kabul ediyorsunuz? Catch deyimi orada Integer.parseInt (yine, atmayı görmezden) nedeniyle.
usr

1
@usr: Bu cevap daha çok sistemin geri kalanının birlikte nasıl çalıştığına bağlı. İstisnaların bir noktada ele alınması gerekir. Onu organize etmenin birkaç farklı yolu var ve bu onlardan biri. En iyisi, burada sahip olmadığımız diğer bilgilere bağlıdır.
unholysampler

4

Bu istisnaların kötü kullanımıdır. Başlangıç ​​olarak, pozitif olmayan bir sayı biçim istisnası değildir.

Neden istisnalar kullanılmalı? Hangi girişe izin verilmediğini biliyorsanız, kullanıcıdan geçerli bir girdi elde edene kadar döngüden çıkmayın, aşağıdakine benzer:

while (true)
{
   // Get user input.
   String input = scanner.nextLine();

   try
   {
      side = Integer.parseInt(input);

      break;
   }
   catch (NumberFormatException ex)
   {
      // Inform user of invalid input.
      System.out.println("Invalid input. Enter a natural number.");
   }
}

Integer.intParse bir biçim istisnası atar, bu nedenle catch deyimini kullanmak tamamen geçerlidir. Ben esas olarak bir fonksiyonda bir döngüde catch deyimi kullanmak için Tamam olup olmadığını bilmek istiyorum veya ben fonksiyon tanıtıcı biçimi istisna izin gerekir.
usr

Integer.parseInt()NumberFormatExceptionverilen dize bağımsız değişkenini ayrıştıramıyorsa bir atar . İstisnayı kendiniz atmanıza gerek yoktur (ve yapamazsınız).
Bernard

Kod örneğini daha açık olacak şekilde düzenledim.
Bernard

"ve bunu yapamazsınız) istisnayı kendiniz fırlatabilirsiniz" - orada ne demek istiyorsun?
Michael Borgwardt

@Michael Borgwardt: Yani, eğer Integer.parseInt()yöntem gerçekleşirse sizin için istisnayı atacağından, daha önce atıldığından beri kendiniz atamazsınız.
Bernard

1

Yalnızca geçerli yöntem çağrısı ile ilgili bir şey yapmak istiyorsanız istisnaları yakalayın; temizleme, hata mantığı vb. Bu durumda, yakalama yalnızca konsola bir mesaj gönderir, sideInput yöntemiyle ilgili değildir, bu nedenle çağrı zinciri / yığını üzerinde daha fazla ele alınabilir.

Burada denemek / yakalamak kurtulmak ve sadece yöntem çağrısı belgelemek:

//Throws NumberFormatException if read input is less than 0
private static int sideInput()

Hala bu istisnayı çağrı zinciri / yığını daha ileri ele gerekir!


1
Mesaj sadece daha iyi bir kullanıcı arayüzü için var. Fonksiyonun amacı, geçerli bir giriş girene kadar kullanıcıyı giriş için tıklamasıdır. Bu try-catch blokları olmadan yapılamaz. Benim sorum noktanın geçerli olup olmadığıydı. Sanırım öyle, ama birisi bana try-catch bloklarını kaldırmam ve arayanın bu özel istisnayı ele alması gerektiğini söyledi. Ancak, işlev amaçlandığı gibi çalışmaz.
usr

1

Bir yöntemde aynı istisnayı hem atmalı hem de yakalamamalısınız, hatta catch bloğunun attığınız aynı istisnayı yakalayacağını düşünüyorum, bu yüzden gerçekten atmıyorsunuz.

parseIntBaşarılı olsaydı , o değil NumberFormatException.

taraf sıfırdan küçükse, a atmalısınız NegativeSideLengthException;

Adlı bir özel / iş istisnası oluşturun NegativeSideLengthException

public class NegativeSideLengthException extends Exception
{


    public NegativeSideLengthException(Integer i)
    {
        super("Invalid negative side length "+i);        
    }

}

Sonra sideInputNegativeSideLengthException atar

private static int sideInput() throws NegativeSideLengthException
{
    int side = 0;
    String input;
    Scanner scanner = new Scanner(System.in);

    do {
        System.out.print("Side length: ");
        input = scanner.nextLine();
        try {
            side = Integer.parseInt(input);
            if (side <= 0) {
                throw new NegativeSideLengthException(side);
            }
        }
        catch (NumberFormatException numFormExc) {
            System.out.println("Invalid input. Enter a natural number.");
        }
    } while (side <= 0);

    return side;
}

Hatta (isterseniz) yakalamak için başka bir catch bloğu ekleyebilir NegativeSideLengthExceptionve yöntemin atmasını sağlayamazsınız.

do {
    System.out.print("Side length: ");
    input = scanner.nextLine();
    try {
        side = Integer.parseInt(input);
        if (side <= 0) {
            throw new NegativeSideLengthException(side);
        }
    }
    catch (NumberFormatException numFormExc) {
        System.out.println("Invalid input. Enter a natural number.");
    } catch (NegativeSideLengthException e){
        System.out.println("Invalid input. Enter a non-negative number.");
    }
} while (side <= 0);

Bayraklar istisnaları ele almak için iyi bir yol değildir.


-1

İstisnalar oldukça kabusuz şeyler, çözdüklerinden daha fazla karmaşıklık getiriyorlar.

İlk olarak, istisnalarınızı yakalamazsanız, arayan sadece yapabilir on error resume next, yani bir hafta sonra işlevinizin ne atabileceğini ve onunla ne yapacağını bilemezsiniz:

{
    ...
}
catch(OutOfMemory, CorruptedMemory, BadData, DanglingPointers, UnfinishedCommit)
{
    Console.WriteLine("Nothing to see here, move on.");
    Console.WriteLine("The app is very stable, see, no crashing!");
}

Temel olarak, onları yakalarsanız, sözleşmeler ve istisna garantileri hakkında çok iyi bir anlayışa sahip olmanız gerekir. Bu nadiren gerçek bir dünyada olur. Ayrıca kodunuzu okumak zor olacaktır.

Ayrıca, komik olan şey, gerçekten istisnaları ele alma şansınız varsa, Java ve .NET'in tamamen istisnalarla ilgili olması nedeniyle, bir çeşit mizahi olan gerçek RAII diline ihtiyacınız var ...

Bunu bir kez daha tekrarlıyorum, ama ...:

http://blogs.msdn.com/b/oldnewthing/archive/2004/04/22/118161.aspx

http://blogs.msdn.com/b/oldnewthing/archive/2005/01/14/352949.aspx

http://www.joelonsoftware.com/items/2003/10/13.html


4
OP'nin asıl sorusunu cevaplamak yerine, oldukça doğru olmayan - veya en azından bağlama / dile bağlı - ifadelerle dolu bir sınır çizgisi yayınlamak için -1 .
Péter Török

@ PéterTörök: "Bir adama bir balık verin ve onu bir günlüğüne besleyin. Bir adama balık tutmayı öğretin ve onu ömür boyu beslersiniz." İstisnaların arkasında çok ciddi sorunlar var ve insanlar onları -1000 / + 1 bilmeli, gerçekten umrumda değil.
Kodlayıcı

1
İstisnasız olarak doğru kodu daha kolay yazabileceğinize inanmaktan çekinmeyin. Görüşlerinizi ve inançlarınızı gerçekler olarak belirtmeyin (Joel aynı görüşte olsa bile, bu hala bir gerçek değil, bir fikirdir) ve SE'ye alakasız cevaplar göndermeyin.
Péter Török

@ PéterTörök: Bu bir fikir değil, bu bir gerçek, dahili olarak bir istisna atan bir bileşeni her kullandığınızda, tüm hiyerarşiyi taramanız ve ne yakalayacağınızı bilmek için her bir kod satırını kontrol etmeniz ve bileşenlerin güçlü olup olmadığını kontrol etmeniz gerekir. garanti, ve her şey geri alınır veya bu yakalama sadece sahte bir güvenlik duygusu ise. Heck, std :: string'in tüm istisnalarını bile bilmiyorsunuz, teknik özelliklere bakabilirsiniz, ancak asla bulamazsınız. Gibi şeyler : throw(thisexception, thatexception)düpedüz yanlış ve asla kullanılmamalıdır, çünkü aksi takdirde beklenmedik olacaksınız.
Kodlayıcı

2
Tamam, kod istisnaları kullanmamaya ne dersiniz? Gee, dönüş değerlerinin düzgün işlenip işlenmediğini veya yoksayıldığını görmek için her satırı kontrol etmek için kodu taramanız gerekiyor. Bir dönüş değeri göz ardı edildiğinde, uygulamanız birkaç bin satır sonra çökene kadar kimse fark etmez. İstisnalar en azından sizi fark etmeye zorlar . Evet, onları yutabilirsiniz - ancak sadece açık bir şekilde catch. Yok sayılan bir dönüş değeri erişilemez olsa da, yalnızca satır satır kod incelemesi ile tanımlanabilir. Son fakat en önemlisi, kurucuların dönüş değerleri yoktur, bu istisnaları kullanmanın en önde gelen nedenidir.
Péter Török
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.