270 likes | 407 Views
Tirgul 2 Notes. This tirgul will have two parts: In the first part we’ll give some examples for asymptotic analysis. In the second part we’ll talk about error handling in Java. Definitions (reminder). ( Big - O ) We say that if there exists a constant c>0 and some n0 such that for all n>n0,
E N D
Tirgul 2 Notes • This tirgul will have two parts: • In the first part we’ll give some examples for asymptotic analysis. • In the second part we’ll talk about error handling in Java
Definitions (reminder) • ( Big - O ) We say thatif there exists a constant c>0 and some n0 such that for all n>n0, • (Big - Omega) We say thatif there exists a constant c>0 and some n0 such that for all n>n0, • (Big - Theta) We say thatif there exists constants c1, c2 > 0 and some n0 such that for all n>n0,
Example 1 (2-4-e. in Cormen) • Claim: If (for n>n0)then • Proof: Take . Thus for n>n0, • Note that if there is no such for f(n) then the claim is not necessarily true: take for example f(n) = 1/n. For any constant c, if we take n>c then f(n) > c (f(n))2
Example 2 (2-4-d. in Cormen) • Does imply that • Answer: No. For example, Then,but: for any constant c.
Summations - example 1 • (from Cormen, ex. 3.2-2., page 52)(note how we “got rid” of the integer rounding) • Note that the first term is n so the sum is greater than n, so the term is also • It’s an example how the largest item dominates the growth of the term in an exponential decrease/increase.
Bounding the sum - example 2 • (from Cormen, ex. 3.1-a., page 52) • (r is a constant) :(note that ) , and also: • Note: if n is odd then we should change a bit: • Thus
Recurrences • Example: the running time of the “Towers of Hanoi” algorithm. • Reminder: (moving k disks from pole s to pole t with a middle pole m) H(s, t, m, k) { H(s, m, t, k-1) moveDisk(s, t) H(m, t, s, k-1) } • The recurrence: h(n) = 2h(n-1) + 1 h(1) = 1
Step 1: guessing the solution • h(n) = 2h(n-1) + 1 = 2[2h(n-2)+1] + 1 = 4h(n-2) + 3 = 4[2h(n-3)+1] + 3 = 8h(n-3) + 7 • So we can “guess” that if doing it k times we will get h(n)=2k h(n-k) + (2k - 1) • Now take k=n-1. We’ll get:h(n) = 2n-1 h(n-(n-1)) + 2n-1 - 1 = 2n - 1
Step 2: proving by induction • If we guessed right, it will be easy to prove by induction: (for n=1 it is easy to check)Suppose h(n-1) = 2n-1 - 1. Then,h(n) = 2h(n-1) + 1 = 2(2n-1 - 1) + 1 = 2n -2 + 1 = 2n -1
Making a good guess • We have to give a precise guess in order for the induction to work ( h(n) = 2n - 1, and not just h(n)=O(2n) or h(n)=2n). • For example, consider the recurrence T(n) = 2 T(n/2) + 1 • We can check that T(n) = 2T(n/2) + 1 = 2 (2T(n/4) + 1) + 1 = 4T(n/4) + 3 = 4(2T(n/8) + 1) +3 = 8T(n/8) + 7 • So we can guess: T(n) = k T(n/k)+(k-1) = n T(1)+n-1=2n-1, but if we are tempted at the beginning just to guess T(n)<= c n it won’t work: by induction T(n/2) <= c(n/2) and we tryT(n) = 2T(n/2) + 1 = c n + 1 > c n, and the proof is incorrect! • We can, however, shorten the calculation and guess at the beginning T(n) <= c n - b. Now the induction will beT(n) <= 2 (c(n/2) - b) + 1 = c n - 2b + 1 <= c n - b(when b>=1) and this is correct.
Another possible mistake • It is also wrong to prove T(n)=O(n) by guessing T(n) <= c n and doing:T(n) = 2T(n/2) + 1 <= 2 ( c(n/2) ) + 1 == c n + 1 = O(n) ===> The last step is not in place. The induction step has to be precise, so we have to prove thatT(n) <= c n, which is not what is shown!
Recursion Trees • For each level we write the time added due to this level (in Hanoi, each call to h() adds one operation and the recursion). Thus the total is:
Error handling - Exceptions • Exceptions are a mean of flow-control in the program. The basic structure is:try {…..} catch (MyException e) {handle the exception ...} • When an exception occurs in the try{} block , the flow control in the try block is terminated. Then, if it is of type MyException then the flow control switches to the catch{} block and after that continues as normal, otherwise the flow control terminates the execution in this method and “looks for” an appropriate catch{} block (until reaching main). • “try”, “catch”, and “throw” are reserved words in the language. You can only throw objects that extends the base class java.lang.Throwable. • What is “thrown” and caught is basically an instance of an exception class initialized somewhere (where it was first created) by:“throw new MyException(); “
Exceptions - advantages • So why are they useful to us ? Actually exceptions are a great feature which can help you handle problems (exceptions ….) in the ordinary run of your program elegantly (as long as you use it correctly and don’t over use it..) • The basic mechanism enables the programmer to carry the exception up the calling methods and different modules (“bubble up”) automatically, till it reaches the part in the program the programmer thinks should handle such problems and then catch it. As it is an object, the throwing method or module can include in it relevant information. This is much more elegant and efficient than using many return values. • It also enables the programmer to catch several exceptions together in the right place and to use their inheritance (Note the catch clause will catch any object that extends what it explicitly caught, that’s why ‘catch (Exception e)’ will catch ANY exception .
Example • Catching many exceptions:void readInput() { try { // call several kinds of methods for reading the input... // may throw several exceptions - FileNotFound, EOF, etc. } catch (IOException ioe) { System.err.println(“Caught exception” + ioe) }(note that here what is called is ioe.toString() which prints lots of details. We should actually use ioe.getMessage() - we discuss it below). • Bubble up exception:String readInputLine() throws IOException { // read a line from input. Doesn’t care if an exception occurs...}
Exceptions - misuse • Exceptions should handle some error in the program , not some ordinary possible return value of a method - don’t overuse it ! (it’s also much less efficient). • Don’t declare too many new exception classes. In many cases (IF you need an exception, for your new data structure for example), you should use the ones Java already gave you that are just what you need - like ArrayIndexOutOfBoundsException , IOException , and last but not least IllegalArgumentException. • Don’t use very small try{} blocks - aggregate relevant commands.
Example • Not good: void readInput() { InputBuffer buf; try {buf=getNextInput()} catch (IOException e) {...} try{buf.handleInput()} catch (MyException e) {...} try {buf.printOutput()} catch (IOException e) {...} • Good: void readInput() { InputBuffer buf; try { buf=getNextInput(); buf.handleInput(); buf.printOutput() } catch (IOException e) {...} catch (MyException e) {...}
Exceptions -the inheritance tree structure • We can “throw” any object of a class extending the base class java.lang.Throwable. This class has two direct subclasses: java.lang.Error and java.lang.Exception. • Every run-time error is identified by a class that is either a subclass of Error or of Exception. The distinction is not very strict: • Error refer to run-time errors that are rooted in the execution environment and are not in the hands of the application programmer. • Exception refer to all other run-time errors. The application programmer is responsible that all exceptions will be handled. • The application you write must handle all Exceptions but ignore Errors.
Exception - java.lang.Error • If an Error occurs you should let it crash the application. The user will be notified for the error and act accordingly (buy more memory, reinstall the application, call tech support ...) • Examples: • java.lang.InternalError - signals an error caused by an implementation bug in the JVM in which the application is running. • java.lang.OutOfMemory - signals that the application ran out of memory. • java.lang.ClassFormatError - Thrown when the Java Virtual Machine attempts to read a class file and determines that the file is malformed or otherwise cannot be interpreted as a class file.
Exceptions - java.lang.Exception • Examples for Exceptions: • java.lang.ArithmeticException - occurs when you divide an integer by 0. The exception is rooted in the logic of the application, hence it is the programmer responsibility to handle it. • java.io.FileNotFoundException - occurs when the application tries to access a file which does not exist. Again the programmer should treat this. • Class Exception has a special subclass named RuntimeException, which makes further classification of exceptions: runtime-exceptions and regular exceptions (The name RuntimeException is confusing. Every exception and Error occurs during the run-time of the application.) • RuntimeException is characterized as follows: The programmer could avoid the occurrence of the exception (not the environment fault) - this type of exceptions should not occur normally ( a bug in the program… )
Exceptions - RuntimeException (cont.) • A programmer need not explicitly catch a RuntimeException nor to declare it is thrown by a method. • Still, the programmer has the ability to catch those exceptions (e.g., for debugging purposes) and program execution will cease if they occur • examples of run time exceptions: • java.lang.IllegalArgumentException - Passing an illegal argument to a method. Example: Math.pow(0,0) • java.lang.ArithmeticException - Division by zero • java.lang.StringIndexOutOfBoundsException , java.lang.ArrayIndexOutOfBoundsException • java.lang.NullPointerException ,java.lang.NegativeArraySizeException • java.util.EmptyStackException , java.lang.SecurityException
Exceptions - non run-time exceptions • A method must declare all the non run-time exceptions it may throw, using throws keyword . • When you use a non runtime exception, in every method throwing an exception AND in every method in your code calling such a method you MUST do one of the two: either declare that this method throws this exception (when you have no intention of dealing with it at that level), or use a try-catch clause on it ,to handle it. If you throw it all the way up the call stack without handling it , it acts just like an uncaught runtime exception and exits the program. You can also use both ways (catch and throw again for example). • Class exception has a string data member that can be set in the constructor and give description of the problem. This string can be retrieved using the method getMessage() (inherited from Throwable). You should this mechanism. • From Throwable any exception has a method called printStackTrace() which prints the stack of all the methods calls the exception went up through. This is printed (to stderr) automatically for the exception when its not caught and exits the program.
Example • Avoid run time exceptions: Suppose you have an instance l of class myList. Don’t do: try{ n = l.getNextElement()} catch(EmptylistException e) {...}but instead: if ( ! l.isEmpty() ) {x = l.getNextElement()} • Don’t ignore non-runtime exceptions: try { lot’s of I/O code... } catch (Exception e) {} //doing nothing....Instead at least print error message try { lot’s of I/O code... } catch (Exception e) { System.err.println(“Got exception” + e.getMessage()) }
(2) example • Declaring a new exception and using the string data member:class MyException extends Exception { public MyException{}; //Empty constructor public MyException(String errorMsg) { super(errorMsg); }}method createException throws MyException { throw new MyException(“Just a test...”);}and in a catch block somewhere:catch (MyException e) {System.err.println(e.getMessage());}
Exceptions - few more points • The user of the method is warned against possible (non-runtime) exceptions this method can throw. This is part of the interface of a method. • The exceptions that might be thrown by a method should also be documented with the @exception tag. • You can decide sometimes that a method will throw a RuntimeException (for example when implementing a stack). In this case it is not necessary to declare the method as throws this exception, but you should document the exception. This signals the user of this class to be aware from such bugs. • When should you declare and when should you catch the exception within the method? - Design issue! • It goes without saying that you may (and should) declare your own exceptions according to the standard classification (again, only if you need some meaningful name, or a different data member, etc.)
Finally • Finally is part of the try-catch - finally control flow. Actually try block is good for any block of code with a “jump” control flow as break ; continue;return; or an exception. • Finally {……} is a block of code which will be executed in any way: in normal execution after the try{….}. Before it ended , if in the try clause the flow came to a break; or return; the finally will first be executed and only then the control will return to this point. If an exception occurred and was caught in the catch{..} clause the finally{..} clause will be entered after the catch is done. If the exception was not caught than the finally will be executed after it was thrown, and only than will the exception “bubble up”. • Note that if you give a different control flow in the finally clause , the former one will be discarded (if you do a return from it for example). • Finally is useful for “cleaning up” tasks such as close() for streams , flush() and such.
Example • void doStuff () throws MyException { try { //open output file // do stuf... } catch (IOException e) { // handle IO problems } finally { // close output file }Notice that the code in the finally block will be done in any case; if there was no exception, if there was an IOException (that was caught), and if there was a MyException (that is bubbled up and not caught).