1. İstisna türleri

İstisna türleri

Tüm istisnalar, aslında birbirini miras alan sınıflar olan 4 türe ayrılır.

Throwablesınıf

Tüm istisnalar için temel sınıf, sınıftır Throwable. Sınıf, Throwablegeçerli çağrı yığınını (geçerli yöntemin yığın izlemesi) bir diziye yazan kodu içerir. Yığın izlemenin ne olduğunu biraz sonra öğreneceğiz.

Fırlatma operatörü , yalnızca sınıftan türetilen bir nesneyi kabul edebilir Throwable. Ve teorik olarak şöyle bir kod yazabilseniz de throw new Throwable();, bunu genellikle kimse yapmaz. Sınıfın temel amacı Throwable, tüm istisnalar için tek bir üst sınıfa sahip olmaktır.

Errorsınıf

Bir sonraki istisna sınıfı Error, sınıfı doğrudan miras alan sınıftır Throwable. Java makinesi, ciddi sorunlar meydana geldiğindeError sınıfın (ve soyundan gelenlerin) nesnelerini oluşturur . Örneğin, bir donanım arızası, yetersiz bellek vb.

Genellikle bir programcı olarak, programda böyle bir hatanın (atılması gereken türden) meydana geldiği bir durumda yapabileceğiniz hiçbir şey yoktur : bu hatalar çok ciddidir. ErrorYapabileceğiniz tek şey, kullanıcıya programın kilitlendiğini bildirmek ve/veya hatayla ilgili bilinen tüm bilgileri program günlüğüne yazmaktır.

Exceptionsınıf

Exceptionve sınıfları RuntimeException, birçok yöntemin çalışmasında meydana gelen yaygın hatalar içindir. Fırlatılan her istisnanın amacı , onu düzgün bir şekilde nasıl ele alacağını bilen bir blok tarafından yakalanmaktır .catch

Bir yöntem herhangi bir nedenle işini tamamlayamadığında, uygun türde bir istisna atarak çağıran yönteme derhal bildirimde bulunmalıdır.

Başka bir deyişle, bir değişken eşittir ise null, yöntem bir atar NullPointerException. Yönteme yanlış bağımsız değişkenler iletildiyse, bir InvalidArgumentException. Yöntem yanlışlıkla sıfıra bölerse, bir ArithmeticException.

RuntimeExceptionsınıf

RuntimeExceptionsnin bir alt kümesidir Exceptions. RuntimeExceptionBunun sıradan istisnaların ( ) hafif bir versiyonu olduğunu bile söyleyebiliriz Exception- bu tür istisnalara daha az gereksinim ve kısıtlama uygulanır.

Exceptionile arasındaki farkı daha sonra öğreneceksiniz RuntimeException.


2. Throws: kontrol edilen istisnalar

Atar: kontrol edilen istisnalar

Tüm Java istisnaları 2 kategoriye ayrılır: işaretli ve işaretsiz .

RuntimeExceptionveya öğesini devralan tüm istisnalar, denetlenmeyen istisnalarError olarak kabul edilir . Diğer tüm istisnalar kontrol edilir .

Önemli!

Denetlenen istisnaların tanıtılmasından yirmi yıl sonra, hemen hemen her Java programcısı bunun bir hata olduğunu düşünür. Popüler modern çerçevelerde, tüm istisnaların %95'i denetlenmez. Java'yı neredeyse birebir kopyalayan C# dili, kontrol edilen istisnaları eklemedi .

Kontrol edilen ve kontrol edilmeyen istisnalar arasındaki temel fark nedir ?

Kontrol edilen istisnalara uygulanan ek gereksinimler vardır . Kabaca söylemek gerekirse bunlar:

Gereksinim 1

Bir yöntem kontrol edilen bir istisna atarsa , imzasında istisna türünü belirtmelidir . Bu şekilde, onu çağıran her yöntem, bu "anlamlı istisnanın" kendi içinde oluşabileceğinin farkındadır.

Anahtar kelimeden sonra yöntem parametrelerinden sonra işaretli istisnaları belirtin ( yanlışlıkla anahtar kelimeyi kullanmayın ). Şuna benzer:throwsthrow

type method (parameters) throws exception

Örnek:

işaretli istisna denetlenmeyen istisna
public void calculate(int n) throws Exception
{
   if (n == 0)
      throw new Exception("n is null!");
}
public void calculate(n)
{
   if (n == 0)
      throw new RuntimeException("n is null!");
}

