교재 : JAVA 프로그래밍 기초 - 17. 예외 처리

+ 자바의 정석[기초편]

# 프로그램 오류

[오류의 종류]

· 컴파일 에러 : 컴파일 시 발생하는 에러

· 런타임 에러 : 실행 시 발생하는 에러

· 논리적 에러 : 실행은 되지만 의도와 다르게 동작하는 것

 

 

# 런타임 에러

자바에서는 실행 시 발생할 수 있는 오류 (error와 exception)를 클래스로 정의함.

· 에러(error) 

프로그램 코드에 의해서 수습될 수 없는 심각한 오류 (예 : 하드웨어 고장, 메모리 부족 등)

· 예외(exceptiom) 

프로그램 코드에 의해서 수습될 수 있는 다소 미약한 오류

  • 정수를 0으로 나눔
  • 배열의 요소 수보다 큰 요소 수를 지정해 액세스 실시
  • 사용자의 입력 실수 (수치 입력 요구중인데 문자 입력 등)
  • 존재하지 않는 파일을 지정하고 읽음
  • 데이터베이스에 연결 불가
  • 할당되지 않은 저장 영역에 액세스 (부정한 값의 포인터 참조 등)

 

 

 

예외 처리하기 (try - catch문) 정의

예외처리(exception handling)의

정의 : 프로그램 실행시 발생할 수 있는 예외의 발생에 대비한 코드를 작성

목적 : 프로그램의 비정상 종료를 막고, 정상적인 실행 상태를 유지

 

try { 
   실행내용
   ...
} catch (예외처리문) {
   예외 처리 내용
   ...
}
try {
     // 예외가 발생할 가능성이 있는 문장들을 넣는다.
} catch (Exception1 e1) {
     // Exception1이 발생했을 경우, 이를 처리하기 위한 문장
} catch (Exception2 e2) {
     // Exception2가 발생했을 경우, 이를 처리하기 위한 문장
} catch (Exception3 e3) {
     // Exception3이 발생했을 경우, 이를 처리하기 위한 문장
}

· 하나의 try 블럭 다음에는 여러 종류의 예외를 처리할 수 있도록 하나 이상의 catch블럭이 올 수 있다.

· 이 중 발생한 예외의 종류와 일치하는 단 한개의 catch블럭만 수행됨.

· 일치하는게 없으면 예외 처리 되지 않음.

 

 

 

예외처리 순서

▶ try블럭 내에서 예외가 발생한 경우

    1. 발생한 예외와 일치하는 catch블럭이 있는지 찾는다.

    2. 일치하는 catch블럭을 찾으면, 그 catch블럭 내의 문장들을 수행 → 전체 try - catch문을 빠져나간 후 그 다음 문장을 계속해서 수행한다.

    일치하는 catch블럭을 찾지 못하면 예외는 처리되지 못한다.

 

▶ try블럭 내에서 예외가 발생하지 않은 경우

    1. catch블럭을 거치지 않고 전체 try - catch문을 빠져나가서 수행을 계속한다.

 

 

예제

배열 요소수를 초과하여 액세스하고 예외처리 실행해보기

package chap17;

public class ArrayException2 {

    public static void main(String[] args) {
        try {
            // int형 배열 
            int[] intArray = new int[5];

            // 10엔덱스에 값을 대입
            System.out.println("intArray[10]에 숫자를 할당합니다.");
            intArray[10] = 50; // 최대 배열 요소수를 초과하는 대입처리

            // 결과 표시
            System.out.println("intArray[10]에 50을 할당하였습니다.");

        } catch (ArrayIndexOutOfBoundsException e) { // 최대 배열 요소수 초과 예외처리
            System.out.println("배열의 요소수를 초과했습니다.");
        }
        System.out.println("프로그램 종료");
    }
}

▽ 실행 ▽

 

 

정수를 0으로 나눠서 예외처리 실행해보기

package chap17;

public class ZeroException2 {
    public static void main(String[] args) {
        try {
            // 숫자를 0으로 나눔 
            int num = 10 / 0;

            // 결과 
            System.out.println("10/0 결과: " + num);
        } catch (ArithmeticException e) { // 0나누기의 예외처리
            System.out.println("0으로 나눌 수 없습니다.");
        }
        System.out.println("처리 종료");
    }
}

▽ 실행 ▽

 

 

③ 호출한 메소드 내에서 발생한 예외 처리 실행해보기

package chap17;

