1. İstisnalar API-nin bir hissəsi kimi
Niyə istisnalar metodun “kontrakt”ının bir hissəsidir?
Metod yazanda siz yalnız parametrləri və qaytarılan dəyəri deyil, həm də onun hansı istisnaları ata biləcəyini müəyyən edirsiniz. Bu, metodunuz ilə onu istifadə edənlər arasında “kontrakt”ın bir hissəsidir. Əgər metod istisna ata bilirsə, onu çağıranların hamısı bunu bilməlidir — xətanı düzgün emal etmək üçün (və ya heç olmasa, proqram qəfil xəta ilə dayandıqda təəccüblənməmək üçün).
Nümunə:
public void readFile(String filename) throws IOException {
// ... faylın oxunması
}
Burada metodun IOException ata biləcəyi açıq şəkildə göstərilib. Bu, metodun istifadəçisinə siqnaldır: “Fayl oxuma xətasını emal etməyə hazır ol!”
İstisnaların sənədləşdirilməsi: Javadoc-da @throws anotasiyası
Başqa tərtibatçıların metodunuzun hansı istisnaları ata biləcəyini başa düşməsi üçün Javadoc-da @throws (və ya @exception) anotasiyasından istifadə edin.
Nümunə:
/**
* Faylın məzmununu oxuyur.
*
* @param filename fayl adı
* @return faylın məzmunu sətir kimi
* @throws IOException fayl oxunarkən xəta baş verərsə
*/
public String readFile(String filename) throws IOException {
// ...
}
Bu nə üçün lazımdır?
- Başqa tərtibatçıların hansı xətaları emal etməli olduqlarını anlamağa kömək edir.
- IDE-lər və sənəd generatorları (məsələn, Javadoc) bu istisnaları birbaşa ipucu pəncərələrində göstərir.
- Kodun etibarlılığını və proqnozlaşdırıla bilməsini artırır.
API-də checked və unchecked istisnalar
Checked istisnalar (Exception-dan miras alanlar, lakin RuntimeException deyil) — metod kontraktının bir hissəsidir. Onları ya emal etməli, ya da açıq şəkildə yuxarı ötürməlisiniz (throws).
Unchecked istisnalar (RuntimeException və törəmələri) — adətən proqram xətalarına işarə edir (məsələn, NullPointerException, IllegalArgumentException). Onları siqnaturada göstərmək məcburi deyil, lakin metodunuz belə bir səhv ata bilərsə (məsələn, yanlış arqumentlərdə), bunu da Javadoc-da təsvir etmək lazımdır.
Nümunə:
/**
* a-nı b-yə bölür.
* @param a bölünən
* @param b bölən
* @return bölmə nəticəsi
* @throws IllegalArgumentException əgər b == 0-dırsa
*/
public int divide(int a, int b) {
if (b == 0) throw new IllegalArgumentException("Bölən sıfır ola bilməz");
return a / b;
}
İstisnalar və API dizaynı
- Metodunuzun istifadəçisi barədə düşünün: o hansı xətaları emal edə bilər və etməlidir? Hansılar bug-dur, hansılar isə “işçi” situasiyalardır?
- Checked istisnalardan həddindən artıq istifadə etməyin: əgər səhv bug-dursa (məsələn, yalnış arqument), unchecked istisna atmaq daha yaxşıdır.
- “Yuxarıya” ötürülə bilən bütün istisnaları sənədləşdirin.
2. try-with-resources konstruksiyası
Problem: resursları necə təhlükəsiz bağlamaq olar?
Bir çox tapşırıqda istifadədən sonra mütləq bağlanmalı olan resurslarla çalışmaq lazım olur: fayllar, şəbəkə bağlantıları, verilənlər bazaları və s. Resursu bağlamağı unutduqda — yaddaş sızması, faylın bloklanması və digər xoşagəlməz hallar baş verə bilər.
Əvvəllər:
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader("data.txt"));
String line = reader.readLine();
// ...
} catch (IOException e) {
// xəta emalı
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
// bağlama zamanı xəta emalı
}
}
}
Çox kod, asanlıqla səhv etmək olar, resursu bağlamağı unutmaq mümkündür.
Həll: try-with-resources
Java 7-dən etibarən try-with-resources konstruksiyası peyda oldu; o, blok daxilində istisna baş versə belə bütün resursları avtomatik bağlayır.
Sintaksis:
try (ResourceType resource = new ResourceType(...)) {
// resursla iş
} catch (ExceptionType e) {
// xəta emalı
}
Nümunə:
try (BufferedReader reader = new BufferedReader(new FileReader("data.txt"))) {
String line = reader.readLine();
System.out.println(line);
} catch (IOException e) {
System.out.println("Faylı oxuyarkən xəta: " + e.getMessage());
}
// reader.close() avtomatik çağırılacaq!
Bu necə işləyir?
- try-dan sonra mötərizələrdə bağlanmalı resurslar elan olunur.
- try blokundan çıxıldıqdan sonra (istisna baş versə belə!) hər bir resurs üçün close() metodu çağırılır.
- Bu yalnız AutoCloseable (və ya onun əcdadı Closeable) interfeysini reallaşdıran resurslar üçün işləyir.
AutoCloseable interfeysi:
public interface AutoCloseable {
void close() throws Exception;
}
Java-nın bütün standart resursları (fayllar, axınlar, DB bağlantıları) bu interfeysi reallaşdırır.
Bir neçə resursu elan etmək olar
try (
BufferedReader reader = new BufferedReader(new FileReader("input.txt"));
BufferedWriter writer = new BufferedWriter(new FileWriter("output.txt"))
) {
String line;
while ((line = reader.readLine()) != null) {
writer.write(line);
writer.newLine();
}
}
Hər iki resurs istisna baş versə belə avtomatik bağlanacaq.
try-with-resources-un üstünlükləri
- Təhlükəsizlik: resurslar həmişə bağlanır, hətta xətalarda da.
- Qısa: daha az kod, səhv etmək üçün daha az şans.
- Oxunaqlılıq: hansı resursların istifadə olunduğu və nə vaxt bağlandığı dərhal görünür.
3. Praktika: try-with-resources ilə təhlükəsiz kod yazırıq
Nümunə: faylın oxunması
public static void printFirstLine(String filename) {
try (BufferedReader reader = new BufferedReader(new FileReader(filename))) {
String line = reader.readLine();
System.out.println("Birinci sətir: " + line);
} catch (IOException e) {
System.out.println("Xəta: " + e.getMessage());
}
}
Nümunə: fayla yazma
public static void writeToFile(String filename, String text) {
try (BufferedWriter writer = new BufferedWriter(new FileWriter(filename))) {
writer.write(text);
} catch (IOException e) {
System.out.println("Yazma zamanı xəta: " + e.getMessage());
}
}
Nümunə: öz resursunuz
Əgər bağlanmalı olan öz sinfinizi yazırsınızsa, sadəcə AutoCloseable-ı reallaşdırın:
public class MyResource implements AutoCloseable {
@Override
public void close() {
System.out.println("Resurs bağlandı!");
}
}
İndi onu try-with-resources daxilində istifadə etmək olar:
try (MyResource res = new MyResource()) {
// resursla iş
}
4. Tipik səhvlər və ən yaxşı təcrübələr
Xəta №1: resursu bağlamağı unutmaq (try-with-resources olmadan).
Əgər try-with-resources-dən istifadə etməsəniz, faylı və ya axını bağlamağı asanlıqla unuda bilərsiniz — bu, resurs sızmalarına gətirir.
Xəta №2: try-with-resources-u AutoCloseable reallaşdırmayan obyektlə istifadə etməyə cəhd.
Sinifiniz bu interfeysi reallaşdırmırsa, kompilyator onu try-with-resources-da istifadə etməyə imkan verməyəcək.
Xəta №3: API-də istisnaları sənədləşdirmirsiniz.
Metodunuz istisna ata bilirsə — bunu mütləq siqnaturada (throws) və Javadoc-da (@throws) göstərin. Bu, başqalarının kodunuzu düzgün istifadə etməsinə kömək edəcək.
Xəta №4: konkret xətalar əvəzinə Exception tutursunuz.
Yalnız həqiqətən gözlədiyiniz və emal etməyi bacardığınız istisnaları tutmaq daha yaxşıdır.
GO TO FULL VERSION