Sağdaki örnekte, kodumuz denetlenmeyen bir istisna oluşturuyor; ek bir işlem gerekmiyor. Soldaki örnekte, yöntem kontrol edilen bir istisna atar, böylece throwsanahtar kelime, istisna türüyle birlikte yöntem imzasına eklenir.

Bir yöntem birden fazla kontrol edilen istisna atmayı bekliyorsa , bunların tümü throwsanahtar kelimeden sonra virgülle ayrılarak belirtilmelidir . Sıra önemli değil. Örnek:

public void calculate(int n) throws Exception, IOException
{
   if (n == 0)
      throw new Exception("n is null!");
   if (n == 1)
      throw new IOException("n is 1");
}

Gereksinim 2

İmzasında istisnaları kontrol eden bir yöntemi çağırırsanız , istisnaları attığı gerçeğini göz ardı edemezsiniz.

catchYa her biri için bloklar ekleyerek ya da bunları yönteminiz için bir throwsyan tümceye ekleyerek tüm bu tür istisnaları yakalamanız gerekir .

Sanki " Bu istisnalar o kadar önemli ki onları yakalamamız gerekiyor. Ve eğer onlarla nasıl başa çıkacağımızı bilmiyorsak, o zaman yöntemimizi çağırabilecek herkese bu tür istisnaların oluşabileceği bildirilmelidir.

Örnek:

İnsanların yaşadığı bir dünya yaratmak için bir yöntem yazdığımızı hayal edin. İlk kişi sayısı bağımsız değişken olarak iletilir. Bu nedenle, çok az kişi varsa istisnalar eklememiz gerekir.

Dünya Yaratmak Not
public void createWorld(int n) throws EmptyWorldException, LonelyWorldException
{
   if (n == 0)
      throw new EmptyWorldException("There are no people!");
   if (n == 1)
      throw new LonelyWorldException ("There aren't enough people!");
   System.out.println("A wonderful world was created. Population: " + n);
}
Yöntem potansiyel olarak iki kontrol edilen istisna atar:

  • EmptyWorldİstisna
  • LonelyWorldİstisna

Bu yöntem çağrısı 3 şekilde ele alınabilir:

1. Herhangi bir istisna yakalamayın

Bu genellikle, yöntem durumu düzgün bir şekilde nasıl ele alacağını bilmediğinde yapılır.

kod Not
public void createPopulatedWorld(int population)
throws EmptyWorldException, LonelyWorldException
{
   createWorld(population);
}
Çağıran yöntem istisnaları yakalamaz ve diğerlerini onlar hakkında bilgilendirmek zorundadır: onları kendi throwsyan tümcesine ekler.

2. İstisnalardan bazılarını yakalayın

Başa çıkabileceğimiz hataları hallederiz. Ama anlamadıklarımızı çağıran metoda atıyoruz. Bunu yapmak için, throws yan tümcesine adlarını eklememiz gerekir:

kod Not
public void createNonEmptyWorld(int population)
throws EmptyWorldException
{
   try
   {
      createWorld(population);
   }
   catch (LonelyWorldException e)
   {
      e.printStackTrace();
   }
}
Arayan yalnızca bir işaretli istisna yakalar — LonelyWorldException. throwsDiğer istisna, anahtar kelimeden sonra belirtilerek imzasına eklenmelidir.

3. Tüm istisnaları yakalayın

Yöntem, çağıran yönteme istisnalar atmazsa, çağıran yöntem her zaman her şeyin yolunda gittiğinden emin olur. Ve istisnai bir durumu düzeltmek için herhangi bir işlem yapamayacak.

kod Not
public void createAnyWorld(int population)
{
   try
   {
      createWorld(population);
   }
   catch (LonelyWorldException e)
   {
      e.printStackTrace();
   }
   catch (EmptyWorldException e)
   {
      e.printStackTrace();
   }
}
Tüm istisnalar bu yöntemde yakalanır. Arayan kişi, her şeyin yolunda gittiğinden emin olacaktır.


3. Sarma istisnaları

Kontrol edilen istisnalar teoride harika görünüyordu, ancak pratikte büyük bir hayal kırıklığı olduğu ortaya çıktı.

Diyelim ki projenizde çok popüler bir yönteminiz var. Programınızdaki yüzlerce yerden çağrılır. Ve buna yeni bir işaretli istisna eklemeye karar veriyorsunuz . Ve bu kontrol edilen istisna gerçekten önemli ve o kadar özel olabilir ki, main()yakalanırsa ne yapacağını yalnızca yöntem bilir.

Bu, süper popüler yönteminizi çağıran her yöntemin yan tümcesine işaretli istisnayı eklemeniz gerekeceğithrows anlamına gelir . throwsBu yöntemleri çağıran tüm yöntemlerin yan tümcesinde olduğu gibi . Ve bu yöntemleri çağıran yöntemlerden.

