이 셋 중 가장 중점적으로 다루어질 에러는 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!");
}
}