BAB 7: Exception Handling

BAB 7: Exception Handling

7.1 Try-Catch

Pengenalan Exception Handling

Exception adalah kejadian yang tidak diinginkan yang dapat mengganggu alur normal program. Exception handling memungkinkan kita menangani error dengan cara yang elegan.

Struktur Dasar Try-Catch

void main() {
  try {
    // Kode yang mungkin menghasilkan exception
    int result = 12 ~/ 0;  // Pembagian dengan nol
    print(result);
  } catch (e) {
    print('Terjadi error: $e');
  }
}

Menangkap Multiple Exception

void main() {
  try {
    // Kode yang mungkin menghasilkan exception
    String? input = null;
    print(input!.length);  // Null pointer exception
    
  } on FormatException {
    print('Format tidak valid!');
    
  } on NoSuchMethodError {
    print('Method tidak ditemukan!');
    
  } catch (e) {
    print('Error lain: $e');
  }
}

Stack Trace dalam Exception

void main() {
  try {
    List<int> numbers = [1, 2, 3];
    print(numbers[10]);  // Index out of range
    
  } catch (e, stackTrace) {
    print('Error: $e');
    print('Stack trace: $stackTrace');
  }
}

7.2 Finally

Penggunaan Finally

Finally block akan selalu dijalankan, baik terjadi exception atau tidak.

void main() {
  var file;
  
  try {
    // Simulasi membuka file
    file = openFile();
    // Proses file
    processFile(file);
    
  } catch (e) {
    print('Error saat memproses file: $e');
    
  } finally {
    // Selalu tutup file, terlepas dari berhasil atau error
    if (file != null) {
      file.close();
    }
    print('Pembersihan resources selesai');
  }
}

Contoh Penggunaan Praktis

class DatabaseConnection {
  bool isConnected = false;
  
  void connect() {
    // Simulasi koneksi database
    print('Connecting to database...');
    isConnected = true;
  }
  
  void disconnect() {
    print('Disconnecting from database...');
    isConnected = false;
  }
  
  void query(String sql) {
    if (!isConnected) {
      throw Exception('Database tidak terkoneksi!');
    }
    print('Executing query: $sql');
  }
}

void main() {
  var db = DatabaseConnection();
  
  try {
    db.connect();
    db.query('SELECT * FROM users');
    
  } catch (e) {
    print('Database error: $e');
    
  } finally {
    db.disconnect();  // Selalu disconnect, sukses atau gagal
  }
}

7.3 Custom Exception

Membuat Custom Exception

class InsufficientBalanceException implements Exception {
  final double balance;
  final double withdrawAmount;
  
  InsufficientBalanceException(this.balance, this.withdrawAmount);
  
  @override
  String toString() {
    return 'Saldo tidak mencukupi! Saldo: $balance, Jumlah penarikan: $withdrawAmount';
  }
}

class BankAccount {
  double _balance = 0;
  
  void deposit(double amount) {
    if (amount <= 0) {
      throw ArgumentError('Jumlah deposit harus positif');
    }
    _balance += amount;
  }
  
  void withdraw(double amount) {
    if (amount <= 0) {
      throw ArgumentError('Jumlah penarikan harus positif');
    }
    if (amount > _balance) {
      throw InsufficientBalanceException(_balance, amount);
    }
    _balance -= amount;
  }
}

Menggunakan Custom Exception

void main() {
  var account = BankAccount();
  
  try {
    account.deposit(1000);
    print('Deposit berhasil');
    
    account.withdraw(1500);
    print('Penarikan berhasil');
    
  } on InsufficientBalanceException catch (e) {
    print('Error: $e');
    
  } on ArgumentError catch (e) {
    print('Error argument: $e');
    
  } catch (e) {
    print('Error lain: $e');
  }
}

7.4 Praktek: Program Validasi Form

class ValidationException implements Exception {
  final String field;
  final String message;
  
  ValidationException(this.field, this.message);
  
  @override
  String toString() => '$field: $message';
}

