Chapter 14 예외 처리

Ruinak·2021년 6월 16일
0

Java

목록 보기
14/15
post-thumbnail

14-1 예외 클래스

오류란 무엇인가요?

  • 프로그램에서 오류가 발생하는 상환은 두 가지
    1) 프로그램 코드 작성 중 실수로 발생하는 컴파일 오류(compile error)
    2) 실행중인 프로그램이 의도하지 않은 동작을 하거나 프로그램이 중지되는 실행 오류(runtime error)
  • 실행 오류 중 프로그램을 잘못 구현하여 의도한 바와 다르게 실행되어 생기는 오류를 버그(bug)라고 함
  • 컴파일 오류는 개발 환경에서 대부분 원인을 알 수 있음
  • 발생한 컴파일 오류를 모두 수정해야 프로그램이 정상적으로 실행되므로 문법적으로 오류가 있다는 것을 바로 알 수 있음
  • 프로그램 실행 중에 발생하는 오류는 예측하기 어려운 경우가 많고, 프로그램이 비정상 종료되면서 갑자기 멈춰 버림
  • 실제 서비스를 제공하고 있는 프로그램의 경우 오류가 생기면 문제가 심각해지므로(서비스가 중지됨) 로그(log) 분석을 통해 원인을 찾을 수 있도록 프로그램을 개발할 때 로그를 정확하게 남기는 것이 중요함

    로그(log)란 소프트웨어 실행 중에 발생하는 여러 상황을 기록한 내용으로서 주로 파일에 기록합니다. 이 파일을 로그 파일(log file)이라고 합니다.

  • 자바는 이러한 비정상 종료를 최대한 줄이기 위해 다양한 예외에 대한 처리 방법을 가지고 있음
  • 예외 처리를 하는 목적은 일단 프로그램이 비정상 종료되는 것을 방지하기 위한 것임
  • 예외가 발생했을 때 로그를 남겨 두면 예외 상황을 파악하고 버그를 수정하는데 도움을 받을 수 있음

오류와 예외

  • 실행 오류 는 크게 두가지가 있음
    1) 자바 가상 머신에서 발생하는 시스템 오류(error)
    - 예로 사용 가능한 동적 메모리가 없는 경우나 스택 메모리의 오버 플로가 발생한 경우 등
    - 이러한 시스템 오류는 프로그램에서 제어할 수 없음
    2) 예외(exception)
    - 프로그램에서 제어할 수 있음
  • Error와 Exception을 오류 클래스라고 함
  • 오류 클래스는 모두 Throwable 클래스에서 상속 받음
  • Error 클래스의 하위 클래스는 시스템에서 발생하는 오류를 다루며 프로그램에서 제어하지 않음
  • 프로그램에서 제어하는 부분은 Exception 클래스와 그 하위에 있는 예외 클래스임

에외 클래스의 종류

  • 프로그램에서 처리하는 예외 클래스의 최상위 클래스는 Exception 클래스임

Exception 하위 클래스

  • IOException(입출력 예외 처리)
    • FileNotFountException
    • Soket Exception
  • RuntimeException(실행 오류 예외 처리)
    • ArithmeticException
    • IndexOutofBoundsException
  • Exception 클래스 하위에는 이외에도 많은 클래스가 있음
  • IOException 클래스는 입출력에 대한 예외를 처리하고, RuntimeException는 프로그램 실행 중 발생할 수 있는 오류에 대한 예외를 처리함
  • 이클리스 같은 개발 환경에서는 예외가 발생하면 대부분 처리하라는 컴파일 오류 메세지를 띄움
    - try-catch문을 사용하여 예외 처리를 해야함
  • Exception 하위 클래스중 RuntimeException은 try-catch문을 사용하여 예외 처리를 하지 않아도 컴파일 오류가 나지 않음
    - 이러한 컴파일러에 의해 체크되지 않는 예외는 프로그래머가 알아서 처리해야 하므로 주의해야 함

14-2 예외 처리하기

try-catch문

  • try-catch문의 형식
  • try 블럭에는 예외가 발생할 가능성이 있는 코드를 작성함
  • try 블럭 안에서 예외가 발생하면 바로 catch 블럭이 수행됨
  • catch문의 괄호 ( ) 안에 쓰는 예외 타입은 예외 상황에 따라 달라짐

