/*
Two independent possibilities for try-catch blocks.
	1) try{...}-catch(...){...}-catch(...){...}-catch(...){...}-catch(...){...}...
	 -There may any number >=1 of catch blocks.  
	 -If an exception is thrown in the try block, excecution will start at the
	top (first) catch and try to match the type of exception thrown to the type 
	of exception in the catch() parameter.  ONLY the code for the first matching
	catch parameter will be run--all others will be ignored.
	 -If the exception is never matched, it will be passed on to the function that
	called the code containing the try-catch block, perhaps to be caught there
	 -If the exception is matched, it will only run the code in the matching 
	catch block and ignore all other catch blocks.  It will then either jump out
	of the try-catch block or skip to the finally block (if there is one)	

	2) try{...}-catch(...){...} 	vs.	 try{...}-catch(...){...}-finally{...}
	 -A finally block is optional. If written, it will be run whether an 
	exception is thrown and caught, thrown and uncaught, or not thrown.  
	The finally block does not have to written
** ==========================================================**
Here's a similar description, but in code form
	
try {
	
	//code to start running.
	//if an exception is not thrown, after last line in try-code is executed,
	//	will skip out of try-catch block or to finally code (if there is)
	//if an exception is thrown, 
	//	will stop running the try code and go to first matching catch() block
	//
	//Consider: if line 6 throws an exception, lines 7,8,9... will never be executed
	//
	
} catch (IOException ioe) { //does not have to be named ioe, may be named anything

	//code to run if somewhere in the try-block, an exception of
	//	type IOException (or a subclass of IOException) was thrown
 	//if code here us run, when done will go to finally block (if there is), or 
 	//	else exit out of try-catch block
 	 
} catch (Exception e) { //does not have to be e, may be named anything
	
	//code to run if both:
		-none of the above catch statements matches the exception type, and
		-this catch statement parameter matches the exception type
	//if code here is run, when done wil go to finally block (if there is), or 
	//	else exit out of try-catch block
	//
	//Consider: in this example, this code will be run if any type of Exception
	//	is thrown that is not an IOException or subclass of IOException
} finally {
	//the above finally statement and this code are optional.  This will get
	//	executed regardless of whether an exception was thrown and caught,
	//	thrown and uncaught, or whether no exception was thrown at all.
}

*/

import java.io.*; //needed for IoException

public class LearnExceptions {

	public static void main(String [] args) throws Exception {
		//RUN EACH OF THESE METHODS. The commenting explains the output for each
		noFinally(); //a try-catch block without a finally statement 
//		uncaughtFinally(); //finally code is executed for an uncaught exception
		multipleCatches(); //there can be multiple catch statement
		//multipleCatchesBadOrder(); //the order of catch statement is important	
	}

	//The finally statement is optional and need not be written
	public static void noFinally() {
		try {
			System.out.println("1");
			//here i call the constructor to create a new Exception object
			throw new Exception();  //Exceptions are objects too!
		} catch (Exception e) { //why does the exception get named 'e'?
			System.out.println("2");
			System.out.println("Exception I Caught was: " + e);//this is why!
		}	
	}

	//The compiler knows this Exception may not be caught, so it makes the
	//method header declare that uncaughtFinally() may throw an Exception 
	public static void uncaughtFinally() throws Exception {
		try {
			System.out.println("z");
			throw new Exception();  
		} catch (IOException ioe) { //IOException is a subclass of Exception
			System.out.println("y");
		} finally {
			System.out.println("x");
		}
	}

	//There can be any number >=1 of catch blocks
	//They should be written top down from most specific to most general
	public static void multipleCatches() {
		try {
			System.out.println("A");
			
			/***CHANGE THE ORDER OF THE LINES BELOW***/
			
			if (true) //make the compiler happy
				throw new Exception(); //if first, this will print AE
			if (true) //make the compiler happy
				throw new IOException(); //if first, this will print AB
			if (true) //make the compiler happy
				throw new NoSuchMethodException(); //if first, this will print AC
			
			/***CHANGE THE ORDER OF THE LINES ABOVE***/
			
		} catch (IOException ioe) {
			System.out.println("B");
		} catch (NoSuchMethodException nsme) {
			System.out.println("C");
		} catch (ArrayIndexOutOfBoundsException aioobe) {
			System.out.println("D");
		} catch (Throwable t) { //Throwable is the direct superclass of Exception
			System.out.println("E");
		}	
	}


/********* UNCOMMENT THE BELOW METHOD AND SEE THAT IT DOES NOT COMPILE *******/
/*
	//Catch statements should go from most specific (top)  to most general (bottom)
	//Here Throwable is the most general, so for any choice of throw ae will print
	public static void multipleCatchesBadOrder() {
		try {
			System.out.println("a");
			throw new IOException();
			//throw new NoSuchMethodException();
			//throw new ArrayIndexOutOfBoundsException();
		} catch (Throwable t) { //THROWABLE IS A SUPERCLASS OF IOEXCEPTION
			System.out.println("e"); //SO THIS CATCH() WILL ALWAYS MATCH
		} catch (IOException ioe) {
			System.out.println("b");
		} catch (NoSuchMethodException nsme) {
			System.out.println("e");
		} catch (ArrayIndexOutOfBoundsException aioobe) {
			System.out.println("d");
		}	
	}
*/


}