Ahmet Balaman LogoAhmet Balaman

Dart'ta Hata Yönetimi: Try-Catch ve Asenkron İşlemler

personAhmet Balaman
calendar_today
DartTry CatchAsyncAwaitFutureHata Yönetimi

Hata Yönetimi ve Asenkron Programlama

Bugün iki önemli konuyu öğrendim: Hata yönetimi (Try-Catch) ve asenkron işlemler (Async-Await). İkisi de gerçek uygulamalarda çok kritik konular.

Canlı Demo: Try-Catch ve Async-Await

Hata yönetimi ve asenkron programlamayı interaktif olarak öğrenin:

Try-Catch - Hataları Yakalamak

Programlarımız her zaman kusursuz çalışmıyor. Kullanıcı yanlış bir şey girebilir, internet bağlantısı kopabilir, dosya bulunamayabilir. İşte Try-Catch tam da bu durumlar için.

İlk Karşılaştığım Problem

Kullanıcıdan sayı istiyorum ama kullanıcı harf giriyor. Program çöküyor:

import 'dart:io';

void main() {
  print("Bir sayı girin:");
  String girdi = stdin.readLineSync()!;
  int sayi = int.parse(girdi); // Eğer harf girerse HATA!
  print("Girdiğiniz sayı: $sayi");
}

Kullanıcı "abc" yazarsa program patlar. Çözüm? Try-Catch!

Try-Catch ile Güvenli Hale Getirme

import 'dart:io';

void main() {
  print("Bir sayı girin:");
  
  try {
    String girdi = stdin.readLineSync()!;
    int sayi = int.parse(girdi);
    print("Girdiğiniz sayı: $sayi");
  } catch (e) {
    print("Hata! Lütfen geçerli bir sayı girin.");
    print("Hata detayı: $e");
  }
}

Şimdi kullanıcı ne yazarsa yazsın program çökmüyor. Hata olursa catch bloğu çalışıyor.

Sürekli Sayı İsteyen Program

Ben bunu bir adım ileri götürdüm. Kullanıcı doğru sayı girene kadar tekrar tekrar sor:

import 'dart:io';

void main() {
  int sayi;
  
  while (true) {
    try {
      print("Bir sayı girin:");
      sayi = int.parse(stdin.readLineSync()!);
      break; // Başarılıysa döngüden çık
    } catch (e) {
      print("Lütfen geçerli bir sayı giriniz!");
    }
  }
  
  print("Tebrikler! Girdiğiniz sayı: $sayi");
}

Bu kod kullanıcı doğru sayı girene kadar devam ediyor. Çok kullanışlı!

Finally Bloğu

Bazen hata olsa da olmasa da çalışmasını istediğiniz kod olabilir:

try {
  // Riskli işlem
  int sonuc = 10 ~/ 0; // Sıfıra bölme hatası
} catch (e) {
  print("Hata oluştu: $e");
} finally {
  print("Bu her zaman çalışır");
}

finally bloğu ne olursa olsun çalışır. Genelde dosya kapatma, bağlantı kesme gibi işler için kullanılır.

Asenkron İşlemler - Async ve Await