try-catch문 사용하기

  • 다음은 요소가 5개인 정수형 배열을 만들고 요소에 0부터 4를 대입하는 코드
  • 배열 크기가 5개 이므로 정수 값을 5개 저장할 수 있음
  • 여기서 i < 5를 i<=5로 바꿔보겠음
  • 변경한 코드는 0부터 까지 총 6개 숫자를 넣기 때문에 아래와 같은 예외상황이 발생
  • 배열에 저장하려는 값의 개수가 배열 범위를 벗어났기 때문에 예외가 발생한 것임
  • 예외가 발생한 순간 프로그램이 비정상 종료되지 않도록 예외 처리를 해주어야 함

예제 14-1 try-catch문 사용하기

  • 배열 범위가 유효한 값 4까지는 배열에 저장되어 출력되고 그다음 값을 배열에 넣으려 할때 예외가 발생함
  • 발생한 예외는 catch 블럭에서 처리하므로 System.out.println("프로그램 종료") 문장까지 수행되하고 프로그램이 정상 종료 됨
  • 예외가 발생하여 프로그램이 바로 비정상 종료되었다면 System.out.println("프로그램 종료") 문장을 수행할 수 없음
  • 예외처리는 프로그램이 비정상 종료되는 것을 방지할 수 있으므로 매우 중요함

컴파일러에 의해 예외가 체크되는 경우

  • 위에서 살펴본 예제는 예외 처리 하지 않아도 컴파일 오류가 나지 않지만, 자바에서 제공하는 많은 예외 클래스들은 컴파일러에 의해 처리됨
    - 이런 경우 자바에서는 예외 처리를 하지 않으면 컴파일 오류가 계속 남음

파일 입출력에서 발생하는 예외 처리하기

  • 자바에서 파일을 읽고 쓰는 데 스트림(stream) 객체를 사용함
  • 스트림 종류는 여러가지가 있지만, 여기에서는 파일에서 데이터를 바이트 단위로 읽어 들이는 FileInputStream을 사용함
  • 지금까지 클래스를 생성할 때 사용하던 코드와 다르지 않음
  • 위 코드는 a.txt 파일에서 데이터를 읽어 들이기 위해 스트림 객체를 생성한다는 의미임
  • new FileInputStream("a.txt"); 부분에 오류가 발생함
  • 'FileNotFoundException이 처리되지 않았다'는 메세지가 나타나고 두 옵션 중 하나를 선택하라고 되어 있음
  • 위 코드는 a.txt 파일을 열어 읽으려고 FileInputStream 클래스를 생성한 경우인데, 이 경우 a.txt 파일이 존재하지 않는 오류가 발생할 수 있다는 것임
  • 읽으려는 파일이 없는 경우에 자바 가상 머신에서는 FileNotFoundException 예외 클래스가 생성됨
    - 따라서 이러한 예외 상황에 대비한 예외 처리를 해야 한다는 뜻임
  • try-catch문으로 감싼다는 뜻인 Surrond with try/catch를 클릭함
  • 예외가 발생할 위험이 있는 코드가 try 블럭으로 감싸짐
  • try 블럭이 먼저 수행되고, 이 코드에서 예외가 발생하면 catch 블럭을 수행함
  • try문으로 감싸진 부분에서 발생할 수 있는 예외는 FileNotFoundException이고 변수 이름 e로 선언됨
  • 어디에서 예외가 발생했는지 따라 가는 printStackTrace( ) 메서드가 호출된 것을 알 수 있음
  • a.txt 파일이 없으므로 당연히 아래처럼 예외가 발생할 것임
  • 결과 화면에서 그린박스 안에 ExceptionHandling1.java:10를 클릭해보면 예외가 발생한 코드 위치로 이동함

예제 14-2 try-catch문 사용하기

  • 예외가 발생했을 때 FileNotFoundException e의 toString( ) 메서드가 호출되도록 코드를 작성해 봄
  • 출력 결과를 보면 첫 번째 줄은 e의 출력 내용임
  • 두번째 줄이 줄력되었으므로 예외 처리 후에도 프로그램이 계속 수행되었음을 알 수 있음
  • 예외 처리를 한다고 프로그램의 예외 상황 자체를 막을 수는 없음
  • 예외 처리를 하면 예외 상황을 알려주는 메세지를 볼 수 있고, 프로그램이 비정상 종료되지 않고 계속 수행되도록 만들 수 있음

