Sunday, December 25, 2016

Bab 2. Visual C# Untuk Programer



Penanganan Eksepsi






2.1 Pengantar

Eksepsi merupakan suatu indikasi terjadinya suatu masalah selama eksekusi program. Penanganan eksepsi memampukan Anda untuk menciptakan aplikasi yang bisa menyelesaikan (menangani) eksepsi. Pada banyak kasus, penanganan suatu eksepsi membolehkan program untuk melanjutkan eksekusi, layaknya seperti tidak ada masalah. Fitur yang disajikan pada bab ini membantu Anda dalam menulis program yang handal dan toleran-kesalahan, yang dapat menangani masalah dan melanjutkan eksekusi atau berhenti secara normal. Penanganan eksepsi C# didasarkan pada kerja dari Andrew Koenig dan Bjarne Stroustrup.

2.2 Contoh: Pembagian Nol Tanpa Eksepsi
Pertama, akan didemonstrasikan apa yang terjadi ketika error terjadi dalam suatu aplikasi yang tidak menggunakan penanganan eksepsi. Gambar 2.1 meminta pengguna untuk memasukkan dua integer, yang menghitung hasil pembagian  atas dua integer dan menghasilkan nilai balik berupa suatu nilai int. Pada contoh ini, Anda akan melihat bahwa eksepsi dilempar ketika suatu metode mendeteksi adanya masalah dan tidak mampu mengatasinya.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// Gambar 2.1: PembagianNolTanpaEksepsi.cs
// Pembagian integer tanpa penanganan eksepsi.
using System;

class PembagianNolTanpaEksepsi
{
    static void Main()
    {
        // membaca numerator dan denominator
        Console.Write( "Silahkan masukkan sebuah numerator integer: " );
        int numerator = Convert.ToInt32( Console.ReadLine() );
        Console.Write("Silahkan masukkan sebuah denominator integer: ");
        int denominator = Convert.ToInt32( Console.ReadLine() );

        // membagi dua integer, kemudian menampilkan hasilnya
        int hasil = numerator / denominator;
        Console.WriteLine( "\nHasil: {0:D} / {1:D} = {2:D}",
            numerator, denominator, hasil );
    } // akhir Main
} // akhir kelas PembagianNolTanpaEksepsi

Silahkan masukkan sebuah numerator integer: 100
Silahkan masukkan sebuah denominator integer: 7

Hasil: 100 / 7 = 14

Silahkan masukkan sebuah numerator integer: 100
Silahkan masukkan sebuah denominator integer: 0

Unhandled Exception: System.DivideByZeroException:
   Attempted to divide by zero.
   at PembagianNolTanpaEksepsi.Main() in e:\
   Projects Visual C#\PembagianNolTanpaEksepsi\
   PembagianNolTanpaEksepsi\PembagianNolTanpaEksepsi.cs:line 16

Silahkan masukkan sebuah numerator integer: 100
Silahkan masukkan sebuah denominator integer: jogja

Unhandled Exception: System.FormatException:
   Input string was not in a correct format.
   at System.Number.StringToNumber(String str, NumberStyles options,
       NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal)
   at System.Number.ParseInt32(String s, NumberStyles style,
       NumberFormatInfo info)
   at System.Convert.ToInt32(String value)
   at PembagianNolTanpaEksepsi.Main() in e:\Projects Visual C#
      \PembagianNolTanpaEksepsi\PembagianNolTanpaEksepsi\
      PembagianNolTanpaEksepsi.cs:line 13

Menganalisa Hasil
Contoh eksekusi pertama pada Gambar 2.1 menunjukkan pembagian integer yang sukses. Eksekusi kedua, pengguna memasukan nilai 0 sebagai denominator. Beberapa baris informasi ditampilkan sebagai respon terhadap masukan yang tidak valid. Informasi tersebut dikenal dengan jejak tumpukan (stack trace), yang mencantumkan nama eksepsi (System.DivideByZeroException) dalam pesan deskriptif yang mengindikasikan terjadinya masalah dan menampilkan tumpukan pemanggilan metode pada saat masalah terjadi. Jejak tumpukan menyertakan jalur eksekusi yang mengarah ke eksepsi metode demi metode. Ini akan membantu Anda untuk mendebug program. Baris pertama menspesifikasi bahwa suatu DivideByZeroException telah terjadi. Teks setelah nama eksekusi (“Attempted to divide by zero”) mengindikasikan bahwa eksepsi ini terjadi sebagai akibat dari percobaan untuk membagi dengan nol. C# tidak mengijinkan pembagian oleh nol dalam aritmatika integer. Ketika hal ini terjadi, C# akan melemparkan suatu DivideByZeroException. Tetapi C# membolehkan pembagian oleh nol menggunakan nilai-nilai pecahan. Kalkulasi semacam itu akan menghasilkan nilai tak-terhingga positif atau negaitif, yang direpresentasikan dalam C# sebagai konstanta Double.PositiveInfinity atau konstanta Double.NegativeInfinity, tergantung dari apakah numerator positif atau negatif.