Sonuç olarak, throwsprojedeki yöntemlerin yarısının yan tümceleri yeni bir kontrol edilen istisna alır. Ve tabii ki projeniz testlerle kapsanıyor ve artık testler derlenmiyor. Ve şimdi, testlerinizde throws yan tümcelerini de düzenlemeniz gerekiyor.

Ve sonra tüm kodunuz (yüzlerce dosyadaki tüm değişiklikler) diğer programcılar tarafından gözden geçirilmelidir. Ve bu noktada kendimize neden projede bu kadar çok kanlı değişiklik yaptığımızı soruyoruz. Çalışma günleri ve başarısız testler - hepsi kontrol edilen bir istisna eklemek uğruna mı ?

Ve elbette, kalıtım ve yöntem geçersiz kılma ile ilgili sorunlar hala var. Kontrol edilen istisnalardan kaynaklanan sorunlar, faydadan çok daha büyüktür. Sonuç olarak, artık çok az insan onları seviyor ve çok az insan kullanıyor.

Ancak yine de bu kontrol edilen istisnaları içeren çok sayıda kod (standart Java kitaplık kodu dahil) vardır . Onlarla ne yapılmalı? Onları görmezden gelemeyiz ve onlarla nasıl başa çıkacağımızı bilmiyoruz.

Java programcıları, kontrol edilen istisnaları RuntimeException. Başka bir deyişle, kontrol edilen tüm istisnaları yakalayın ve ardından kontrol edilmeyen istisnalar oluşturun (örneğin, RuntimeException) ve bunların yerine onları atın. Bunu yapmak şuna benzer:

try
{
   // Code where a checked exception might occur
}
catch(Exception exp)
{
   throw new RuntimeException(exp);
}

Bu çok güzel bir çözüm değil, ama burada suçlu bir şey yok: istisna basitçe bir RuntimeException.

İstenirse, oradan kolayca alabilirsiniz. Örnek:

kod Not
try
{
   // Code where we wrap the checked exception
   // in a RuntimeException
}
catch(RuntimeException e)
{
   Throwable cause = e.getCause();
   if (cause instanceof Exception)
   {
      Exception exp = (Exception) cause;
      // Exception handling code goes here
   }
}







Nesnenin içinde saklanan istisnayı alın RuntimeException. Değişken cause, null

türünü belirleyebilir ve kontrol edilen bir istisna türüne dönüştürebilir.


4. Birden fazla istisna yakalama

Programcılar kodu kopyalamaktan gerçekten nefret ederler. Hatta buna karşılık gelen bir geliştirme ilkesi buldular: Kendini Tekrar Etme (DRY) . Ancak istisnaları ele alırken, bir bloğun ardından aynı koda sahip birkaç bloğun geldiği sık durumlar vardır .trycatch

catchVeya aynı koda sahip 3 blok ve diğer aynı koda sahip 2 blok daha olabilir catch. Bu, projeniz istisnaları sorumlu bir şekilde ele aldığında standart bir durumdur.

Sürüm 7'den başlayarak, Java dilinde tek bir blokta birden çok türde istisna belirtme yeteneği eklendi catch. Şuna benzer:

try
{
   // Code where an exception might occur
}
catch (ExceptionType1 | ExceptionType2 | ExceptionType3 name)
{
   // Exception handling code
}

catchDilediğiniz kadar bloğa sahip olabilirsiniz . Ancak, tek bir catchblok birbirini miras alan istisnaları belirleyemez. Başka bir deyişle, sınıf miras aldığı için catch ( Exception| RuntimeExceptione) yazamazsınız .RuntimeExceptionException



5. Özel istisnalar

Her zaman kendi istisna sınıfınızı oluşturabilirsiniz. Siz sadece sınıfı miras alan bir sınıf yaratırsınız RuntimeException. Bunun gibi bir şey görünecek:

class ClassName extends RuntimeException
{
}

Siz OOP, kalıtım, yapıcılar ve metot geçersiz kılmayı öğrenirken detayları tartışacağız.

Ancak, yalnızca bunun gibi basit bir sınıfınız olsa bile (tamamen kodsuz), yine de buna dayalı olarak istisnalar oluşturabilirsiniz:

kod Not
class Solution
{
   public static void main(String[] args)
   {
      throw new MyException();
   }
}

class MyException extends RuntimeException
{
}




İşaretlenmemiş bir MyException.

Java Multithreading arayışında , kendi özel istisnalarımızla çalışmayı derinlemesine inceleyeceğiz.