예외처리란 프로그램의 비정상적인 종료를 방지하고, 정상적인 실행 상태를 유지하기 위한 것
컴파일 에러는 컴파일 할 때 발생하는 에러를 가리킨다.
public class ErrorTest {
public static void main(String[] args) {
int i;
for (i= 1; i<= 5; i++ {
System.out.println(i);
}
}
}
///오류
java: ')' expected
상대적으로 발견하기 쉽고, 어렵지 않게 해결할 수 있다.
런타임 시에 발생하는 에러
public class RuntimeErrorTest {
public static void main(String[] args) {
System.out.println(4 * 4);
System.out.println(4 / 0); // 예외 발생
}
}
//출력값
16
Exception in thread "main" java.lang.ArithmeticException: / by zero
at RuntimeErrorTest.main(RuntimeErrorTest.java:5)
겉보기에는 아무런 문제가 없지만 코드를 실행하면 ArithmenticException
예외가 발생한다.
참고로 ArithmenticException
은 특정 숫자를 0으로 나눴을 때 발생하는 예외이다.
에러 : 복구하기 어려운 수준의 심각한 오류를 의미, 대표적으로 메모리 부족(OutOfMemoryError)와 스택오버플로우(StackOverFlowError) 등이 있다.
예외 : 잘못된 사용 또는 코딩으로 인한 상대적으로 미약한 수준의 오류로서 코드 수정 등을 통해 수습이 가능한 오류를 자칭한다.
런타임 시 발생하는 RuntimeException
클래스와 그 하위 클래스를 제외한 모든 Exception
클래스와 그 하위 클래스들을 가리킨다.
컴파일러가 코드 실행 전에 예외 처리 코드 여부를 검사합나고 하여 checked 예외라 부르기도 한다.
ex) 잘못된 클래스명(ClassNotFoundException), 데이터 형식(DataFormatException)등 주로 사용자 편의 실수로 발생
런타임 시 발생하는 RuntimeException
클래스와 그 하위클래스를 자칭한다.
컴파일러가 예외 처리 코드 여부를 검사하지 않는다는 의미에서 unchecked 예외라 부르기도 한다.
주로 개발자의 실수에 의해 발생, 자바 문법 요소와 관련이 있다.
ex) 클래스 간 형변환 오류(ClassCastException), 벗어난 배열 범위 지정(ArrayIndexOutOfBoundsException), 값이 null인 참조변수 사용(NullPointerException) 등이 있다.
자바에서 예외 처리는 try - catch
블럭을 통해 구현이 가능하다.
try {
// 예외가 발생할 가능성이 있는 코드를 삽입
}
catch (ExceptionType1 e1) {
// ExceptionType1 유형의 예외 발생 시 실행할 코드
}
catch (ExceptionType2 e2) {
// ExceptionType2 유형의 예외 발생 시 실행할 코드
}
finally {
// finally 블럭은 옵셔널
// 예외 발생 여부와 상관없이 항상 실행
}
try
블럭 안에는 예외가 발생할 가능성이 있는 코드를 삽입한다.
만약 작성한 코드가 예외 없이 정상적으로 실행되면 catch
블럭은 실행되지 않고 finally
블럭이 실행된다.
finally
블럭은 필수로 포함되지 않아도 되지만, 포함된 경우에는 예외 발생 여부와 상관없이 항상 실핸된다.
catch
블럭은 예외가 발생하는 경우 실행되는 코드이다.
//예제
public class RuntimeExceptionTest {
public static void main(String[] args) {
System.out.println("[소문자 알파벳을 대문자로 출력하는 프로그램]");
printMyName("abc"); // (1)
printMyName(null); // (2) 넘겨주는 매개변수가 null인 경우 NullPointerException 발생
System.out.println("[프로그램 종료]");
}
static void printMyName(String str) {
String upperCaseAlphabet = str.toUpperCase();
System.out.println(upperCaseAlphabet);
}
}
//출력값
[소문자 알파벳을 대문자로 출력하는 프로그램]
ABC //(3) 정상 실행
Exception in thread "main" java.lang.NullPointerException // (4) 예외 발생!
at RuntimeExceptionTest.printMyName(RuntimeExceptionTest.java:11)
at RuntimeExceptionTest.main(RuntimeExceptionTest.java:6)
이렇게 에러가 난다.
try-catch
문을 사용하면
public class RuntimeExceptionTest {
public static void main(String[] args) {
try {
System.out.println("[소문자 알파벳을 대문자로 출력하는 프로그램]");
printMyName(null); // (1) 예외 발생
printMyName("abc"); // 이 코드는 실행되지 않고 catch 문으로 이동
}
catch (ArithmeticException e) {
System.out.println("ArithmeticException 발생!"); // (2) 첫 번째 catch문
}
catch (NullPointerException e) { // (3) 두 번째 catch문
System.out.println("NullPointerException 발생!");
System.out.println("e.getMessage: " + e.getMessage()); // (4) 예외 정보를 얻는 방법 - 1
System.out.println("e.toString: " + e.toString()); // (4) 예외 정보를 얻는 방법 - 2
e.printStackTrace(); // (4) 예외 정보를 얻는 방법 - 3
}
finally {
System.out.println("[프로그램 종료]"); // (5) finally문
}
}
static void printMyName(String str) {
String upperCaseAlphabet = str.toUpperCase();
System.out.println(upperCaseAlphabet);
}
}
// 출력값
[소문자 알파벳을 대문자로 출력하는 프로그램]
NullPointerException 발생!
e.getMessage: null
e.toString: java.lang.NullPointerException
[프로그램 종료]
java.lang.NullPointerException
at RuntimeExceptionTest.printMyName(RuntimeExceptionTest.java:20)
at RuntimeExceptionTest.main(RuntimeExceptionTest.java:7)
예외처리를 할 수 있다
try
문 안에서 순차적으로 잘 실행되는 코드가 null값을 매개변수로 넘긴 printMyName
메서드 호출 부분에서 예외가 발생했다.
따라서 다음 코드라인인 printMyName("abc")
는 호출되지 않고 catch
문으로 넘어간다.
발생한 예외는 NullPointerException
인데, 예외는 ArithmenticException
이므로 예외처리가 되지 않고 그냥 지나간다.
발생한 예외와 일치하는 조건이므로 해당 catch
문의 코드블럭이 순차적으로 실행된다.
finally
문은 예외 발생 여부와 관계없이 무조건 실행된다.
throws
키워드를 사용해서 예외를 호출한 곳으로 다시 예외를 떠넘긴다.
반환타입 메서드명(매개변수, ...) throws 예외클래스1, 예외클래스2, ... {
...생략...
}
예시
public class ThrowExceptionTest {
public static void main(String[] args) {
try {
throwException();
} catch (ClassNotFoundException e) {
System.out.println(e.getMessage());
}
}
static void throwException() throws ClassNotFoundException, NullPointerException {
Class.forName("java.lang.StringX");
}
}
//출력값
java.lang.StringX
위 코드에서 try-catch
문 안에서 thorowException
메서드가 호출되었지만 잘못된 코드 작성으로 인한 런타임 에러가 발생한다.
이런 경우 try-catch
문으로 다시 가서 예외처리를 한다.
throws
와 유사한 throw
키워드를 사용하면 의도적으로 예외를 발생시킬 수 있다.
public class ExceptionTest {
public static void main(String[] args) {
try {
Exception intendedException = new Exception("의도된 예외 만들기");
throw intendedException;
} catch (Exception e) {
System.out.println("고의로 예외 발생시키기 성공!");
}
}
}
//출력값
고의로 예외 발생시키기 성공!