Three examples are given here as a refresher:
Read through these examples to familiarize yourself with the different types of exception objects thrown for each scenario. Note the comments I have made at the end of each example. 13.1.1 Exception example 1: basic try-catch-finallyHere is a basic example of exception handling in C#. Try to trace the program flow based on your knowledge of Java's exception handling. 1: using System; 2: 3: class TestClass{ 4: public static void Main(){ 5: 6: Console.Write("Enter a number :"); 7: string userInput = Console.ReadLine(); 8: 9: try{ 10: int number1 = Convert.ToInt32(userInput); 11: int number2 = 1/number1; 12: } 13: catch (FormatException e){ 14: Console.WriteLine("check point 1"); 15: Console.WriteLine(e.Message); 16: Console.WriteLine(e.StackTrace); 17: } 18: catch (DivideByZeroException e){ 19: Console.WriteLine("check point 2"); 20: Console.WriteLine(e.Message); 21: Console.WriteLine(e.StackTrace); 22: } 23: finally { 24: Console.WriteLine("running finally block"); 25: } 26: } 27: } Convert.ToInt32() on line 10 is a static method of the System.Convert class. Like Java's Integer.parseInt() , Convert.ToInt32() takes in a string and returns an int . While Integer.parseInt() throws a java.lang.NumberFormatException if the string passed in contains non-numeric characters , Convert.ToInt32() throws a System.FormatException when that happens. Line 11 may throw a System.DivideByZeroException if a division by 0 is performed. As the name implies, System.DivideByZeroException is the C# equivalent of java.lang.ArithmeticException . You can execute the program, key in different inputs, observe the output, and trace through the code. First case: enter a non-numeric string c:\expt>test Enter a number: not_a_number check point 1 Input string was not in a correct format at System.Number.ParseInt32(String s, NumberStyles style, NumberFormatInfo info) at TestClass.Main() running finally block This user input will cause line 10 to throw a System.FormatException . The exception is caught at the first catch block (line 13). The finally block (line 23) runs after that. The program flow goes like this:
Second case: enter the number zero c:\expt>test Enter a number: check point 2 Attempted to divide by zero at TestClass.Main() running finally block The statement on line 11 throws a System.DivideByZeroException exception. Similarly, the finally block runs after the second exception block finishes. The program flow goes like this:
Third case: enter a proper integer c:\expt>test Enter a number: 70 running finally block No exceptions were thrown, the two catch blocks were skipped , and the finally block executes. The program flow goes like this:
13.1.2 Exception example 2: nested tryLike Java, you can have multiple levels of try-catch nesting. Instead of a fully fledged code example, I will step through a skeletal code fragment, and discuss the program flow when an exception occurs at different points in the code. I am using an example of one try-catch block immediately enclosed within another. Though you usually do not write nested try blocks within a single method, this exercise will clarify any conceptual uncertainties. 10: try{ 11: // statement 1 12: // statement 2 13: try{ 14: // statement 3 15: // statement 4 16: } 17: catch(Exception1 e){ 18: // statement 5 19: // statement 6 20: } 21: catch(Exception2 e){ 22: // statement 7 23: // statement 8 24: } 25: finally{ 26: // statement 9 27: // statement 10 28: } 29: // statement 11 30: // statement 12 31: } 32: catch (Exception1 e){ 33: // statement 13 34: // statement 14 35: } 36: catch (Exception2 e){ 37: // statement 15 38: // statement 16 39: } 40: catch (Exception3 e){ 41: // statement 17 42: // statement 18 43: } 44: finally{ 45: // statement 19 46: // statement 20 47: } First case: Exception2 thrown on statement 3 onlyFigure 13.1 shows the program flow. Figure 13.1. Program flow: Exception2 thrown on statement 3.
The exception is caught at line 21. The finally block completes and, since the exception has been handled properly in the inner try-catch block, the exception is not propagated to the next enclosing try block. Second case: statement 3 throws Exception3 onlyFigure 13.2 shows the program flow for this case. Figure 13.2. Program flow: Exception3 thrown on statement 3.
Since the inner try-catch block cannot handle Exception3 , it is propagated to the next enclosing try block. Note that the inner finally block (lines 25 “ 28) executes first before control leaves the inner block. The exception is caught on line 40, and the enclosing finally block executes after the exception is handled. Third case: statement 3 throws Exception1 and statement 5 throws Exception2Figure 13.3 shows the program flow. Figure 13.3. Two exceptions thrown.
This is a pretty interesting scenario. An exception is thrown within the inner catch block itself. (Some programmers do practice this deliberately when they want to propagate the exception 'outwards'. After catching an exception, and performing some initial handling, a more descriptive new exception is created and thrown out to be handled by a higher-level exception handler.) At line 18 (statement 5), note that when Exception2 is thrown it will no longer be handled by the inner catch block on line 21. Any exception thrown in lines 17 “ 28 will be propagated to the next enclosing try block for processing. Nevertheless, the inner finally block (lines 25 “ 28) will be executed first before control goes out to the next enclosing try block. 13.1.3 Exception example 3: user-defined exceptionHere is a more complex example showing how new user-defined exception objects are created and 'thrown back several levels'. 1: using System; 2: 3: class NotEnuffMoneyException:Exception{ 4: public float Debt; 5: public NotEnuffMoneyException(float debt){ 6: this.Debt = debt; 7: } 8: } 9: 10: class TestClass{ 11: public static void Main(){ 12: 13: try{ 14: CollectFood(); 15: } 16: catch (NotEnuffMoneyException e){ 17: Console.WriteLine(e.Message); 18: Console.WriteLine("Debt: $" + e.Debt); 19: } 20: } 21: 22: static void CollectFood(){ 23: PayForFood(); 24: } 25: 26: static void PayForFood(){ 27: throw new NotEnuffMoneyException(2.5f); 28: } 29: } Output: c:\expt>test Exception of type NotEnuffMoneyException was thrown. .5 A new exception class called NotEnuffMoneyException [3] is created (on lines 3 “ 8). Notice that NotEnuffMoneyException is a subclass of System.Exception . In C#, all exception classes must be subclasses of System.Exception , directly or indirectly. Main() calls CollectFood() , which in turn calls BuyFood() . BuyFood() throws a new NotEnuffMoneyException to CollectFood() . CollectFood() hasn't got the necessary exception handling mechanism to handle this, and so it automatically throws it backwards (or upwards) to Main() , where it is handled. [4]
Hopefully, the three exception examples above have 'warmed you up' a bit. There haven't really been any distinctive differences between C# and Java yet. I shall now discuss some general similarities first, followed by the differences. Like Java
Unlike Java
Compiler warning: test.cs(13,1): warning CS0168: The variable 'e' is declared but never used. In such cases, you can replace line 13 with 13: catch (Exception){ so that no unused local variable is declared. In contrast, Java insists that the local variable referring to the caught exception object be specified, regardless of whether it is used in the catch block.
|