import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

class MyArray {
	private int[] nums;

	public MyArray(int size) {
		nums = new int[size];
	}

	public void addElement(int index, int value) {
		try {
			nums[index] = value;
		} catch (ArrayIndexOutOfBoundsException e) {
			System.err.println("Invalid index " + index + " - " + e.getMessage());
		}

		// another alternative
		if (index < nums.length) {
			nums[index] = value;
		} else {
//			System.err.println("Invalid index " + 5);
			throw new ArrayIndexOutOfBoundsException(
					"Invalid index. Array size is " + nums.length + " and index is " + index);
			// exception thrown and must be handled in caller (main)
		}
	}
}

public class ExceptionExample {

	public static void main(String[] args) {

		MyArray myarray = new MyArray(5);
		myarray.addElement(0, 100);

		try {
//			myarray.addElement(4, 200);
			myarray.addElement(5, 200);
		} catch (Exception e) {
			System.err.println(e.getMessage());
		} finally {
			// always executed
			System.out.println("This is always gets executed: finally!");
		}

		// try-with-resource
		try (BufferedReader reader = new BufferedReader(new FileReader("test.txt"))) {
			// if file opened successfully
			// start reading the content

		} catch (ArrayIndexOutOfBoundsException | FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}

		// use the user-defined exceptions
		try {
			first();

			second();
			
			third();

		} catch (FirstException e) {
			e.printStackTrace();
		} catch (SecondException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	private static void first() throws FirstException {
		throw new FirstException("thrown from first");
	}

	private static void second() throws SecondException {
		throw new SecondException("thrown from second");
	}

//	private static void third() throws FirstException, SecondException {
	private static void third() throws Exception {
		boolean flag = true;
		if (flag) {
			throw new FirstException("thrown from first");
		} else {
			throw new SecondException("thrown from second");
		}

	}

}

// user-defined exception class
class FirstException extends Exception {
	private int num;
	private String msg = "FirstException";

	public FirstException(String msg) {
		this.msg = msg;
	}

	public FirstException(String msg, int num) {
		this.msg = msg;
		this.num = num;
	}
}

class SecondException extends Exception {
	private int num;
	private String msg = "SecondException";

	public SecondException(String msg) {
		this.msg = msg;
	}

	public SecondException(String msg, int num) {
		this.msg = msg;
		this.num = num;
	}
}