try-catch-finally문

  • 프로그램에서 사용한 리소스는 프로그램이 종료되면 자동으로 해제됨
    - 예로 네트워크가 연결되었을 경우에 채팅 프로그램이 종료될 때 연결도 닫힘

    리소스(resource)란 시스템에서 사용하는 자원을 말합니다. 예를 들어 파일이나, 네트워크, 데이터베이스 연결 등이 리소스에 해당합니다.

  • 끝나지 않고 계속 수행되는 서비스 같은 경우에 리소스를 여러번 반복해서 열기만 하고 닫지 않는다면 문제가 발생함
  • 시스템에서 허용하는 자원은 한계가 있기 때문임
  • 사용한 시스템 리소스는 사용 후 반드시 close( ) 메서드로 닫아주어야 함
  • try-catch-finally문의 형식
  • try 블럭이 수행되면 finally 블럭은 어떤 경우에도 반드시 수행됨
    - 이를테면 try나 catch문에 return문이 있어도 수행됨
  • 따라서 try-catch-catch 각 블럭마다 리소스를 해제하지 않고 finally 블럭에서 한 번만 해제해주면 됨

예제 14-3 finally 블럭 사용하기

  • 입력받은 파일이 없는 경우에 대해 try-catch문을 사용해 FileNotFoundException 예외 처리를 함
  • 프로그램을 실행하면 a.txt 파일이 없으므로 예외가 발생하여 catch 블럭이 실행될 것임
  • 강제로 return을 해도 return문과 상관없이 finally 블럭이 수행되어 '항상 수행됩니다.' 문장이 출력됨

try-with-resources문

  • 시스템 리소스를 사용하고 해제하는 코드는 다소 복잡함
  • 자바 7부터 try-with-resources문을 제공하여 close( ) 메서드를 명시적으로 호출하지 않아도 try 블럭 내에서 열린 리소스를 자동으로 닫도록 만들 수 있음
  • try-with-resources 문법을 사용하려면 해당 리소스가 AutoCloseable 인터페이스를 구현해야 함
  • AutoCloseable 인터페이스에는 close( ) 메서드가 있고 이를 구현한 클래스는 close를 명시적으로 호출하지 않아도 close( ) 메서드 부분이 호출됨
  • FileInputStream 클래스는 Closeable과 AutoCloseable 인터페이스를 구현했음
    - 자바 7부터는 try-with-resources 문법을 사용하면 FileInputStream을 사용할 때 close( )를 명시적으로 호출하지 않아도 정상인 경우와 예외가 발생한 경우 모두 close( ) 메서드가 호출됨
  • FileInputStream 이외에 네트워크(socket)와 데이터베이스(connection) 관련 클래스도 AutoCloseable 인터페이스를 구현하고 있음

AutoCloseable 인터페이스

예제 14-4 AutoCloseable 인터페이스 구현하기

  • AutoCloseable 인터페이스는 반드시 close( ) 메서드를 구현해야 함
  • 시스템 리소스인 경우에는 파일 스트림을 닫거나 네트워크 연결을 해제하는 코드를 작성해야겠지만, 여기서는 close( ) 메서드가 제대로 호출되는지 알아보기 위해 출력문만 남김

14-5 try-with-resources문 사용하기(1)

  • try-with-resources문을 사용할 때 try문의 괄호 ( ) 안에 리소스를 선언함
  • 이 예제는 예외가 발생하지 않고 정상 종료되는데 출력 결과를 보면 close( ) 메서드가 호출되어 '리소스가 close( ) 되었습니다.' 문장이 출력된 것을 알 수 있음
  • 리소스를 여러 개 생성해야 한다면 아래처럼 세미 콜론( ; )으로 구분할 수 있음