Setiap baris “at” pada jejak tumpukan mengindikasikan sebuah baris kode pada metode tertentu yang dieksekusi ketika eksepsi terjadi. Baris “at” memuat namespace, kelas, dan metode dimana di dalamnya eksepsi terjadi (PembagianNolTanpaEksepsi.Main()), lokasi dan nama file yang memuat kode (e:\Projects Visual C#\PembagianNolTanpaEksepsi\   PembagianNolTanpaEksepsi\PembagianNolTanpaEksepsi.cs), dan nomor baris (:line 16) dimana eksekusi terjadi. Pada kasus ini, jejak tumpukan mengindikasikan bahwa eksepsi DivideByZeroException terjadi ketika program mengeksekusi baris 16 pada metode Main. Baris pertama “at” pada jejak tumpukan mengindikasikan titik lempar (throwing point) eksepsi, yaitu titik awal di mana eksepsi terjadi (baris 16 pada Main). Informasi ini memudahkan Anda untuk melihat di mana eksepsi berawal, dan pemanggilan metode apa yang dilakukan pada program.

Pada contoh eksekusi ketiga, pengguna memasukkan string “jogja” sebagai denominator. Perhatikan kembali bahwa jejak tumpukan ditampilkan. Hal ini menginformasikan Anda bahwa suatu FormatException telah terjadi. Kode program yang membaca nilai numerik mengasumsikan bahwa pengguna akan memasukkan nilai integer. Tetapi, pengguna kadangkala melakukan kesalahan dan memasukkan nilai non-integer. Suatu FormatException (namespace System) terjadi ketika metode ToInt32 dari kelas Convert menerima suatu string yang tidak merepresentasikan suatu integer yang valid. Dimulai dari baris terakhir “at” pada jejak tumpukan, Anda melihat bahwa eksepsi dideteksi pada baris 13 dari metode Main. Jejak tumpukan juga menunjukkan metode-metode lain yang terlibat dengan eksepsi yang sedang dilempar. Untuk melakukan tugasnya, Convert.ToInt32 memanggil metode Number.ParseInt32, yang juga memanggil Number.StringToNumber. Titik lempar terjadi pada Number.StringToNumber, seperti diindikasikan oleh baris pertama “at” pada jejak tumpukan.

Pada dua contoh eksekusi pada Gambar 2.1, program berhenti ketika eksekusi terjadi dan jejak tumpukan ditampilkan. Ini tidak selalu terjadi, karena kadangkala program berlanjut mengeksekusi meskipun eksepsi terjadi dan jejak tumpukan ditampilkan. Pada contoh berikutnya akan didemonstrasikan bagaimana menangani eksepsi untuk memampukan sebuah program diekseksi secara normal.

2.3 Contoh: Penanganan DivideByZeroException dan FormatException
Aplikasi pada Gambar 2.2, yang didasarkan pada Gambar 2.1, menggunakan penanganan eksepsi untuk memproses sembarang DivideByZeroException dan FormatException yang dibangkitkan. Versi aplikasi ini menggunakan penanganan eksepsi sehingga jika pengguna melakukan kesalahan, program akan menangkap dan menangani eksepsi, sehingga pada kasus ini, pengguna dapat mengentri masukan kembali. Aplikasi membaca dua integer dari pengguna (baris 18-21). Jika pengguna menyediakan dua integer sebagai masukan dan tidak menetapkan 0 sebagai denominator, maka baris 25 akan melakukan pembagian dan baris 28-29 menampilkan hasilnya. Namun, jika pengguna mengentrikan masukan tak-integer atau menyediakan 0 sebagai denominator, maka eksepsi akan terjadi. Program ini mendemonstrasikan bagaimana menangkap dan menangani eksepsi semacam itu. Pada kasus ini, program akan menampilkan pesan error dan mengijinkan pengguna untuk mengentrikan-ulang masukan.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
// Gambar 2.2: PembagianNolDenganEksepsi.cs
// Menangani eksepsi FormatException dan DivideByZeroException.
using System;

class PembagianNolDenganEksepsi
{
    static void Main( string[] args )
    {
        bool loopLanjut = true; // menentukan apakah tetap beriterasi

        do
        {
// membaca masukan pengguna dan menghitung hasil bagi
try
{
    // Convert.ToInt32 membangkitkan FormatException
    // jika argumen tidak dapat dikonversi menjadi integer
    Console.Write( "Masukkan sebuah numerator integer: " );
    int numerator = Convert.ToInt32( Console.ReadLine() );
    Console.Write( "Masukkan sebuah denominator integer: " );
    int denominator = Convert.ToInt32( Console.ReadLine() );

    // pembagian membangkitkan DivideByZeroException
    // jika denominator bernilai 0
    int hasil = numerator / denominator;

    // menampilkan hasil
    Console.WriteLine( "\nHasil: {0} / {1} = {2}",
    numerator, denominator, hasil );
    loopLanjut = false;
} // akhir try
catch ( FormatException eksepsiFormat )
{
    Console.WriteLine( "\n" + eksepsiFormat.Message );
    Console.WriteLine(
        "Anda harus memasukkan dua integer. Silahkan coba lagi.\n" );
} // akhir catch
catch ( DivideByZeroException eksepsiPembagianDenganNol )
{
    Console.WriteLine( "\n" + eksepsiPembagianDenganNol.Message );
    Console.WriteLine(
        "Nol tidak valid untuk denominator. Silahkan coba lagi.\n" );
} // akhir catch
        } while ( loopLanjut ); // akhir do...while
    } // akhir Main
} // akhir kelas PembagianNolDenganEksepsi

Silahkan masukkan sebuah numerator integer: 100
Silahkan masukkan sebuah denominator integer: 7

Hasil: 100 / 7 = 14

Masukkan sebuah numerator integer: 100
Masukkan sebuah denominator integer: 0

Attempted to divide by zero.
Nol tidak valid untuk denominator. Silahkan coba lagi.

Masukkan sebuah numerator integer: 100
Masukkan sebuah denominator integer: jogja

Input string was not in a correct format.
Anda harus memasukkan dua integer. Silahkan coba lagi.

Contoh-Contoh Keluaran
Sebelum mendiskusikan detil program, akan didiskusikan lebih dahulu contoh-contoh keluaran program pada Gambar 2.2. Contoh keluaran program yang pertama menunjukkan perhitungan yang sukses dimana di dalamnya pengguna memasukkan numerator 100 dan denominator 7. Hasil (14) merupakan sebuah int, karena pembagian integer selalu menghasilkan hasil int. Contoh keluaran program yang kedua mendemonstrasikan hasil dari percobaan pembagian dengan nol. Dalam aritmatika integer, pembagian nol akan membangkitkan eksepsi DivideByZeroException jika denominator bernilai nol. Program mendeteksi eksepsi dan menampilkan sebuah pesan error yang mengindikasikan percobaan pembagian nol. Contoh keluaran program yang terakhir menampilkan hasil dari pengentrian sebuah nilai tak-int. Pada kasus ini, pengguna memasukkan “jogja” sebagai denominator. Program mencoba mengkonversi masukan string menjadi int menggunakan metode Convert.ToInt32 (baris 19 dan 21). Jika argumen tidak dapat dikonversi menjadi int, maka metode akan melemparkan eksepsi FormatException. Program menangkap eksepsi dan menampilkan pesan error yang mengindikasikan bahwa pengguna harus memasukkan dua int.

Cara Lain Untuk Mengkonversi String Menjadi Integer
Cara lain untuk memvalidasi masukan adalah dengan menggunakan metode Int32.TryParse, yang mengkonversi sebuah string menjadi sebuah int jika memungkinkan. Semua tipe numerik memiliki metode TryParse masing-masing. Metode itu memerlukan dua argumen, yaitu satu berupa string yang akan dikonversi dan yang lain adalah varibel yang di dalamnya nilai terkonversi akan disimpan. Metode ini menghasilkan nilai balik true jika string dikonversi dengan sukses. Jika string tidak dapat dikonversi, maka nilai 0 ditugaskan kepada argumen kedua, yang dilewatkan dengan referensi sehingga nilainya dapat dimodifikasi pada metode pemanggil. Metode TryParse dapat dipakai untuk memvalidasi masukan sehingga kode tidak perlu melemparkan eksepsi.

Kode di dalam Blok try
Baris 14-31 memuat suatu blok try, yang mengapit kode, yang mungkin, akan melempar suatu eksepsi dan kode tersebut tidak akan dieksekusi jika eksepsi terjadi (blok try akan dilompati). Blok try memuat katakunci try diikuti dengan suatu blok kode yang diapit oleh sepasang kurung kurawal.

Beberapa statemen yang membaca integer dari papanketik (baris 19 dan 21) masing-masing menggunakan metode Convert.ToInt32 untuk mengkonversi string menjadi int. Metode ini melempar eksepsi FormatException jika ia tidak berhasil mengkonversi string menjadi int. Jika baris 19 dan 21 mengkonversi nilai-nilai dengan benar (tidak ada eksepsi terjadi), maka baris 25 akan membagi numerator dengan denominator dan menugaskan hasilnya kepada variabel hasil. Jika baris 25 tidak menyebabkan eksepsi dilempar, maka baris 28-29 akan menampilkan hasil pembagian.

Menangkap Eksepsi
Kode penanganan-eksepsi berada di dalam blok catch. Secara umum, ketika sebuah eksepsi terjadi pada suatu blok try, blok catch terkait akan menangkap eksepsi tersebut dan menanganinya. Blok try pada contoh ini diikuti oleh dua blok catch, yaitu satu yang menangani eksepsi FormatException (baris 32-37) dan satu lagi yang menangani eksepsi DivideByZeroException (baris 38-43). Blok catch menetapkan parameter eksepsi yang merepresentasikan eksepsi yang akan ditanganinya. Blok catch dapat menggunakan pengenal parameter (yang Anda pilih sendiri) untuk berinteraksi dengan objek eksepsi yang ditangkap. Jika Anda tidak perlu menggunakan objek eksepsi pada blok catch, maka pengenal dari parameter eksepsi dapat diabaikan. Tipe parameter catch adalah tipe eksepsi yang akan ditangani oleh blok catch. Secara opsional, Anda bisa mencantumkan sebuah blok catch yang tidak menetapkan tipe eksepsi spesifik. Blok catch semacam itu akan menangkap semua tipe eksepsi. Satu blok catch dan/ atau blok finally harus diikuti oleh sedikitnya satu blok try.

Pada Gambar 2.2, blok catch yang pertama menangkap eksepsi FormatException (yang dilempar oleh metode Convert.ToInt32), dan blok catch kedua menangkap eksepsi DivideByZero-Exception. Jika eksepsi terjadi, program hanya akan mengeksekusi blok catch pertama yang sesuai. Kedua handler eksepsi pada contoh ini menampilkan pesan error. Jika salah satu blok catch selesai dieksekusi, kendali program akan berlanjut ke statemen pertama yang berada setelah blok catch yang terakhir.

2.4 Blok finally
Program yang memperoleh tipe tertentu dari sumberdaya harus mengembalikannya lagi kepada sistem secara ekplisit untuk menghindari apa yang disebut dengan kebocoran sumberdaya. Dalam bahasa pemrograman seperti C dan C++, kebocoran sumberdaya yang sering terjadi adalah kebocoran memori. C# melakukan pengumpulan sampah secara otomatis terhadap memori yang tidak lagi digunakan oleh program, sehingga menghindari kebanyakan kasus kebocoran memori. Tetapi, beberapa tipe kebocoran tetap saja terjadi. Sebagai contoh, koneksi file, koneksi database, dan koneksi jaringan yang tidak ditutup secara tepat setelah tidak lagi dibutuhkan bisa dimanfaatkan oleh program lain.

Blok finally (yang memuat katakunci finally, diikuti dengan kode yang diapit oleh sepasang kurung kurawal), kadangkala disebut pula dengan klausa finally, bersifat opsional. Jika blok ini ada, maka ia ditempatkan setelah blok catch terakhir. Jika tidak terdapat satupun blok catch, maka blok finally ditempatkan setelah blok try.

Blok finally akan dieksekusi tanpa memandang suatu eksepsi dilempar atau tidak di dalam suatu blok try. Blok finally juga akan dieksekusi jika suatu blok try keluar menggunakan statemen return, break, atau continue atau jika suatu blok try keluar hanya karena kurung kurawal penutupnya. Blok finally tidak akan dieksekusi jika aplikasi keluar dari suatu blok try dengan menggunakan statemen System.exit.

Karena blok finally hampir selalu dieksekusi, ia biasanya memuat kode pelepas sumberdaya. Dimisalkan bahwa suatu sumberdaya dialokasikan di dalam suatu blok try. Jika tidak terjadi eksepsi, maka blok catch akan dilompati dan kendali program akan berlanjut untuk mengeksekusi blok finally, yang akan melepaskan sumberdaya yang dipakai. Jika suatu eksepsi terjadi di dalam suatu blok try, maka blok try itu akan berhenti. Jika program menangkap eksepsi di dalam salah satu blok catch yang disediakan, maka program akan memproses eksepsi, kemudian blok finally akan melepaskan semua sumberdaya yang dipakai dan kendali program berlanjut untuk mengeksekusi statemen pertama setelah blok finally. Jika program tidak menangkap eksepsi yang terjadi, blok finally juga masih tetap membebaskan sumberdaya yang dipakai dan eksepsi akan dicoba untuk ditangkap dalam metode pemanggil.

Jika suatu eksepsi, yang terjadi di dalam suatu blok try, tidak dapat ditangkap oleh salah satu dari blok catch, maka program akan melompati sisa blok try dan kendali program akan mengeksekusi blok finally. Kemudian program akan melewatkan eksepsi tersebut kepada blok try sebelah luar, yang biasanya berada di dalam metode pamanggil, dimana blok catch terkait bisa menangkapnya. Hal ini dapat terjadi pada banyak level blok try.

Jika suatu blok catch menangkap suatu eksepsi, blok finally masih tetap dieksekusi. Kemudian eksepsi tersebut dilewatkan kepada blok try sebelah luar, yang biasanya ditempatkan di dalam metode pemanggil.

Gambar 2.3 mendemonstrasikan bahwa blok finally tetap dieksekusi meskipun bila eksepsi tidak dilemparkan di dalam blok try. Program memuat metode Main (baris 8-47) dan empat metode lain yang dipanggil Main untuk mendemonstrasikan finally. Keempat metode tersebut adalah TidakLemparEksepsi (baris 50-67), LemparEksepsiDenganCatch (baris 70-89), LemparEksepsiTanpaCatch (baris 92-108), dan LemparEksepsiCatchLemparUlang (baris 111-136).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
// Gambar. 2.3: MenggunakanEksepsi.cs
// menggunakan blok-blok finally.
// blok-blok finally selalu dieksekusi, meski jika tidak ada eksepsi yang terjadi.
using System;

class MenggunakanEksepsi
{
    static void Main()
    {
        // Kasus 1: Tidak ada eksepsi yang terjadi pada metode terpanggil
        Console.WriteLine( "Memanggil TidakLemparEksepsi" );
        TidakLemparEksepsi();

        // Kasus 2: Eksepsi terjadi dan ditangkap pada metode terpanggil
        Console.WriteLine( "\nMemanggil LemparEksepsiDenganCatch" );
        LemparEksepsiDenganCatch();

        // Kasus 3: Eksepsi terjadi, tetapi tidak ditangka pada metode terpanggil
        // karena tidak ada blok catch.
        Console.WriteLine( "\nMemanggil LemparEksepsiTanpaCatch" );

        // memanggil LemparEksepsiTanpaCatch
        try
        {
            LemparEksepsiTanpaCatch();
        } // akhir try
        catch
        {
            Console.WriteLine( "Menangkap eksepsi dari " +
            "LemparEksepsiTanpaCatch di dalam Main" );
        } // akhir catch

        // Kasus 4: Eksepsi terjadi dan ditangkap pada metode terpanggil,
        // kemudian dilempar-ulang kepada pemanggil.
        Console.WriteLine( "\nMemanggil LemparEksepsiCatchLemparUlang" );

        // memanggil LemparEksepsiCatchLemparUlang
        try
        {
            LemparEksepsiCatchLemparUlang();
        } // akhir try
        catch
        {
            Console.WriteLine( "Menangkap eksepsi dari " +
                "LemparEksepsiCatchLemparUlang di dalam Main" );
        } // akhir catch
    } // akhir metode Main

    // tidak ada eksepsi yang dilempar
    static void TidakLemparEksepsi()
    {
        // blok try tidak melempar eksepsi
        try
        {
            Console.WriteLine("Di dalam TidakLemparEksepsi");
        } // akhir try
        catch
        {
            Console.WriteLine( "Blok catch ini tidak pernah dieksekusi" );
        } // akhir catch
finally
{
    Console.WriteLine("finally dieksekusi di dalam TidakLemparEksepsi");
} // akhir finally

        Console.WriteLine("Akhir dari TidakLemparEksepsi");
    } // akhir metode TidakLemparEksepsi

    // melempar eksepsi dan menangkapnya secara lokal
    static void LemparEksepsiDenganCatch()
    {
        // blok try melempar eksepsi
        try
        {
            Console.WriteLine("Di dalam LemparEksepsiDenganCatch");
            throw new Exception("Eksepsi di dalam LemparEksepsiDenganCatch");
        } // akhir try
        catch ( Exception parameterEksepsi )
        {
            Console.WriteLine( "Pesan: " + parameterEksepsi.Message );
        } // akhir catch
finally
{
    Console.WriteLine(
        "finally dieksekusi di dalam LemparEksepsiDenganCatch");
} // akhir finally

        Console.WriteLine("Akhir dari LemparEksepsiDenganCatch");
    } // akhir metode LemparEksepsiDenganCatch

    // melempar eksepsi dan tidak menangkapnya secara lokal
    static void LemparEksepsiTanpaCatch()
    {
        // melempar eksepsi, tetapi tidak menangkapnya
        try
        {
            Console.WriteLine("Di dalam LemparEksepsiTanpaCatch");
            throw new Exception("Eksepsi di dalam LemparEksepsiTanpaCatch");
        } // akhir try
finally
{
    Console.WriteLine( "finally dieksekusi di dalam " +
        "LemparEksepsiTanpaCatch");
} // akhir finally

        // kode tidak dieksekusi; error logika
        Console.WriteLine("Akhir dari LemparEksepsiTanpaCatch");
    } // akhir metode LemparEksepsiTanpaCatch

    // melempar eksepsi, menangkapnya dan melemparnya ulang
    static void LemparEksepsiCatchLemparUlang()
    {
        // blok try melempar eksepsi
        try
        {
            Console.WriteLine("Di dalam LemparEksepsiCatchLemparUlang");
            throw new Exception("Eksepsi di dalam LemparEksepsiCatchLemparUlang");
        } // akhir try
        catch ( Exception parameterEksepsi )
        {
            Console.WriteLine( "Pesan: " + parameterEksepsi.Message );

            // melempar-ulang eksepsi untuk pemrosesan lebih lanjut
            throw;

            // kode tidak dieksekusi; error logika
        } // akhir catch
finally
{
    Console.WriteLine( "finally dieksekusi di dalam " +
        "LemparEksepsiCatchLemparUlang");
} // akhir finally

        // sembarang kode yang ditempatkan di sini tidak akan pernah dieksekusi
        Console.WriteLine("Akhir dari LemparEksepsiCatchLemparUlang");
    } // akhir metode LemparEksepsiCatchLemparUlang
} // akhir kelas MenggunakanEksepsi

Memanggil TidakLemparEksepsi
Di dalam TidakLemparEksepsi
finally dieksekusi di dalam TidakLemparEksepsi
Akhir dari TidakLemparEksepsi

Memanggil LemparEksepsiDenganCatch
Di dalam LemparEksepsiDenganCatch
Pesan: Eksepsi di dalam LemparEksepsiDenganCatch
finally dieksekusi di dalam LemparEksepsiDenganCatch
Akhir dari LemparEksepsiDenganCatch

Memanggil LemparEksepsiTanpaCatch
Di dalam LemparEksepsiTanpaCatch
finally dieksekusi di dalam LemparEksepsiTanpaCatch
Menangkap eksepsi dari LemparEksepsiTanpaCatch di dalam Main

Memanggil LemparEksepsiCatchLemparUlang
Di dalam LemparEksepsiCatchLemparUlang
Pesan: Eksepsi di dalam LemparEksepsiCatchLemparUlang
finally dieksekusi di dalam LemparEksepsiCatchLemparUlang
Menangkap eksepsi dari LemparEksepsiCatchLemparUlang di dalam Main

Baris 12 pada Main memanggil metode TidakLemparEksepsi. Blok try pada metode ini menampilkan sebuah pesan (baris 55). Karena blok try tersebut tidak melempar sembarang eksepsi, maka kendali program akan mengabaikan blok catch (baris 57-60) dan mengekseksi blok finally (baris 61-64), yang menampilkan sebuah pesan. Pada titik ini, kendali program berlanjut ke statemen pertama yang berada setelah kurung kurawal penutup pada blok finally (baris 66), yang menampilkan sebuah pesan untuk mengindikasikan bahwa akhir metode telah diraih. Kemudian, kendali program kembali ke Main.

Melempar Eksepsi Menggunakan Statemen throw
Baris 16 pada Main memanggil metode LemparEksepsiDenganCatch (baris 70-89), yang diawali dengan blok try (baris 73-77) dengan menampilkan sebuah pesan. Selanjutnya, blok try tersebut menciptakan sebuah objek Exception dan menggunakan statemen throw untuk melemparkannya (baris 76). Pengeksekusian statemen throw mengindikasikan bahwa ada masalah yang terjadi pada kode. Statemen throw menetapkan sebuah objek untuk dilemparkan. Operand dari statemen throw dapat bertipe Exception atau sembarang tipe yang diderivasi dari kelas Exception.

String yang dilewatkan kepada konstruktor menjadi pesan error dari objek eksepsi. Ketika statemen throw di dalam suatu blok try dieksekusi dan kendali program akan langsung keluar dari blok try tersebut dan berlanjut ke blok catch pertama yang cocok (baris 78-81) yang berada setelah blok try itu. Pada contoh ini, tipe eksepsi (Exception) yang dilemparkan cocok dengan tipe yang dispesifikasi pada catch, jadi baris 80 menampilkan sebuah pesan yang mengindikasikan eksepsi yang telah terjadi. Kemudian, blok finally (baris 82-86) dieksekusi dan menampilkan sebuah pesan. Pada titik ini, kendali program berlanjut ke statemen pertama yang berada setelah kurung kurawal penutup pada blok finally (baris 88), yang menampilkan sebuah pesan untuk mengindikasikan bahwa akhir metode telah diraih. Kendali program kemudian kembali ke Main. Pada baris 80, Anda menggunakan properti Message dari objek eksepsi untuk membaca pesan error yang berkaitan dengan eksepsi yang terjadi (pesan tersebut dilewatkan kepada konstruktor Exception).

Baris 23-31 pada Main mendefinisikan suatu statemen try, dimana di dalamnya Main memanggil metode LemparEksepsiTanpaCatch (baris 92-108). Blok try tersebut memampukan Main untuk menangkap sembarang eksepsi yang dilemparkan oleh LemparEksepsiTanpaCatch. Blok try pada baris 95-99 pada LemparEksepsiTanpaCatch dimulai dengan menampilkan sebuah pesan. Selanjutnya, blok try itu melemparkan sebuah Exception (baris 98).

Normalnya, kendali program akan berlanjut ke blok catch pertama yang berada setelah blok try. Namun, blok try ini tidak memiliki blok catch. Oleh karena itu, eksepsi tidak ditangkap di dalam metode LemparEksepsiTanpaCatch. Kendali program berlanjut ke blok finally (baris 100-104), yang menampilkan sebuah pesan. Pada titik ini, kendali program kembali ke Main. Jadi, sembarang statemen yang berada setelah blok try (misalnya, baris 107) tidak akan pernah dieksekusi. Pada contoh ini, statemen semacam itu menyebabkan error logika, karena eksepsi yang dilempar pada baris 98 tidak ditangkap. Pada Main, blok catch pada baris 27-31 menangkap eksepsi dan menampilkan sebuah pesan yang mengindikasikan bahwa eksepsi telah terjadi pada Main.

Melemparkan-Ulang Eksepsi
Baris 38-46 pada Main mendefinisikan sebuah statemen try dimana di dalamnya Main memanggil metode LemparEksepsiCatchLemparUlang (baris 111-136). Statemen try memampukan Main untuk menangkap sembarang eksepsi yang dilemparkan oleh LemparEksepsiCatch-LemparUlang. Statemen try pada baris 114-132 pada LemparEksepsiCatchLemparUlang dimulai dengan menampilkan sebuah pesan. Selanjutnya, blok try melemparkan sebuah Exception (baris 117). Kendali program langsung keluar dari blok try tersebut dan berlanjut ke blok catch pertama (baris 119-127) yang berada setelah blok try itu. Pada contoh ini, tipe yang dilemparkan (Exception)  cocok dengan tipe yang dispesifikasi pada catch, jadi baris 121 menampilkan sebuah pesan yang mengindikasikan di mana eksepsi terjadi. Baris 124 menggunakan statemen throw untuk melempar-ulang eksepsi. Ini mengindikasikan bahwa blok try melakukan pemrosesan parsial terhadap eksepsi dan sekarang melempar-ulang eksepsi tersebut (pada kasus ini, kembali ke metode Main) untuk pemrosesan berikutnya.

Penanganan eksepsi pada metode LemparEksepsiCatchLemparUlang tidak sempurna, karena statemen throw pada baris 124 secara mendadak menghentikan blok catch. Jika terdapat sembarang kode yang berada di antara baris 124 dan kurung kurawal penutup blok catch itu, maka kode tersebut tidak akan dieksekusi. Ketika baris 124 dieksekusi, metode LemparEksepsiCatch-LemparUlang akan berhenti dan mengembalikan kendali program kepada Main. Sekali lagi, blok finally (baris 128-132) dieksekusi dan menampilkan sebuah pesan sebelum kendali program kembali kepada Main. Ketika kendali kembali kepada Main, blok catch pada baris 42-46 akan menangkap eksepsi dan menampilkan sebuah pesan yang mengindikasikan bahwa eksepsi telah ditangkap. Kemudian program berhenti.

Setelah Blok finally
Statemen selanjutnya yang akan dieksekusi setelah blok finally berhenti bergantung dari keadaan penanganan eksepsi. Jika blok try dengan sukses dieksekusi, atau jika blok catch menangkap dan menangani eksepsi, maka program akan berlanjut mengeksekusi statemen berikutnya yang berada setelah blok finally. Namun, jika eksepsi tidak ditangkap, atau jika blok catch melempar-ulang eksepsi, maka kendali program akan berlanjut ke kurung kurawal penutup dari blok try berikutnya. Kurung kurawal penutup blok try dapat berada di metode pemanggil atau di dalam salah satu pemanggilnya. Adalah memungkinkan untuk membuat sebuah statemen try bersarang di dalam suatu blok try. Pada kasus semacam itu, blok catch dari statemen try sebelah luar akan memproses sembarang eksepsi yang tidak ditangkap pada statemen try sebelah dalam. Jika sebuah blok try dieksekusi dan memiliki suatu blok finally, maka blok finally itu tetap dieksekusi bahkan jika blok try berhenti secara mendadak karena keberadaan statemen return.

2.5 Properti-Properti pada Kelas Exception
Semua tipe eksepsi diderivasi dari kelas Exception, yang memiliki beberapa properti. Properti-properti tersebut digunakan untuk memformulasikan pesan yang menjelaskan eksepsi yang ditangkap. Dua properti penting adalah Message dan StackTrace. Properti Message menyimpan pesan error yang berkaitan dengan sebuah objek Exception. Pesan ini dapat berupa pesan default yang berkaitan dengan tipe eksepsi atau pesan termodifikasi yang dilewatkan kepada konstruktor dari objek Exception ketika objek Exception dilemparkan. Properti StackTrace memuat suatu string yang merepresentasikan tumpukan pemanggilan-metode. Properti StackTrace merepresentasikan serangkaian metode yang belum selesai diproses pada saat eksepsi terjadi.

Properti InnerException
Properti lain yang sering digunakan oleh programer pustaka-kelas adalah InnerException. Umumnya, para programer kelas pustaka “membungkus” objek-objek eksepsi yang ditangkap pada kodenya sehingga kemudian dapat melempar tipe eksepsi baru yang spesifik dengan pustaka yang diciptakan programer. Sebagai contoh, seorang programer yang mengimplementasikan sistem akunting memiliki kode pemrosesan akun dimana di dalamnya angka-angka akun dientrikan sebagai string tetapi direpresentasikan sebagai int pada kode. Ingat bahwa sebuah program dapat mengkonversi string menjadi int menggunakan Convert.ToInt32, yang melemparkan sebuah ekspesi FormatException ketika ia menjupai format angka tak-valid.

Ketika sebuah format tak-valid dijumpai, programer sistem-akunting akan menggunakan pesan error yang berbeda dari pesan default yang disediakan oleh FormatException atau akan menciptakan sebuah tipe eksepsi baru, seperti FormatAngkaTakValidException. Pada kasus itu, Anda perlu menyediakan kode untuk menangkap FormatException, kemudian menciptakan sebuah tipe baru yang cocok dengan tipe Exception pada blok catch dan melewatkan eksepsi asli sebagai salah satu argumen konstruktor. Objek eksepsi asli menjadi InnerException dari objek eksepsi yang baru. Ketika eksepsi FormatAngkaTakValidException terjadi pada kode yang menggunakan pustak sistem akunting, blok catch yang menangkap eksepsi tersebut dapat memperoleh referensi yang menunjuk ke eksepsi asli melalui properti InnerException. Jika properti InnerException bernilai null, maka ini mengindikasikan bahwa eksepsi tidak disebabkan oleh eksepsi lain.

Properti-Properti Exception Lain
Kelas Exception menyediakan properti-properti lain, seperti HelpLink, Source, dan TargetSite. Properti HelpLink menetapkan lokasi dari file help yang menjelaskan masalah yang terjadi. Properti ini bernilai null jika file tersebut tidak ada. Properti Source menetapkan nama aplikasi atau objek yang menyebabkan eksepsi. Properti TargetSite menetapkan metode dimana eksepsi berawal.

Mendemonstrasikan Properti-Properti Exception
Contoh selanjutnya (Gambar 2.4) mendemonstrasikan properti Message, StackTrace, dan InnerException dari kelas Exception. Selain itu, contoh ini juga mengintroduksi penguraian tumpukan, dimana sebuah eksepsi dilemparkan tetapi tidak ditangkap oleh skop tertentu. Hal ini menyebabkan tumpukan pemanggilan-metode terurai. Contoh ini menjejak metode-metode pada tumpukan pemanggilan menggunakan properti StackTrace.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
// Gambar 2.4: Properti.cs
// Penguraian tumpukan dan properti-properti kelas Exception .
// Mendemonstrasikan penggunaan properti Message, StackTrace dan InnerException.
using System;

class Properti
{
    static void Main()
    {
        // memanggil Metode1; setiap Exception yang dibangkitkan ditangkap
        // di dalam blok catch yang mengikutinya
        try
        {
            Metode1();
        } // akhir try
        catch ( Exception parameterEksepsi )
        {
            // menampilkan representasi string dari Exception, kemudian menampilkan
            // properti-proprti Message, StackTrace dan InnerException
            Console.WriteLine("parameterEksepsi.ToString: \n{0}\n",
                parameterEksepsi );
            Console.WriteLine("parameterEksepsi.Message: \n{0}\n",
                parameterEksepsi.Message );
            Console.WriteLine("parameterEksepsi.StackTrace: \n{0}\n",
                parameterEksepsi.StackTrace );
            Console.WriteLine("parameterEksepsi.InnerException: \n{0}\n",
                parameterEksepsi.InnerException );
        } // akhir catch
    } // akhir metode Main

    // memanggil Metode2
    static void Metode1()
    {
        Metode2();
    } // akhir metode Metode1

    // memanggil Metode3
    static void Metode2()
    {
        Metode3();
    } // akhir metode Metode2

    // melemparkan sebuah Exception yang memuat sebuah InnerException
    static void Metode3()
    {
        // mencoba mengkonversi string menjadi int
        try
        {
            Convert.ToInt32( "Bukan sebuah integer" );
        } // akhir try
        catch ( FormatException parameterEksepsiFormat )
        {
            // membungkus FormatException di dalam Exception baru
throw new Exception( "Exception terjadi pada Metode3",
    parameterEksepsiFormat );
        } // akhir catch
    } // akhir metode Metode3
} // akhir kelas Properti

parameterEksepsi.ToString:
System.Exception: Exception terjadi pada Metode3 --->
   System.FormatException: Input string was not in a correct format.
   at System.Number.StringToNumber(String str, NumberStyles options,
      NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal)
   at System.Number.ParseInt32(String s, NumberStyles style,
      NumberFormatInfo info)
   at System.Convert.ToInt32(String value)
   at Properti.Metode3() in e:\Projects Visual C#\Properti\
      Properti\Properti.cs:line 49
   --- End of inner exception stack trace ---
   at Properti.Metode3() in e:\Projects Visual C#\Properti\Properti\
      Properti.cs:line 54
   at Properti.Metode2() in e:\Projects Visual C#\Properti\Properti\
      Properti.cs:line 40
   at Properti.Metode1() in e:\Projects Visual C#\Properti\Properti\
      Properti.cs:line 34
   at Properti.Main() in e:\Projects Visual C#\Properti\Properti\
      Properti.cs:line 14

parameterEksepsi.Message:
Exception terjadi pada Metode3

parameterEksepsi.StackTrace:
   at Properti.Metode3() in e:\Projects Visual C#\Properti\Properti\
      Properti.cs:line 54
   at Properti.Metode2() in e:\Projects Visual C#\Properti\Properti\
      Properti.cs:line 40
   at Properti.Metode1() in e:\Projects Visual C#\Properti\Properti\
      Properti.cs:line 34
   at Properti.Main() in e:\Projects Visual C#\Properti\Properti\
      Properti.cs:line 14

parameterEksepsi.InnerException:
System.FormatException: Input string was not in a correct format.
   at System.Number.StringToNumber(String str, NumberStyles options,
      NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal)
   at System.Number.ParseInt32(String s, NumberStyles style,
      NumberFormatInfo info)
   at System.Convert.ToInt32(String value)
   at Properti.Metode3() in e:\Projects Visual C#\Properti\Properti\
      Properti.cs:line 49

Eksekusi program diawali dari Main, yang menjadi metode pertama pada tumpukan pemanggilan metode. Baris 14 pada blok try di dalam main memanggil Metode1 (dideklarasikan pada baris 32-35), yang menjadi metode kedua pada tumpukan. Jika Metode1 melemparkan sebuah eksepsi, maka blok catch pada baris 16-28 akan menangani eksepsi itu dan menampilkan informasi seputar eksepsi yang terjadi. Baris 34 pada Metode1 memanggil Metode2 (baris 38-41), yang menjadi metode ketiga pada tumpukan. Kemudian baris 40 pada Metode2 memanggil Metode3 (baris 44-57), yang menjadi metode keempat pada tumpukan.

Pada titik ini, tumpukan pemanggilan-metode (dari atas ke bawah) untuk program adalah:

Metode3
Metode2
Metode1
Main

Metode yang dipanggil paling belakangan (Metode3) berada di atas tumpukan; metode pertama yang dipanggil (Main) berada di bawah tumpukan. Statemen try (baris 47-56) pada Metode3 memanggil metode Convert.ToInt32 (baris 49), yang mencoba mengkonversi string menjadi int. Pada titik ini, Convert.ToInt32 menjadi metode kelima dan terakhir pada tumpukan pemanggilan.

Melempar Exception dengan InnerException
Karena argumen pada Convert.ToInt32 tidak dalam format int, baris 49 melemparkan sebuah eksepsi FormatException yang ditangkap pada baris 52 pada Metode3. Eksepsi tersebut menghentikan pemanggilan terhadap Convert.ToInt32, jadi metode tersebut dihapus dari tumpukan pemanggilan-metode. Blok catch pada Metode3 kemudian menciptakan dan melemparkan sebuah objek Exception. Argumen pertama pada konstruktor Exception adalah pesan error yang dimodifikasi “Exception terjadi pada Metode3”. Argumen keduanya adalah InnerException, yaitu eksepsi FormatException yang ditangkap. Properti StackTrace untuk objek eksepsi yang baru ini merefleksikan titik dimana eksepsi dilemparkan (baris 54-55). Sekarang Metode3 berhenti, karena eksepsi yang dilemparkan di dalam blok catch tidak ditangkap di dalam tubuh metode itu. Jadi, kendali program kembali ke statemen yang memanggil Metode3 (yaitu Metode2). Ini akan menghapus atau mengurai Metode3 dari tumpukan pemanggilan-metode.

Ketika kendali program kembali ke baris 40 pada Metode2, kompiler menentukan bahwa baris 40 tidak berada di dalam sebuah blok try. Oleh karena itu, eksepsi tidak ditangkap di dalam Metode2, dan Metode2 pun berhenti. Ini akan menghapus Metode2 dari tumpukan pemanggilan dan mengembalikan kendali program kepada baris 34 pada Metode1.

Di sini lagi, baris 34 tidak berada di dalam sebuah blok try, jadi Metode1 tidak dapat menangkap eksepsi. Metode ini berhenti dan dihapus dari tumpukan pemanggilan, kemudian mengembalikan kendali ke baris 14 pada Main, yang berlokasi di dalam suatu blok try. Blok try pada Main berhenti dan blok catch (baris 16-28) menangkap eksepsi. Blok catch menggunakan properti Message, StackTract, dan InnerException untuk menghasilkan keluaran. Penguraian tumpukan berlanjut sampai sebuah blok catch menangkap eksepsi atau sampai program berhenti.

Menampilkan Informasi Seputar Exception
Blok keluaran pertama pada Gambar 2.4 memuat representasi string atas eksepsi, yang merupakan nilai balik dari pemanggilan implisit terhadap metode ToString. Representasi string diawali dengan nama kelas eksepsi yang diikuti dengan nilai properti Message. Empat item berikutnya menyajikan jejak tumpukan dari objek InnerException. Informasi lain pada blok ini menunjukkan StackTrace untuk eksepsi yang dilemparkan di dalam Metode3. Properti StackTrace merepresentasikan keadaan dari tumpukan pemanggilan-metode pada titik lempar eksepsi, bukan pada titik dimana eksepsi akhirnya ditangkap. Setiap baris StackTrace yang diawali dengan “at” merepresentasikan sebuah metode pada tumpukan pemanggilan. Tiap baris ini mengindikasikan metode dimana di dalamnya eksepsi terjadi, file dimana di dalamnya metode ditempatkan, dan nomor baris dari titik lempar pada file. Informasi seputar InnerException mencakup jejak tumpukan inner-exception.

Blok keluaran berikutnya (dua baris) menampilkan nilai properti Message (Exception terjadi pada Metode3) dari eksepsi yang dilempar pada Metode3.

Blok ketiga pada keluaran menampilkan properti StackTrace dari eksepsi yang dilempar pada Metode3. Properti StackTrace ini memuat jejak tumpukan diawali dari baris 54 pada Metode3, karena di situlah titik di mana objek Exception diciptakan dan dilemparkan. Jejak tumpukan selalu diawali dari titik lempar eksepsi.

Terakhir, blok keluaran terakhir menampilkan representasi string atas properti InnerException, yang mencantumkan namespace dan nama kelas dari objek eksepsi, berikut dengan properti Message dan StackTracenya.

2.6 Kelas Eksepsi Buatan Sendiri
Dalam banyak kasus, Anda dapat menggunakan kelas-kelas eksepsi dari .NET Framework Class Library untuk mengindikasikan eksepsi-eksepsi yang terjadi pada program Anda. Pada beberapa kasus, Anda mungkin ingin menciptakan kelas eksepsi sendiri yang spesifik dengan permasalahan pada program Anda. Kelas eksepsi terdefinisi-pengguna harus diderivasi secara langsung atau tak-langsung dari kelas Exception pada namespace System. Ketika Anda menuliskan kode yang melemparkan eksepsi semacam itu, Anda perlu mendokumentasikannya, sehingga pengembang lain yang menggunakan kode Anda akan mengetahui bagaimana menanganinya.

Kelas AngkaNegatifException
Gambar 2.5 – 2.6 mendemonstrasikan sebuah kelas eksepsi buatan sendiri. Kelas AngkaNegatifException (Gambar 2.5) merepresentasikan eksepsi yang terjadi ketika sebuah program melakukan suatu operasi ilegal pada angka negatif, seperti mencoba untuk menghitung akar kuadratnya.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// Gambar 2.5: AngkaNegatifException.cs
// AngkaNegatifException merepresentasikan eksepsi-eksepsi yang disebabkan oleh
// operasi-operasi ilegal terhadap angka-angka negatif.
using System;

class AngkaNegatifException : Exception
{
// konstruktor default
public AngkaNegatifException()
    : base( "Operasi ilegal untuk sebuang angka negatif" )
{
    // tubuh kosong
} // akhir konstruktor default

// konstruktor untuk memodifikasi pesan error
public AngkaNegatifException( string nilaiPesan )
    : base( nilaiPesan )
{
    // tubuh kosong
} // akhir konstruktor satu-argumen

// konstruktor untuk memodifikasi pesan error
// dan menetapkan objek InnerException
public AngkaNegatifException(string nilaiPesan,
    Exception inner )
    : base(nilaiPesan, inner)
{
    // tubuh kosong
} // akhir konstruktor dua-argumen
} // akhir kelas AngkaNegatifException

Sesuai dengan dokumentasi Microsoft, eksepsi terdefinisi-pengguna harus mewarisi kelas Exception, memiliki nama kelas yang diakhiri dengan “Exception”, dan mendefinisikan tiga konstruktor: sebuah konstruktor tanpa parameter; sebuah konstruktor yang menerima sebuah argumen string (pesan error); dan sebuah konstruktor yang menerima sebuah argumen string dan sebuah argumen Exception (pesan error dan objek inner-exception). Pendefinisian ketiga konstruktor ini membuat kelas eksepsi Anda lebih fleksibel, yang memampukan programer lain agar lebih mudah menggunakan dan mewarisinya.

Karena AngkaNegatifException sering terjadi pada saat operasi aritmatika, jadi logis bila Angka-NegatifException mewarisi kelas ArithmeticException. Namun, kelas ArithmeticException mewarisi kelas SystemException. Tetapi, menurut Microsoft, yang terbaik dilakukan adalah mewarisi dari Exception, bukan dari SystemException. Pada kasus ini, Anda bisa saja menggunakan kelas ArgumentException (tersedia pada .NET Framework), yang direkomendasi untuk nilai-nilai argumen tak-valid. Anda menciptakan tipe eksepsi sendiri di sini hanya untuk tujuan demonstrasi saja.

Kelas UjiAkarKuadrat
Kelas UjiAkarKuadrat (Gambar 2.6) mendemonstrasikan kelas eksepsi yang telah dibuat. Aplikasi memampukan pengguna untuk memasukkan sebuah angka numerik, kemudian memanggil metode AkarKuadrat (baris 40-48) untuk menghitung akar kuadrat dari nilai itu. Untuk melakukan perhitungan ini, AkarKuadrat memanggil metode Sqrt dari kelas Math, yang menerima sebuah nilai double sebagai argumennya. Normalnya, jika argumennya negatif, maka metode Sqrt akan menghasilkan NaN. Pada program ini, Anda akan mencegah pengguna untuk menghitung akar kuadrat atas suatu nilai negatif. Jika nilai numerik yang dimasukkan pengguna bernilai negatif, maka metode AkarKuadrat akan melemparkan eksepsi AngkaNegatifException (baris 44-45). Sebaliknya, AkarKuadrat memanggil metode Sqrt dari kelas Math untuk menghitung akar kuadrat (baris 47).

Ketika pengguna memasukkan sebuah nilai, statemen try (baris 14-34) mencoba memanggil AkarKuadrat menggunakan nilai masukan oleh pengguna. Jika masukan pengguna bukan suatu angka, maka eksepsi FormatException akan terjadi, dan blok catch pada baris 25-29 akan memproses eksepsi itu. Jika pengguna memasukkan sebuah angka negatif, maka metode AkarKuadrat akan melemparkan AngkaNegatifException (baris 44-45); blok catch pada baris 30-34 menangkap dan menangani tipe eksepsi ini.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
// Gambar 2.6: UjiAkarKuadrat.cs
// Mendemonstrasikan sebuah kelas eksepsi terdefinisi-pengguna.
using System;

class UjiAkarKuadrat
{
    static void Main( string[] args )
    {
        bool loopLanjut = true;

        do
        {
            // menangkap sembarang AngkaNegatifException yang dilempar
            try
            {
                Console.Write(
                    "Masukkan sebuah nilai untuk menghitung akar kuadratnya: " );
                double nilaiMasukan = Convert.ToDouble( Console.ReadLine() );
                double hasil = AkarKuadrat( nilaiMasukan );

                Console.WriteLine( "Akar kuadrat dari {0} adalah {1:F6}\n",
                    nilaiMasukan, hasil );
                loopLanjut = false;
            } // akhir try
            catch ( FormatException eksepsiFormat )
            {
                Console.WriteLine( "\n" + eksepsiFormat.Message );
                Console.WriteLine( "Silahkan masukkan sebuah nilai double.\n" );
            } // akhir catch
            catch ( AngkaNegatifException angkaNegatifException )
            {
                Console.WriteLine( "\n" + angkaNegatifException.Message );
                Console.WriteLine( "Silahkan masukkan sebuah nilai tak-negatif.\n" );
            } // akhir catch
        } while ( loopLanjut );
    } // akhir Main

    // menghitung akar kuadrat dari parameter; melemparkan
    // AngkaNegatifException jika parameter bernilai negatif
    public static double AkarKuadrat( double nilai )
    {
        // jika operand negatif, lemparkan AngkaNegatifException
        if ( nilai < 0 )
            throw new AngkaNegatifException(
                "Akar kuadrat dari angka negatif tidak diijinkan" );
        else
            return Math.Sqrt( nilai ); // menghitung akar kuadrat
    } // akhir metode AkarKuadrat
} // akhir kelas UjiAkarKuadrat

Masukkan sebuah nilai untuk menghitung akar kuadratnya: 30
Akar kuadrat dari 30 adalah 5.477226

Masukkan sebuah nilai untuk menghitung akar kuadratnya: jogja

Input string was not in a correct format.
Silahkan masukkan sebuah nilai double.

Masukkan sebuah nilai untuk menghitung akar kuadratnya: 25
Akar kuadrat dari 25 adalah 5.000000

Masukkan sebuah nilai untuk menghitung akar kuadratnya: -2

Akar kuadrat dari angka negatif tidak diijinkan
Silahkan masukkan sebuah nilai tak-negatif.

Masukkan sebuah nilai untuk menghitung akar kuadratnya: 2
Akar kuadrat dari 2 adalah 1.414214




No comments:

Post a Comment