public class ThrowZeroException2 {
    public static void calcTest() {
        // 숫자를 0으로 나눔
        int num = 10 / 0;

        // 결과표시
        System.out.println("10/ 결과: " + num);
    }

    public static void main(String[] args) {
        try {
            // calcTest메소드 호출
            calcTest();
        } catch (ArithmeticException e) { // 0나누기 예외처리
            System.out.println("0으로 나눌 수 없습니다.");
        }
        System.out.println("처리 완료");
    }
}

▽ 실행 ▽

※ 예외가 발생했을 경우 예외 처리가 행해지고 있는지의 여부가 호출처에서 호출원으로 거슬러 간다.

 

 

 

예외 클래스의 계층구조

catch(Exception e) {
        …
 }

모든 예외 클래스는 Exception클래스의 자손이므로,

catch블럭의 괄호()에 Exception클래스 타입의 참조변수를 선언해 놓으면

어떤 종류의 예외가 발생하더라도 이 catch블럭에 의해 처리됨.

 

 

 

finally블럭

예외의 발생여부에 상관없이 실행되어야할 코드를 포함시킬 목적으로 사용

try {
     // 예외가 발생할 가능성이 있는 문장
} catch (Exception e) {
     // 예외 처리를 위한 문장
} finally {
     // 예외의 발생여부에 관계없이 항상 수행되어야하는 문장
}

finally블럭은 try - catch문의 가장 마지막에 위치해야한다.

 

예제 ①

package chap17;

public class FinallyBlock {
    public static void main(String[] args) {
        try {
            // int형 배열
            int[] intArray = new int[5];

            // 배열에 값을 할당
            System.out.println("배열에 숫자를 할당합니다.");
            intArray[10] = 50; // 예외를 일부러 발생시키는 대입
            // intArray[0] = 50; // 올바르게 할당

            // 결과 표시
            System.out.println("배열에 50을 할당했습니다.");
        } catch (ArrayIndexOutOfBoundsException e) { // 최대 배열요소수를 초과하는 예외 처리
            System.out.println("배열의 요소수를 초과했습니다.");
        } finally {
            System.out.println("예외처리의 마지막 처리입니다."); // finally블록
        }
        System.out.println("처리 종료");
    }
}

▽ 실행 ▽

 

 

예외 처리 패턴

① try-catch(필수)
② try-catch-finally(catch가 있는 경우는 임의 설정)
③ try-(catch* 임의의 수)-finally(catch가 있는 경우는 임의 설정)
④ try-finally(필수)

 

 

[예외 처리 용어]
· 예외를 throw한다 : 프로그램 실행중 에러가 발생하는 것
· 예외 catch(잡기) : catch문의 매개 변수와 발생한 예외 객체가 일치하는 것
처리내용
try {
   // try내부문장
} catch (예외클래스명 인수명) {
   // 예외처리 내용
} finally {
   // 예외중 catch문내에 포함이 안되는 경우
}
처리내용

 

 

 

checked예외 & unchecked예외

체크(checked)예외 : 예외 처리를 기술하지 않으면 컴파일 에러가 되는 예외

비체크(unchecked)예외 : 예외 처리를 기술하지 않아도 컴파일할 수 있는 예외

체크(checked)예외 비체크(unchecked)예외
ArithmeticExceptio IOExceptiuon
NullPointerException ClassNotFoundException
ArrayIndexOutOfBoundsException FileNotFoundException
IndexOutOfBoundsException  
ArrayStoreException
ClassCastException
NoSuchFieldException
NoSuchMethodException
RuntimeException
IllegalAccessException
NumberFormatException

 

 

 

# 연습문제

더보기

17.5 연습문제

<질문 1 >다음의 질문 ①~⑤에 대해 ○인가×로 대답하십시오.

① 예외가 발생하면 반드시 catch 블록이 처리된다. X
② 예외가 발생하지 않는 경우에도 반드시 finally 블록 내의 처리가 실행된다. O
③ catch 블록은 복수 설정할 수 있으므로, catch 블록에 지정하는 예외 클래스의 배열은 특별히 신경쓸 필요는 없다. X
④ catch의 「()」괄호내에 지정한 변수명을 이용하면, 예외의 상세한 정보를 취득할 수 있다. O
⑤ 예외처리를 짜면 소스코드가 번잡해지므로 어떤 예외도 절대로 처리할 필요는 없다. X

 

<질문 2> 아래에 표시된 소스 코드를 실행 한 결과로 올바른 것을 대답하십시오.

