Halo! Setelah bersama-sama mempelajari dasar-dasar pemrograman C# di “Seri Belajar Dasar Pemrograman Bahasa C#“, kini saatnya kita mempelajari materi yang lebih advance, yaitu penanganan eksepsi terstruktur di C#.
Materi ini akan sangat panjang apabila ditulis menjadi satu materi saja. Supaya Anda bisa mempelajari materi ini sedikit demi sedikit, materi kali ini akan saya bagi menjadi 5 bagian, yaitu:
- Dasar penanganan eksepsi. (artikel ini)
- Konfigurasi status dari sebuah eksepsi.
- Membuat definisi eksepsi kita sendiri (custom exception).
- Memproses beberapa eksepsi.
- Memfilter Ekspesi.
Materi ini akan kita mulai dengan mempelajari dasar-dasar penanganan eksepsi di C#.
Apa itu Bug, Error, dan Eksepsi?
Tidak ada orang yang sempurna. Begitu pula kita sebagai programmer, sebanyak apapun pengalaman seorang programmer, pasti tidak luput dari membuat sebuah kesalahan.
Oleh karena itu, software terbaik yang sudah sukses beredar di pasaran pun tidak lepas dari masalah. Permasalahan bisa disebabkan oleh bug yang terdapat di kode program, atau juga bisa timbul karena pengguna memasukkan nilai yang tidak sesuai dengan format yang diminta.
Terlepas dari apa penyebab permasalahan pada sebuah aplikasi, permasalahan seperti ini biasanya membuat sebuah aplikasi berhenti bekerja atau bekerja tidak semestinya.
Setidaknya ada tiga buah jenis permasalahan umum yang menyebabkan anomali (eror) pada sebuah aplikasi, yaitu:
- Bug: Ini adalah eror yang disebabkan oleh kelalaian seorang programmer. Contoh sederhananya, kita menulis kode program yang mencoba mengakses index sebuah array di luar index dari array tersebut.
- User error: Ini biasanya disebabkan oleh seseorang yang menggunakan sebuah aplikasi. Contoh sederhananya, seorang pengguna memasukkan sebuah teks ke kolom yang seharusnya hanya bisa menerima angka. Apabila kita tidak mengantisipasi hal ini, aplikasi kita akan mengalami eror.
- Exception: Ini adalah eror pada saat runtime (saat sebuah aplikasi dijalankan) yang disebabkan oleh sesuatu yang tidak terduga. Misalnya, eror yang disebabkan karena kode program kita mencoba mengakses sebuah direktori atau file yang tidak ada.
Untuk mengatasi anomali yang bisa terjadi pada sebuah aplikasi, kita perlu menangani setiap kemungkinan yang bisa menyebabkan aplikasi kita berhenti beroperasi. Penanganan eksepsi terstruktur atau structured exception handling merupakan sebuah teknik untuk mengantisipasi setiap kemungkinan eror yang bisa terjadi.
Memicu Terjadinya Eksepsi
Sebelum mempelajari bagaimana menangani sebuah eksepsi, kita akan terlebih dahulu menulis kode program yang berpotensi memicu terjadinya eksepsi.
Katakanlah kita menulis kode program seperti di bawah ini.
static void Main(string[] args)
{
int result = Division(20, 0);
System.Console.WriteLine($"Hasil: {result}");
}
static int Division(int numerator, int denominator)
{
return numerator / denominator;
}
Kira-kira, apa yang akan terjadi? Apakah Anda bisa menemukan masalah pada kode program di atas?
Di sini, melakukan pembagian dengan angka 0 sepertinya akan menjadi masalah. Tentu saja apabila kode program di atas kita jalankan, kita akan menemui sebuah eksepsi seperti di bawah ini.
Unhandled exception. System.DivideByZeroException: Attempted to divide by zero.
at Modul17.PenangananEksepsi.Program.Division(Int32 numerator, Int32 denominator) in C:\Users\prabu\OneDrive\Documents\VSCode\Modul Kursus\01_Fundamental\Modul\Modul17.PenangananEksepsi\Program.cs:line 17
at Modul17.PenangananEksepsi.Program.Main(String[] args) in C:\Users\prabu\OneDrive\Documents\VSCode\Modul Kursus\01_Fundamental\Modul\Modul17.PenangananEksepsi\Program.cs:line 10
Seperti yang bisa kita lihat, kita mendapatkan DivideByZeroException
karena mencoba membagi suatu angka dengan angka 0 (Attempted to divide by zero).
Di baris selanjutnya, kita mendapatkan informasi mengenai di mana eksepsi ini terjadi, yaitu di baris ke-17 pada method Division()
. Karena kita memanggil method Division()
dari dalam method Main()
di baris ke-10, maka kita juga akan mendapatkan informasi mengenai hal tersebut. Informasi ini disebut dengan stack trace.
Catatan
posisi baris yang saya dapatkan bisa saja berbeda dengan posisi baris yang Anda dapatkan.
Contoh Sederhana Penanganan Eksepsi Terstruktur Di C#
Untuk menangani eksepsi, C# menyediakan beberapa kata kunci seperti try
, catch
, throw
, finally
dan when
. Sementara ini, kita hanya akan menggunakan kata kunci try
dan catch
saja.
Aplikasi yang kita buat sebelumnya akan langsung mengalami crash (berhenti beroperasi) tidak lama setelah dieksekusi. Lalu bagaimana mencegah aplikasi kita mengalami hal ini?
Kasus sebelumnya adalah contoh di mana sebuah eksepsi tidak tertangani dengan baik. Aplikasi kita akan mengalami crash dan berhenti beroperasi, tentunya ini akan menjadi pengalaman yang buruk bagi pengguna aplikasi kita.
Oleh karena itu, sebisa mungkin kita mengidentifikasi kode program mana yang sekiranya berpotensi memicu eksepsi.
Jika kita kembali memperhatikan kode program di atas, bagian kode program untuk melakukan operasi pembagian sepertinya bisa memicu eksepsi apabila pengguna memasukkan nilai 0 sebagai denominator.
Untuk mengatasinya, kita bisa menggunakan blok try
–catch
seperti kode program di bawah ini.
static int Division(int numerator, int denominator)
{
try
{
return numerator / denominator;
}
catch (Exception ex)
{
System.Console.WriteLine(ex.Message);
System.Console.WriteLine(ex.StackTrace);
}
return 0;
}
Kode program di dalam blok try
di atas adalah operasi pembagian yang ingin kita “coba” jalankan. Jika tidak terjadi eksepsi, hasil operasi pembagiannya akan dikembalikan sebagai hasil dari operasi method Division()
.
Namun, jika operasi pembagian tersebut memicu sebuah eksepsi, maka eksepsi tersebut akan “ditangkap” oleh blok catch
. Di dalam blok catch
, kita menampilkan pesan eksepsi dan informasi stack trace ke layar console. Setelah itu, program akan dilanjutkan dengan mengembalikan nilai 0.
Apabila kode program di atas dijalankan tanpa mengubah kode program di dalam method Main()
, kita akan mendapatkan keluaran seperti di bawah ini.
Attempted to divide by zero.
at Modul17.PenangananEksepsi.Program.Division(Int32 numerator, Int32 denominator) in C:\Users\prabu\OneDrive\Documents\VSCode\Modul Kursus\01_Fundamental\Modul\Modul17.PenangananEksepsi\Program.cs:line 39
Hasil: 0
Mendapatkan keluaran “Hasil: 0” membuktikan bahwa method Division()
melanjutkan eksekusi setelah berhasil menangkap eksepsi yang terjadi. Ingat bahwa method Division()
akan mengembalikan nilai 0 apabila tidak berhasil melakukan operasi pembagian. Selain itu, kita juga tidak mendapatkan pesan “Unhandled exception“.
Akhirnya kita berhasil menangani eksepsi!
Tapi…
Keluaran seperti di atas bukan merupakan keluaran yang selayaknya kita berikan kepada pengguna aplikasi kita.
Apakah 20 dibagi 0 sama dengan 0? Tentunya bukan. Jadi keluaran “Hasil = 0” tentunya tidak tepat.
Lalu jika kita perhatikan stack trace yang ditampilkan, kita hanya memperoleh satu layer stack trace saja, yaitu stack trace pada class Program
method Division()
baris ke-39.
Apakah ini juga bermasalah? Bisa jadi.
Menangani Eksepsi Dengan Tepat
Katakanlah sekarang kita mendapatkan sebuah class seperti di bawah ini.
namespace ExceptionHandling
{
public class Arithmetic
{
public int GetResult(int x, int y)
{
return Division(x, y);
}
private int Division(int numerator, int denominator)
{
try
{
return numerator / denominator;
}
catch (System.Exception ex)
{
System.Console.WriteLine(ex.Message);
System.Console.WriteLine(ex.StackTrace);
}
return 0;
}
}
}
Lalu class tersebut kita konsumsi dari method Main()
seperti di bawah ini.
static void Main(string[] args)
{
Arithmetic obj = new Arithmetic();
int result = obj.GetResult(20, 0);
Console.WriteLine($"Hasil: {result}");
}
Apabila kita jalankan, kita akan mendapat keluaran seperti di bawah ini.
Attempted to divide by zero.
at Modul17.PenangananEksepsi.Arithmetic.Division(Int32 numerator, Int32 denominator) in C:\Users\prabu\OneDrive\Documents\VSCode\Modul Kursus\01_Fundamental\Modul\Modul17.PenangananEksepsi\Arithmetic.cs:line 14
Hasil: 0
Satu asumsi lagi, katakalah kita tidak tahu menahu tentang mehod Division()
. Kita sama sekali tidak pernah memanggil method tersebut. secara langsung Kita juga tidak tahu method mana yang memanggil method Division()
. Informasi pada stack trace hanya mengatakan bahwa terjadi eksepsi pada method Division()
. Itu saja.
Lagi-lagi, “Hasil = 0” bukanlah keluaran yang tepat.
Lalu, bagiamana cara menangani eksepsi dengan lebih tepat?
Ada satu aturan praktis yang selalu bisa kita ikuti: Sebisa mungkin tangani eksepsi di layer paling atas. Untuk aplikasi console, tangani eksepsi di method Main()
. Untuk aplikasi berbasis User Interface (UI), tangani eksepsi di layer UI.
Karena aplikasi yang kita buat adalah aplikasi console, maka sebisa mungkin kita mengidentifikasi kode program di dalam method Main()
yang sekiranya berpotensi memicu eksepsi.
static void Main(string[] args)
{
try
{
Arithmetic obj = new Arithmetic();
int result = obj.GetResult(20, 0);
Console.WriteLine($"Hasil: {result}");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.WriteLine(ex.StackTrace);
}
}
Dengan begitu, kita bisa menghilangkan penanganan eksepsi di method Division()
pada class Arithmetic
.
namespace Modul17.PenangananEksepsi
{
public class Arithmetic
{
public int GetResult(int x, int y)
{
return Division(x, y);
}
private int Division(int numerator, int denominator)
{
return numerator / denominator;
}
}
}
Kali ini kita akan mendapatkan keluaran seperti di bawah ini.
Attempted to divide by zero.
at Modul17.PenangananEksepsi.Arithmetic.Division(Int32 numerator, Int32 denominator) in C:\Users\prabu\OneDrive\Documents\VSCode\Modul Kursus\01_Fundamental\Modul\Modul17.PenangananEksepsi\Arithmetic.cs:line 23
at Modul17.PenangananEksepsi.Arithmetic.GetResult(Int32 x, Int32 y) in C:\Users\prabu\OneDrive\Documents\VSCode\Modul Kursus\01_Fundamental\Modul\Modul17.PenangananEksepsi\Arithmetic.cs:line 7
at Modul17.PenangananEksepsi.Program.Main(String[] args) in C:\Users\prabu\OneDrive\Documents\VSCode\Modul Kursus\01_Fundamental\Modul\Modul17.PenangananEksepsi\Program.cs:line 13
Dari stack trace di atas, kita mendapatkan informasi bahwa telah terjadi eksepsi di method Division()
pada class Arithmetic
yang dipanggil oleh method GetResult()
pada class Arithmetic
, di mana method GetResult()
ini dipanggil dari method Main()
pada class Program
. Dari sini kita bisa melihat rantai panggilan (call chain) ke method Division()
.
Dengan begitu, kita bisa menginvestigasi operasi pada method mana yang memicu terjadinya eksepsi di method Division()
pada class Arithmetic
. Untuk kasus kita, pemanggilan method GetResult()
di Main()
sepertinya bermasalah karena kita memberikan angka 0 sebagai salah satu parameternya.
Tentu saja, program kita kali ini merupakan program yang sangat sederhana. Namun, seiring dengan meningkatnya kompleksitas pada program kita, informasi pada stack trace seperti di atas sangat berguna pada saat menginvestigasi sebuah anomali.
Terakhir, perhatikan bahwa kali ini kita juga tidak mendapatkan keluaran “Hasil = 0” karena kontrol program melompat ke blok catch segera setelah terjadi eksepsi pada pemanggilan obj.GetResult(20, 0)
. Dengan demikian, baris kode program Console.WriteLine($"Hasil: {result}");
tidak sempat dijalankan. Karena pembagian oleh angka 0 menghasilkan eror, maka selayaknya aplikasi kita tidak menghasilkan nilai apapun.
Penutup
Pada materi tentang penanganan eksepsi terstruktur di C# ini, kita telah mempelajari apa itu yang disebut dengan bug, error, dan exception. Selain itu, kita juga telah mempelajari bagaimana menangani sebuah eksepsi. Tidak hanya sekedar bisa menangani sebuah eksepsi saja, namun kita juga telah mempelajari bagaimana menangani sebuah eksepsi dengan tepat.
Di materi selanjutnya, kita akan bersama-sama mempelajari bagaimana memperoleh berbagai informasi yang bisa kita dapatkan dari sebuah eksepsi dengan mengkonfigurasi status dari sebuah eksepsi.
Jika Anda merasa kesulitan dalam memahami materi tipe data dan variabel, jangan menyerah! Tulis kesulitan atau pertanyaan Anda di kolom komentar, saya akan membantu.
Selamat belajar!