14-6 try-with-resources문 사용하기(2)

  • 6행에서 강제로 예외를 발생시키면 catch 블럭이 수행됨
  • 출력 결과를 보면 리소스의 close( ) 메서드가 먼저 호출되고 예외 블럭 부분이 수행되는 것을 알 수 있음
  • try-with-resources문을 사용하면 close( ) 메서드를 명시적으로 호출하지 않아도 정상 종료된 경우와 예외가 발생한 경우 모두 리소스가 잘 해제됨

14-3 예외 처리 미루기

예외 처리를 미루는 throws 사용하기

  • FileInputStream을 생성했을 때 예외 처리 방법은 두 가지가 있었음
  • Surround with try/catch는 살펴보았으니, Add throws declaration에 대해 살펴보겠음
  • Add throws declaration는 throws 선언을 추가한다는 의미인데, 예외를 해당 메서드에서 처리하지 않고 미룬 후 메서드를 호출하여 사용하는 부분에서 예외를 처리하는 방법임

예제 14-7 throws로 예외 미루기

  • 위 코드에서 정의한 loadClass( ) 메서드는 FileInputStream을 열고 Class를 동적으로 로딩하여 반환함
  • 파일을 열 때는 FileNotFoundException이 발생할 수 있고, 클래스를 로딩할 때는 ClassNotFoundException이 발생할 수 있음

14-4 사용자 정의 예외

  • 자바에서 제공하는 예외 처리 클래스 이외에는 개발하는 프로그램에 따라 다양한 예외 상황이 발생할 수 있음
    - 예 : 회원가입을 할 때 입력하는 아이디 값이 null이어서는 안 되고 8자 이상 20자 이하로 만들어야 한다는 조건이 필요할 수 있음
  • 위와 같은 조건을 체크하는 작업을 자바 프로그램에서 한다면 예외 클래스를 직접 만들어 예외를 발생시키고 예외 처리 코드를 구현할 수 있음

사용자 정의 예외 클래스 구현하기

  • 사용자 정의 예외 클래스를 구현할 때는 기존 JDK에서 제공하는 예외 클래스 중 가장 유사한 클래스를 상속받는 것이 좋음
  • 유사한 예외 클래스를 잘 모르겠다면 가장 상위 클래스인 Exception 클래스에서 상속받으면 됨

예제 14-8 사용자 정의 예외 구현하기

  • Exception 클래스를 상속받아 구현함
  • 예외 상황 메세지를 생성자에서 입력 받음
  • Exception 클래스에서 메세지 생성자, 멤버 변수와 메서드를 이미 제공하고 있으므로 super(message)를 사용하여 예외 메세지를 설정
  • getMessage( ) 메서드를 호출하면 메세지 내용을 볼 수 있음

예제 14-9 사용자 정의 예외 테스트하기

  • IDFormatTest 클래스에서 setUserID( ) 메서드는 아이디에 대한 제약 조건을 구현함
  • 제약 조건이 지켜지지 않으면 예외를 발생시킴
    - 여기에 발생하는 예외는 자바에서 제공하는 예외가 아니므로 예외 클래스를 직접 생성하여 발생시켜야 함

예외 처리를 할 때는 로그를 잘 남기자

  • 어떤 상황에서 오류가 났는지, 또 시스템에서 어떤 메서드를 호출하고 어떻게 매개변수를 전달했는지 오류 현상만 보고는 알 수 없음
  • 프로그램을 개발할 때는 로그(log)를 남기는 것이 매우 중요
  • 오류가 발생했을 때 로그를 보고 오류를 발생하는 코드를 순서대로 따라가며 확인할 수 있고, 원인을 찾을 수 있음
  • 로그는 정보 의미에 따라 레벨을 나누어 관리함
  • 간단한 로그부터 심각한 예외가 발생했을 때의 로그까지 여러 레벨이 존재할 수 있음
  • 로그를 체계적이고 의미 있게 남겨서 시스템에서 오류가 났을 때 그 원인을 유추해 볼 수 있어야 함
  • 웹 애플리케이션이나 안드로이드 앱을 만든다면 프로그램 개발뿐 아니라 유지보수를 위해서도 로그는 정말 중요하므로, 로그의 필요성을 깊이 인식하고 의미 있는 로그를 체계적으로 남기는 습관을 들여야 함
profile
Nil Desperandum <절대 절망하지 마라>

0개의 댓글