① red만 화면에 표시된다.
② red, blue, yellow, pink, black 모두 표시된다.
③ red, blue, pink, black이 표시된다.
④ yellow만 화면에 표시된다.
⑤ red, blue, yellow, 핑크가 표시된다.
⑥ black만 화면에 표시된다.

package chap17exercise;

public class Practice2 {
    public static void main(String[] args) {

        System.out.println("red");

        try {
            int[] array = new int[2];

            System.out.println("blue");

            array[2] = 88;

            System.out.println("yellow");

        } catch (Exception e) {
            System.out.println("pink");
        } finally {
            System.out.println("black");
        }
    }
}

 

<질문 3> 이하에 나타내는 Practice03.java의 소스 코드를 실행했을 경우, 발생할 가능성이 있는 선택사항의 예외를 ○인가×로 대답해 주세요.

① 파일 입출력 에러(ioexception) X
② 0 나누기 에러(arithmeticexception) O
③ 배열 에러(arrayindexoutofboundsexception) O
④ 형식 변환 에러(numberformatexception) X
⑤ 키보드 입력값의 에러(inputmismatchexception) O (int형외에 다른값을 넣으면 에러)

 

package chap17exercise;

import java.util.*;

public class sample {
    public static void main(String[] args) {
        int cnt = 0; // 입력수
        int sum = 0; // 총점
        int ave = 0; // 평균 (소수점 이하는 자름)
        int[] num = new int[3]; // 입력숫자 저장하는 배열 

        Scanner sin = new Scanner(System.in); // scanne클래스 객체화 

        // 반복처리 (배열의 요소수)
        while (true) {
            // 키보드에서 숫자 입력하고 배열에 저장
            System.out.print("(숫자 입력(999에서는 강제종료)): ");
            int tmpnum = sin.nextInt();

            // 입력값이 999이면 강제 종료
            if (tmpnum == 999) {
                break;
            }
            num[cnt] = tmpnum; // 배열에 데이터 자정
            cnt++; // 입력수 계산
        }

        // 반복처리(배열의 요소수분)
        for (int i = 0; i < cnt; i++) {
            // 입력수치를 총점에 추가
            sum += num[i];
        }
        // 평균  계산
        ave = sum / cnt;

        // 각 결과를 화면에 출력
        System.out.println("입력수: " + cnt  );
        System.out.println("총점: " + sum );
        System.out.println("평균점:" + ave );
    }
}

 

<질문 4> 질문 3에서 키보드 입력 값에 대한 예외를 처리했지만 그 이외에도 다음과 같은 예외가 발생합니다.

  • 1명도 입력하지 않고 종료한 경우: 0 나누기 예외
  • 4회 이상 입력한 경우: 최대 배열 요소 수 초과 예외

위를 다루는 각 예외를 가공하는 것과 같은 예외 처리를 통합한 practice1701.java를 창조하십시오.
질문3에서 작성한 소스 코드를 이용해, 변경 사양에 따라 작성해 주세요.

 

변경사양

  • try 블록에 포함시키는 처리는 main 함수 내의 모든 처리를 포함한다.
  • catch 하는 예외는 Exception를 지정한다.
  • catch 블록 내의 처리는 예외의 상세 정보를 화면에 출력한다.→「xxxx라는 예외가 발생했습니다.」
    ※xxxx=예외의 상세 정보
package chap17exercise;

public class Sample {
    
    public static void main(String[] args) {
        try {
            main
        } catch(...) {
            오류처리
        }
    }
}
package xyz.devbro.chap17;

import java.util.InputMismatchException;
import java.util.Scanner;

public class Practice1701 {
    public static void main(String[] args) {
        try {
            int cnt = 0;
            int sum = 0;
            int ave = 0;
            int[] num = new int[3];

            Scanner sc = new Scanner(System.in);
            while(true) {
                try {
                    System.out.print("숫자입력 (999입력시 종료): ");
                     int tempNo = sc.nextInt();
                     if (tempNo == 999) {
                         break;
                     }
                     num[cnt] = tempNo;
                     cnt++;
                } catch (InputMismatchException e) {
                    System.out.println("문자가 입력되었습니다. 정수를 입력하세요");
                    sc.next();
                }
            }

            System.out.println("입력: " + cnt);
            System.out.println("합계: " + sum);
            System.out.println("평균: " + ave);
        } catch (Exception e) {
            System.out.println("예외 발생: " +  e);
        }
    }
}
복사했습니다!