Notice
Recent Posts
Recent Comments
Link
«   2025/07   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
Archives
Today
Total
관리 메뉴

우주코딩

예외처리하기 Exception 본문

자바 본 강의

예외처리하기 Exception

우주코딩 2021. 9. 1. 16:55

호출자에게 예외 상황을 알리는 방법

리턴 값 사용하기



int compute(String op, int a, int b) {
return 숫자;
}

 

이 리턴 값을 통해 보통 결과로 리턴되지 않을 값을 사용하여 예외 상황을 알린다.

예) return -1211212121212121212211

그러나 그 리턴 값이 정상적인 계산 결과일 수 있다. 이것이 리턴 값을 이용하여 예외 상황을 알리는 방법의 한계이다.

예외 처리 문법의 등장 이유

  1. 리턴 값으로 예외상황을 알리는 방식의 한계 극복
  2. 예외가 발생하더라도 jvm을 멈추지 않게 만드는 것

유효하지 않은 연산자인 경우 throw 명령을 이용하여 호출자에게 오류 상황을 알린다.

 

throw new RuntimeException("해당 연산자를 지원하지 않습니다.");

try {

           예외를 던질 수도 있는 메서드를 호출할 때는 try 블록 안에서 호출한다

      } catch (RuntimeException e) {
     System.out.println(e.getMessage());
}

 

try 블록 안에서 메서드를 호출하다가 예외가 발생하면 catch 블록에서 파라미터로 받는다.

catch 문을 여러개 입력하여 여러 예외 상황을 받을 수 있다.

try {
...
...
} catch (InputMismatchException e) {
System.out.println("입력 값이 유효하지 않습니다.");
} catch (RuntimeException e) {
System.out.println(e.getMessage());
}

예외처리

예외를 호출자에게 알려주는 문법
throw [Throwable 객체];

throw new String("예외가 발생했습니다!"); // 컴파일 오류!

예외를 받았을 때 처리하는 문법

예외가 발생하면 catch 블록이 실행된다.
코드에서 던진 예외 객체는 catch의 파라미터가 받는다.
catch 블록에는 예외에 대한 적절한 조치를 수행하는 코드를 둔다.

 

예) 다음과 같이 예외가 발생된 이유를 간단히 출력할 수 있다.
System.out.println(e.getMessage());

예외 던지고 받기

main() 에서 test() 호출 , test() 가 m() 호출

 

m(){ throw new RunTimeException}


test() 에서 에외처리 하지 않으면 main() 으로 넘어감.

main() 메서드에서 try {} catch() {} 로 받는다.

만약 main() 마저도 예외처리를 안한다면 예외를 JVM 으로 넘긴다.

예외의 종류

Throwable -
Error - jvm 에서 발생
        개발자가 처리해서는 안됨
        간단한 조치 후 즉시 종료해야 한다.
예) 메모리 부족

 

 

Exception - 애플리케이션에서 발생
               개발자가 처리해야 한다
               적절한 조치 후 계속 실행
예) 입력 형식 오류

예외 받기

예외 처리 방법 1:

  • 예외를 처리하고 싶지 않다면 상위 호출자에게 책임을 떠넘길 수 있다.
public static void main(String[] args) throws Exception, RuntimeException, SQLException, IOException {

오류메서드()
}

컴파일 오류는 발생하지 않지만, main() 호출자는 JVM이고, JVM은 main()에서 던지 예외를 받는 순간 즉시 실행을 멈춘다.
그래서 main()의 호출자에게 책임을 떠넘기는 것은 바람직하지 않다.
main()은 예외 처리의 마지막 보루이다.
main()에서 마저 예외 처리를 하지 않으면 프로그램은 멈.춘.다!

 

예외 처리 방법 2:

  • try ~ catch 를 사용하여 코드 실행 중에 발생된 예외를 중간에 가로챈다.

try 블록에는 예외가 발생할 수 있는 코드를 둔다.

 

ry 블록에 있는 코드를 실행하는 중에예외가 발생하면, 그 예외 객체를 파라미터로 받을 수 있는 catch 문을 찾아 실행한다.
catch 블록에서 그 예외를 받아서 처리한다.
메서드가 던지는 예외 개수 만큼 catch 블록을 선언하면 된다.

