이 셋 중 가장 중점적으로 다루어질 에러는 Run-time 에러이다.
런타임 에러는 errors와 exceptions로 나누어진다.
자바는 에러와 예외를 클래스로 정의한다.
Throwable이라는 클래스의 subclass들이다. Throwable은 Object 클래스의 subclass이다.RuntimeException과 다른 예외 클래스로 나뉜다.RuntimeException: 주로 프로그래머의 실수(..)에 의해 발생한다.
위에서 예외는 관리할 수 있다고 언급했다. 예외를 관리함으로써, 프로그램은 무사히 실행을 계속할 수 있게 된다. 자바에서는 어떻게 예외를 관리할 수 있을까?
try-catch 블록을 사용함으로써 가능하다.try {
    // statements where exceptions can occur
} catch (Exception1 e1) {
    // statements that will be executed when Exception1 occurs
}
다음 코드는 예외를 발생시킬 수 있다.
public class example {
	public static void main(String[] args){
		int number = 100;
		int result = 0;
		for(int i=0; i<10; i++) {
		result = number / (int)(Math.random() * 10);
		System.out.println(result);
		}
	}
}
int(Math.random() * 10)은 0이 될 수도 있다.위 코드를 ArithmeticException을 다룰 수 있도록 바꿔 보자. 만약 나누는 수가 0이 되면 (그래서 예외가 발생하면), catch 블록이 실행된다. 프로그램은 실행을 계속할 수 있게 되는 것이다.
public class example {
	public static void main(String[] args) {
		int number = 100;
		int result = 0;
		for (int i = 0; i < 10; i++) {
			try {
				result = number / (int) (Math.random() * 10);
				System.out.println(result);
			} catch (ArithmeticException e) {
				System.out.println("0");
			}
		}
	}
}
catch 블록에 인자로 넘긴다.ArithmeticException이 발생하면 실행된다.Exception은 ArithmeticException의 superclass이다.public class example {
	public static void main(String[] args) {
		try {
			System.out.println(3);
			System.out.println(0 / 0); // ArithmeticException!
			System.out.println(4);
		} catch (Exception e) {
			System.out.println(5);
		}
	}
}
public class example {
	public static void main(String[] args) {
		try {
			System.out.println(3);
			System.out.println(0 / 0); // ArithmeticException!
			System.out.println(4);
		} catch (ArithmeticException e) {
			System.out.println("ArithmeticException occured!");
		} catch (Exception e2) {
			System.out.println("Exception occured!");
		}
	}
}
printStackTrace와 getMessage()는 디버깅에 유용한 메서드들이다.printStackTrace는 예외가 발생했을 때 콜 스택에 있던 메서드를 출력한다. 이 메서드를 catch 블록에서 명시적으로 호출하지 않아도 예외 발생시 출력된다. 단, catch 블록이 없는 채로 예외가 발생해서 이 메서드가 호출되면 프로그램은 그대로 중단된다. getMessage는 예외 인스턴스에 저장돼 있던 메시지를 가져온다.public class example {
	public static void main(String[] args) {
		try {
			System.out.println(3);
			System.out.println(0 / 0); // ArithmeticException!
			System.out.println(4);
		} catch (ArithmeticException ae) {
			ae.printStackTrace();
			System.out.println("exception message: " + ae.getMessage());
		}
	}
}
throw 키워드를 사용해서 의도적으로 예외를 만들 수 있다.throw 키워드를 사용해서 예외를 일으킬 수 있다.public class example {
	public static void main(String[] args) {
		try {
			Exception e = new Exception("I created the exception."); // becomes the exception message.
			throw e;
		} catch (Exception e) {
			System.out.println("exception message: " + e.getMessage());
			e.printStackTrace();
		}
		System.out.println("The program terminated normally.");
	}
}
public class example {
	public static void main(String[] args) {
		throw new Exception("My exception.");
	}
} // compile error
public class example {
	public static void main(String[] args) {
		throw new RuntimeException("My exception.");
	} 
} // no error
public class example {
	public static void main(String args[]) {
		method1();
	}
	static void method1() {
		method2(); // Error: must handle Exception or throw Exception.
	}
	static void method2() throws Exception {
		throw new Exception(); 
        // even if this exception is ArithmeticException(RuntimeException), since method2() 'throws Exception', caller must handle method2() or throw the exception itself
        // if this exception is ArithmeticException and doesn't 'throws Exception', there is no compile error.
	}
} // compile error
method1()이 throws Exception을 수행하면, 예외를 처리할 필요가 없어진다.method1()을 호출하는 main 메서드가 예외를 처리하거나 throw Exception을 수행해야 한다.public class example {
	public static void main(String args[]) {
		method1(); // Error: must handle Exception or throw Exception.
	}
	static void method1() throws Exception {
		method2();
	}
	static void method2() throws Exception {
		throw new Exception();
	}
} // compile error
throws Exception을 수행하면, 이 코드는 문제 없이 컴파일된다.throw Exception을 해도 그를 다뤄 줄 메서드가 존재하지 않는다!)public class example {
	public static void main(String args[]) throws Exception{
		method1();
	}
	static void method1() throws Exception {
		method2();
	}
	static void method2() throws Exception {
		throw new Exception();
	}
} // no error at compile time, but will cause program to crash at run time.
public class example {
	public static void main(String args[]) {
		method1();
	}
	static void method1() {
		try {
			method2();
		} catch (Exception e) {
			System.out.println("Exception handled in method1");
			e.printStackTrace();
		}
	}
	static void method2() throws Exception {
		throw new Exception();
	}
}
throws IOException을 적어 줬다.import java.io.FileOutputStream;
import java.io.IOException;
public class example {
	public static void main(String[] args) throws IOException {
		try {
			FileOutputStream output = new FileOutputStream("out.txt");
			String str = "hello world";
			byte[] bytes = str.getBytes();
			output.write(bytes);
			output.close();
		} catch (IOException io){
			System.out.println("IOException occured");
		}
	}
}
try {
	// statements that can cause exceptions.
} catch (Exception1 e1) {
	// statements for handling Exception1
} finally {
	// this block is executed whether or not an exception occurs in the try block.
	// this block must be placed at the end of a try-catch block.
}
return문이 try 블록에 있어도, 그 메서드가 반환되기 전에 finally 블록이 실행된다.public class example {
	public static void main(String args[]) {
		example.method1();
		System.out.println("returned to main method after calling method1.");
	}
	static void method1() {
		try {
			System.out.println("the try block of method 1 is being executed.");
			return;
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			System.out.println("the finally block of method 1 is being executed.");
		}
	}
}
import java.io.FileInputStream;
import java.io.IOException;
public class example {
	public static void main(String args[]) {
		byte[] b = new byte[1024];
		FileInputStream input = null;
		try {
			input = new FileInputStream("aaa.txt");
			input.read(b);
			System.out.println(new String(b));
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				input.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		System.out.println("The program exited normally.");
	}
}
위의 코드는 여러 try-catch 블록을 써야 해서 번거롭다.
try 이후 괄호에 리소스를 생성하는 문장을 넣는다.;)으로 나누어진 여러 문장을 쓸 수 있다.close() 메서드가 호출된다.close()는 catch 블록이나 finally 블록이 실행되기 전에 호출된다.import java.io.FileInputStream;
import java.io.IOException;
public class example {
	public static void main(String args[]) {
		byte[] b = new byte[1024];
		try (FileInputStream input = new FileInputStream("out.txt")) {
			input.read(b);
			System.out.println(new String(b));
		} catch (IOException e) {
			e.printStackTrace();
		}
		System.out.println("The program exited normally.");
	}
}
class MyException extends Exception {
    MyException(String msg) {
        super(msg); // calls constructor of class Exception
    }
}
class MyException extends Exception {
    private final int ERR_CODE;
    MyException(String msg, int errCode){
        super(msg); // calls constructor of class Exception
        ERR_CODE = errCode;
    }
    MyException(String msg){
        this(msg, 100) // calls overloaded contructor
    }
    public int getErrCode(){
        return ERR_CODE;
    }
}
class MyException extends Exception {
    MyException(String msg){
        super(msg); // calls constructor of class Exception
    }
}
public class example {
    public static void main(String args[]) {
        try{
            method1();
        } catch(MyException e) {
            System.out.println("exception msg: " + e.getMessage());
        }
    }
    
    static void method1() throws MyException {
        throw new MyException("throwing MyException!");
    }
}