class EmailValidator {
  static void validate(String email) {
    if (email.isEmpty) {
      throw ValidationException('Email', 'Email tidak boleh kosong');
    }
    
    final emailRegex = RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$');
    if (!emailRegex.hasMatch(email)) {
      throw ValidationException('Email', 'Format email tidak valid');
    }
  }
}

class PasswordValidator {
  static void validate(String password) {
    if (password.isEmpty) {
      throw ValidationException('Password', 'Password tidak boleh kosong');
    }
    
    if (password.length < 8) {
      throw ValidationException(
        'Password', 
        'Password harus minimal 8 karakter'
      );
    }
    
    if (!password.contains(RegExp(r'[A-Z]'))) {
      throw ValidationException(
        'Password', 
        'Password harus mengandung huruf kapital'
      );
    }
    
    if (!password.contains(RegExp(r'[0-9]'))) {
      throw ValidationException(
        'Password', 
        'Password harus mengandung angka'
      );
    }
  }
}

class UserRegistrationForm {
  String? name;
  String? email;
  String? password;
  String? phoneNumber;
  
  void validateAll() {
    // Validasi nama
    if (name == null || name!.isEmpty) {
      throw ValidationException('Name', 'Nama tidak boleh kosong');
    }
    
    // Validasi email
    if (email != null) {
      EmailValidator.validate(email!);
    } else {
      throw ValidationException('Email', 'Email tidak boleh kosong');
    }
    
    // Validasi password
    if (password != null) {
      PasswordValidator.validate(password!);
    } else {
      throw ValidationException('Password', 'Password tidak boleh kosong');
    }
    
    // Validasi nomor telepon
    if (phoneNumber == null || phoneNumber!.isEmpty) {
      throw ValidationException('Phone', 'Nomor telepon tidak boleh kosong');
    }
    
    final phoneRegex = RegExp(r'^\d{10,12}$');
    if (!phoneRegex.hasMatch(phoneNumber!)) {
      throw ValidationException(
        'Phone', 
        'Nomor telepon harus 10-12 digit angka'
      );
    }
  }
}

void main() {
  var form = UserRegistrationForm();
  
  // Simulasi input dari user
  print('=== FORM REGISTRASI USER ===\n');
  
  try {
    // Input nama
    print('Masukkan nama:');
    form.name = stdin.readLineSync();
    
    // Input email
    print('Masukkan email:');
    form.email = stdin.readLineSync();
    
    // Input password
    print('Masukkan password:');
    form.password = stdin.readLineSync();
    
    // Input nomor telepon
    print('Masukkan nomor telepon:');
    form.phoneNumber = stdin.readLineSync();
    
    // Validasi semua input
    form.validateAll();
    
    // Jika sampai di sini berarti validasi sukses
    print('\n✓ Registrasi berhasil!');
    
  } on ValidationException catch (e) {
    print('\n✗ Validasi gagal!');
    print('Error: $e');
    
  } catch (e) {
    print('\n✗ Terjadi kesalahan!');
    print('Error: $e');
    
  } finally {
    print('\nProses registrasi selesai');
  }
}

Latihan Mandiri

  1. Tambahkan validasi untuk:

    • Username (alfanumerik, tanpa spasi)

    • Tanggal lahir (format dan umur minimal)

    • Konfirmasi password

  2. Implementasikan sistem login dengan validasi kredensial

  3. Buat form pendaftaran kursus dengan validasi:

    • Kapasitas kelas

    • Jadwal yang tersedia

    • Persyaratan prerequisite

Tips Exception Handling

  1. Gunakan exception handling untuk error yang bisa dipulihkan

  2. Buat custom exception yang spesifik untuk domain aplikasi

  3. Jangan tangkap exception terlalu umum

  4. Selalu bersihkan resources di block finally

  5. Berikan pesan error yang informatif

  6. Dokumentasikan exception yang mungkin terjadi

  7. Log error untuk debugging

  8. Validasi input sebelum diproses

Last updated