or 연산자로 묶어서 처리할 수 있다 ^^


혹은 수퍼클래스인 Exception 클래스를 통해 처리할 수 있다.

가능한 Error 계열의 시스템 예외는 받지 마라
혹 받더라도 현재 프로그램을 종료하기 전에 필수적으로 수행해야하는 마무리 작업만 수행해라

즉 Error 의 수퍼클래스인 Throwable 클래스를 통해 예외를 받는 것도 안된다.

finally 블록

정상적으로 실행하든, 아니면 예외가 발생하여 catch 블록을 실행하든 finally 블록은 무조건 실행한다.
즉 try ~ catch ~ 블록을 나가기 전에 반드시 실행한다.
그래서 이 블록에는 try 에서 사용한 자원을 해제시키는 코드를 주로 둔다.
=> 자원 해제 코드를 둔다.
=> 자원? 파일, DB 커넥션, 소켓 커넥션, 대량의 메모리 등

스캐너 객체를 사용하여 키보드 입력을 읽는 중 예외가 발생한다면?

 

프로그램을 즉시 종료한다면, 스캐너를 다 사용하고 난 다음에 굳이 스캐너에 연결된 키보드와 연결을 끊을 필요는 없다.
JVM이 종료되면 OS는 JVM이 사용한 모든 자원을 자동으로 회수하기 때문에 굳이 close()를 호출하지 않아도 된다.

그러나 365일 24시간 내내 실행되는 시스템이라면, 키보드 입력을 사용하지 않는 동안에는 다른 프로그램에서 사용할 수 있도록 스캐너와 연결된 키보드를 풀어줘야 한다.

 

이것을 "자원해제"라고 부른다.

보통 자원해제시키는 메서드의 이름이 "close()"이다.
당연히 Scanner 클래스에도 자원을 해제시키는 close() 메서드가 있다.
그런데 우리는 지금까지 Scanner를 사용하면서 close()를 호출하지 않았다.

그 이유는 프로그램이 바로 종료되기 때문이다.
그러나 우리가 자바로 프로그램을 짤 영역은 서버쪽이다.
즉 365일 24시간 내내 실행되는 서버쪽 프로그램을 개발하는 것이기 때문에, 항상 자원을 사용한 후 해제시키는 것을 습관적으로 해야 한다.

keyScan.close();

문제는 close()를 호출하기 전에 예외가 발생한다면, 제대로 자원을 해제시키지도 못한다는 것이다.
이것을 해결하는 방법은 finally 블록을 사용하는 것이다.

try-with-resources

자원해제시키는 코드를 매번 finally 블록을 만들어 작성하기가 귀찮다!
=> try-with-resources 라는 문법을 사용하면 굳이 finally 블록에서 close()를 직접 호출할 필요가 없다. 자동으로 처리한다.

 문법
try (java.lang.AutoCloseable 구현체) {...}

단 java.lang.AutoCloseable 구현체에 대해서만 가능하다

RuntimeException

RuntimeException 계열의 예외를 던지는 메서드를 사용할 때는
그 호출 경로에 있는 모든 메서드에 굳이 throws 문장을 선언할 필요가 없다.
예외를 처리하고 싶은 곳에서 catch 블록으로 받아 처리하면 된다.
즉 중간에 끼어 있는 메서드를 만들 때 throws 문장을 선언하지 않아도 되기 때문에 편하다!
=> 스텔스처럼 조용히 예외를 전달한다.

Exception 클래스의 상속

예외 클래스를 상속 받는 클래스는 생성자가 호출될 때 그와 대응하는 수퍼 클래스의 생성자를 호출하는 일 외에는 다른 작업을 수행하지 않는다.
기능을 추가할 것도 아니면서 왜 RuntimeException을 상속 받았는가?
=> 이 클래스는 기존의 예외 클래스 기능을 확장하기 위함이 아니라, 의미있는 이름을 가진 예외 클래스를 만드는 것이 목적이다.
즉 예외가 발생했을 때 클래스이름으로 어떤 예외인지 쉽게 추측할 수 있도록 하기 위함이다.

예외가 발생되면 원본 예외를 그대로 던지지 말고, 예외를 직관적으로 알아볼 수 있는 예외 객체를 던진다.

Comments