[Java] 컬렉션 -2

최우형·2023년 3월 6일
1

Java

목록 보기
12/24
post-thumbnail

📌 예외처리

예외처리란 프로그램의 비정상적인 종료를 방지하고, 정상적인 실행 상태를 유지하기 위한 것

컴파일 에러(Compile Time Error)

컴파일 에러는 컴파일 할 때 발생하는 에러를 가리킨다.

public class ErrorTest {
    public static void main(String[] args) {
        int i;

        for (i= 1; i<= 5; i++ {
            System.out.println(i);
        }

    }
}

///오류
java: ')' expected

상대적으로 발견하기 쉽고, 어렵지 않게 해결할 수 있다.

런타임 에러(Run Time Error)

런타임 시에 발생하는 에러

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) 등이 있다.

예외 : 잘못된 사용 또는 코딩으로 인한 상대적으로 미약한 수준의 오류로서 코드 수정 등을 통해 수습이 가능한 오류를 자칭한다.

예외 클래스

일반 예외 클래스(Exception)

런타임 시 발생하는 RuntimeException 클래스와 그 하위 클래스를 제외한 모든 Exception 클래스와 그 하위 클래스들을 가리킨다.

컴파일러가 코드 실행 전에 예외 처리 코드 여부를 검사합나고 하여 checked 예외라 부르기도 한다.
ex) 잘못된 클래스명(ClassNotFoundException), 데이터 형식(DataFormatException)등 주로 사용자 편의 실수로 발생

실행 예외 클래스(Runtime Exception)

런타임 시 발생하는 RuntimeException 클래스와 그 하위클래스를 자칭한다.

컴파일러가 예외 처리 코드 여부를 검사하지 않는다는 의미에서 unchecked 예외라 부르기도 한다.
주로 개발자의 실수에 의해 발생, 자바 문법 요소와 관련이 있다.
ex) 클래스 간 형변환 오류(ClassCastException), 벗어난 배열 범위 지정(ArrayIndexOutOfBoundsException), 값이 null인 참조변수 사용(NullPointerException) 등이 있다.


try - catch 문

자바에서 예외 처리는 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)

예외처리를 할 수 있다

(1) 예외 발생

try 문 안에서 순차적으로 잘 실행되는 코드가 null값을 매개변수로 넘긴 printMyName 메서드 호출 부분에서 예외가 발생했다.

따라서 다음 코드라인인 printMyName("abc") 는 호출되지 않고 catch 문으로 넘어간다.

(2) 첫 번째 catch 문

발생한 예외는 NullPointerException인데, 예외는 ArithmenticException 이므로 예외처리가 되지 않고 그냥 지나간다.

(3) 두 번째 catch 문

발생한 예외와 일치하는 조건이므로 해당 catch 문의 코드블럭이 순차적으로 실행된다.

(4) finally 문

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("고의로 예외 발생시키기 성공!");
        }
    }
    
}

//출력값
고의로 예외 발생시키기 성공!
profile
프로젝트, 오류, CS 공부, 코테 등을 꾸준히 기록하는 저만의 기술 블로그입니다!

0개의 댓글