Asenkron programlama konusu beni başta çok zorladı. Ama şöyle anladım: Bazı işlemler zaman alıyor (internet'ten veri çekme, dosya okuma vb.) ve bu işlemleri beklerken programın donmasını istemiyoruz.

Senkron vs Asenkron

Senkron (Normal):

İşlem 1 başla → İşlem 1 bitir → İşlem 2 başla → İşlem 2 bitir

Asenkron:

İşlem 1 başla → İşlem 2 başla → İşlem 1 bitir → İşlem 2 bitir

Yani bir şey beklerken diğer şeyleri de yapabiliyorsunuz.

Future, Async, Await - Üçlü Kavram

Bu üç kelime hep birlikte kullanılıyor:

  • Future: Gelecekte tamamlanacak bir işlem
  • async: Fonksiyonun asenkron olduğunu belirtir
  • await: İşlem bitene kadar bekle

İlk Async Örneğim

Future<void> main() async {
  print("Veri bekleniyor...");
  
  String veri = await veritabanindanVeriAl();
  
  print("Veri alındı: $veri");
}

Future<String> veritabanindanVeriAl() async {
  // 3 saniye bekle (veritabanını simüle ediyoruz)
  await Future.delayed(Duration(seconds: 3));
  return "Kullanıcı verileri";
}

Bu kod şöyle çalışıyor:

  1. "Veri bekleniyor..." yazdır
  2. veritabanindanVeriAl() fonksiyonunu çağır ve bekle (3 saniye)
  3. Veri gelince "Veri alındı: ..." yazdır

Await Kullanmazsak Ne Olur?

Future<void> main() async {
  print("Veri bekleniyor...");
  
  String veri = veritabanindanVeriAl(); // HATA!
  
  print("Veri alındı: $veri");
}

Bu çalışmaz çünkü veritabanindanVeriAl() hemen değer döndürmüyor, bir Future döndürüyor. await kullanmadan Future'ı String'e çeviremezsiniz.

Daha Gerçekçi Bir Örnek

Future<void> main() async {
  print("1. Veri bekleniyor...");
  var veri = await veritabanindanVeriAl();
  print("2. Veri alınıyor: $veri");
}

Future<String> veritabanindanVeriAl() async {
  // Her saniye yükleme durumunu göster
  for (var i = 1; i <= 5; i++) {
    await Future.delayed(
      Duration(seconds: 1),
      () => print("Yükleniyor... %${i * 20}")
    );
  }
  
  return "Veritabanı kümesi";
}

Çıktı:

1. Veri bekleniyor...
Yükleniyor... %20
Yükleniyor... %40
Yükleniyor... %60
Yükleniyor... %80
Yükleniyor... %100
2. Veri alınıyor: Veritabanı kümesi

Try-Catch ile Async Kullanımı

Asenkron işlemlerde de hata olabilir (internet kesildi, timeout vb.):

Future<void> main() async {
  try {
    print("API'den veri çekiliyor...");
    String veri = await apidenVeriCek();
    print("Veri: $veri");
  } catch (e) {
    print("Hata oluştu: $e");
    print("İnternet bağlantınızı kontrol edin");
  }
}

Future<String> apidenVeriCek() async {
  await Future.delayed(Duration(seconds: 2));
  
  // Hata simülasyonu
  throw Exception("Sunucuya bağlanılamadı!");
  
  // return "API Verisi"; // Normalde bu çalışırdı
}

Flutter'da Kullanım

Flutter'da sürekli async kullanıyoruz. Çünkü:

  • API'lerden veri çekiyoruz
  • Veritabanı işlemleri yapıyoruz
  • Dosya okuyoruz
  • Kullanıcı girişi bekliyoruz

Flutter'da API Çağrısı Örneği

class VeriSayfasi extends StatefulWidget {
  @override
  _VeriSayfasiState createState() => _VeriSayfasiState();
}

class _VeriSayfasiState extends State<VeriSayfasi> {
  String veri = "Yükleniyor...";
  
  @override
  void initState() {
    super.initState();
    verileriYukle();
  }
  
  Future<void> verileriYukle() async {
    try {
      // API çağrısı yap (örnek)
      await Future.delayed(Duration(seconds: 2));
      
      setState(() {
        veri = "Veriler başarıyla yüklendi!";
      });
    } catch (e) {
      setState(() {
        veri = "Hata: $e";
      });
    }
  }
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Text(veri),
      ),
    );
  }
}

FutureBuilder Widget'ı

Flutter'da Future'ları göstermek için özel bir widget var:

FutureBuilder<String>(
  future: veritabanindanVeriAl(),
  builder: (context, snapshot) {
    if (snapshot.connectionState == ConnectionState.waiting) {
      return CircularProgressIndicator(); // Loading göster
    }
    
    if (snapshot.hasError) {
      return Text("Hata: ${snapshot.error}"); // Hata göster
    }
    
    return Text("Veri: ${snapshot.data}"); // Veri göster
  },
)

Bu widget otomatik olarak loading, hata ve başarı durumlarını yönetiyor. Çok kullanışlı!

Async-Await Kullanırken Dikkat Edilecekler

Öğrendiğim bazı önemli kurallar:

  1. await sadece async fonksiyonlarda kullanılır
// YANLIŞ
void fonksiyon() {
  await birSey(); // HATA!
}

// DOĞRU
Future<void> fonksiyon() async {
  await birSey(); // Tamam
}
  1. async fonksiyon mutlaka Future döndürür
Future<String> veriAl() async {
  return "Veri";
}
  1. Birden fazla await kullanabilirsiniz
Future<void> tumVerileriAl() async {
  String veri1 = await api1denVeriAl();
  String veri2 = await api2denVeriAl();
  String veri3 = await api3denVeriAl();
  
  print("$veri1, $veri2, $veri3");
}
  1. Paralel çalıştırmak için Future.wait
Future<void> parallelVeriler() async {
  // Üçü aynı anda başlar
  var sonuclar = await Future.wait([
    api1denVeriAl(),
    api2denVeriAl(),
    api3denVeriAl(),
  ]);
  
  print(sonuclar); // [veri1, veri2, veri3]
}

Bugün Ne Öğrendim?

  • Try-Catch ile hataları güvenli şekilde yakalıyoruz
  • Finally bloğu her durumda çalışır
  • Async-Await ile asenkron işlemleri yönetiyoruz
  • Future gelecekte tamamlanacak işlemler için
  • Flutter'da FutureBuilder çok işe yarıyor

Yarın Flutter'ın UI yapısına (Widget ağacı, Row, Column, Stack) bakacağım. Artık kod tarafını iyi öğrendim, şimdi arayüz zamanı!


Sorularınız mı var?

Kodlamaya devam! 🚀