위로
아래
예외처리
잘못된 값 입력 등으로 프로그램이 비정상 종료되지 않도록, 미리 조건을 걸어주는 것.
오류 (error)
- 컴파일 에러(compile error) : 문법적 오류가 있어서 컴파일 과정에서 에러가 나는 경우
- 런타임 에러 (runtime error) : 문법적 오류는 없는데 사용자의 입력에 따라 에러가 나는 경우
- 예측 불가능한 에러 (시스템 에러) : 메모리 부족, 운영체제 에러 등의 경우
- 예측 가능한 에러 : 예측 가능한 런타임 에러를 '예외'라고 부른다.
예외 (exception)
- 예측 가능한 런타임 에러.
- java.lang 패키지에 있는 Throwable 클래스의 자식 객체
- 컴파일러는 일반 예외만 잡아준다. 실행예외는 개발자가 코드로 잡아주어야 한다.
예외 종류
실행 예외(unckecked exception)
예외처리를 하지 않아도 컴파일할 수 있는 비검사형 예외
- ArithmeticException : 0으로 나누기와 같은 부적절한 산술 연산을 수행할 때 발생
- ArrayIndexOutOfBoundsException : 배열에서 인덱스 범위를 초과할 때 발생
- NullPointerException : null값을 가진 참조 변수에 접근할 때 발생
- NumberFormatException : 숫자로 바꿀 수 없는 문자열을 숫자로 변환하려할 때 발생
- IllegalArgumentException : 메서드에 부적절한 매개변수를 전달할 때 발생
- IndexOutOfBoundException : 배열에서 범위를 벗어난 인덱스를 사용할 때 발생
- NoSuchElementException : 요구한 요소가 없을 때 발생
일반 예외(checked exception)
예외처리를 하지 않으면 컴파일 오류가 발생하는 검사형 예외
- ClassNotFoundException : 존재하지 않는 클래스를 사용하려할 때 발생
- InterruptedException : 인터럽트 되었을 때 발생
- NoSuchFieldException : 클래스가 명시한 빌드를 포함하지 않을 때 발생
- CoSuchMethodException : 클래스가 명시한 메소드를 포함하지 않을 때 발생
- IOException : 데이터 읽기 쓰기 같은 입출력 문제가 있을 때 발생
risk
- 에러가 날 위험이 있는 코드는 리스크가 있다고 한다.
- 리스크는 미연에 방지할 수 있기 때문에, 리스크가 있는 코드는 좋지 않다.
실행 예외 예시
더보기
import java.util.StringTokenizer;
public class Unchecked1Demo {
public static void main(String[]args) {
String s = "Time is money";
StringTokenizer st = new StringTokenizer(s);
while(st.hasMoreTokens()) {
System.out.println(st.nextToken());
}
System.out.println(st.nextToken()); // 더이상 나올 토크이 없는데 토큰 호출
}
}
public class Unchecked2Demo {
public static void main(String[]args) {
int[] arr = {0,1,2};
System.out.println(arr[3]); // 존재하지 않는 인덱스의 배열 호출
}
}
일반 예외 예시
더보기
public class CheckedDemo {
public static void main(String[]args) {
Thread.sleep(100); // 아예 컴파일이 안 됨
}
}
Try~catch문
Try{
예외가 발생할 수 있는 실행문;
} catch (예외클래스1 | 예외클래스2 참조변수){
핸들러;
} finally {
예외 발생 여부와 관계 없이 수행할 실행문;
}
- 예외 객체를 이용
- 핸들러 : catch 블록에 포함된 예외 처리 코드
- 더 상위의 예외 객체일 경우 더 밑으로 가야한다.
Throwable 클래스의 메소드
getMessage() // Throwable 객체의 자세한 메시지를 반환
toString() // Throwable 객체의 간단한 베시지를 반환
printStackTrace() // Throwable 객체와 추적 정보를 화면에 출력
예시
더보기
public class TryCatch1Demo {
public static void main(String[]agrs) {
int[] arr = {0,1,2};
try {
System.out.println("배열의 첫번째 원소 : " + arr[0]);
System.out.println("배열의 마지막 원소 : " + arr[3]);
System.out.println("배열의 중간 원소 : " + arr[1]); // 위에서 예외가 발생해서 실행되지 않는다.
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("원소가 존재하지 않습니다.");
}finally {
System.out.println("어이쿠!");
}
}
}
public class TryCatch2Demo {
public static void main(String[] args) {
int dividend = 10;
try {
int divisor = Integer.parseInt(args[0]);
System.out.println(dividend / divisor); // 10을 args에 입력받은 숫자로 나누기
} catch (ArrayIndexOutOfBoundsException e) { // args에 아무것도 입력하지 않았을 경우
System.out.println("원소가 존재하지 않습니다.");
} catch (NumberFormatException e) { // args에 문자를 넣었을 경우
System.out.println("숫자가 아닙니다.");
} catch (ArithmeticException e) { // args에 0을 넣었을 경우
System.out.println("0으로 나눌 수 없습니다.");
} catch (Exception e) { // 최상위 예외 객체라 맨 밑으로 와야 한다.
System.out.println("몰라"+e.getMessage());
} finally { // 예외 유무와 상과 없이 실행
System.out.println("항상 실행됩니다.");
}
System.out.println("종료.");
}
}
Try ~ with ~ resource문
try (자원) {
} catch (...) {
}
- try 블록에서 자원을 사용했다면, try 블록 실행 후 자원을 닫아주어야 메모리 낭비가 없다.
- 자바 7부터는, 자원에 AutoCloseable 인터페이스를 구현시키면, 예외 발생 여부와 상관 없이 자동으로 닫아준다.
예시
더보기
public class TryCatch4Demo {
public static void main(String[] args) {
Resource resource = new Resource();
try(resource){
resource.show();
} catch (Exception e) {
System.out.println("예외 처리");
}
}
}
class Resource implements AutoCloseable {
void show() {
System.out.println("자원 사용");
}
public void close() throws Exception {
System.out.println("자원 닫기");
}
}
throws 문
throws
- 예외를 상위 코드 블록으로 양도해서 떠넘긴다
- 예외를 한 곳에 다 몰아놓고 한 번에 해결하도록 할 수 있다
- 하위 메소드가 상위로 떠넘겨서 main 메소드를 넘어 JVM까지 떠넘긴다.
예시
더보기
import java.util.Scanner;
public class ThrowsDemo {
public static void main(String[] args) {
Scanner in = new Scanner (System.in);
System.out.print("정수 입력 : ");
try {
square(in.nextLine());
} catch(NumberFormatException e) {
System.out.println("정수가 아닙니다.");
}
}
private static void square(String s) throws NumberFormatException {
// 예외가 발생하면 자신을 호출한 곳으로 예외 처리를 떠넘긴다.
// throws 문이 없었다면 여기서 try catch문을 사용했어야 했다. 그럼 코드가 지저분해진다.
int n = Integer.parseInt(s);
System.out.println(n*n);
}
}