[자바 무료 강의] 예외처리 - 코드라떼
Lesson List button
코스자바로 배우는 프로그래밍
hamburger button
강의예외처리최종수정일 2021-11-21
아이콘약 4분

프로그램 이용자나 소스 코드 이용자는 소스 코드 작성자가 작성한 의도대로 행동하지 않을 수 있습니다. 이것을 예외 사항이라고 합니다. 이러한 예외 사항을 어떻게 대응할 수 있을까요? 이번 강의에서는 예외 사항을 대응하는 법에 대해 배웁니다.

추가 노트

예외 처리를 잘 하는 방법은 프로그램 사용자의 입장에서 생각하는 것입니다. 우리가 만든 프로그램은 스스로 사용하기 위해 만들 수도 있지만 대부분은 사용자를 위해서 만들게 됩니다. 실습과 연구를 많이 할수록 더 많은 문제에 미리 대응할 수 있습니다. 또한 지금 당장은 이해가 되지 않는다고 하더라도 코딩하다 보면 깨닫게 되는 부분도 있으므로 마음을 조급하게 먹지 않아도 됩니다.


목차


  1. 예외

  2. 어떤 예외가 발생하는지 확인하는 방법

  3. RuntimeException 클래스로 예외 사항을 대응하기

  4. 커스텀 예외 던지기

  5. [실습해보기] 예외 처리

1. 예외


Throwable

모든 에러와 예외에 대한 최상위 클래스입니다. Object 클래스를 상속받고 있으며 Error와 Exception 하위 클래스들을 가지고 있습니다. 일반적으로는 해당 클래스를 직접적으로 이용할 일은 없습니다. 그러므로 있다는 것만 알고 넘어갑시다.


Error


프로그램 실행 도중 해결할 수 있는 문제가 아니라 이후에 발견되어 처리해야 하는 문제들이 Error 클래스와 연관되어 있습니다. 코드상으로 별도의 예외 처리를 할 수 없습니다.


1. OutOfMemoryError

자바 가상 머신이 메모리가 부족하여 인스턴스를 할당할 수 없고 가비지 컬렉터가 메모리를 사용할 수 없을 때 발생합니다.


2. StackOverflowError

스레드의 Stack 메모리가 꽉 찼을 경우 발생합니다. (이후의 강의에서 Stack 메모리가 무엇인지 알게 됩니다)


3. VirtualMachineError

자바 가상 머신에 문제가 생겼거나 실행되는데 리소스가 부족할 경우 발생됩니다.


Exception


프로그램 실행 도중 종료될 수 있는 문제와 연관되어 예외 처리를 선택적으로 하거나, 꼭 해야 하는 클래스들의 슈퍼 클래스입니다. Exception에는 Checked Exception과 Unchecked Exception이 있으며 Checked Exception은 반드시 예외 처리를 해야지 컴파일이 가능하나 Unchecked Exception은 예외 처리가 선택입니다.

*Checked Exception과 Unchecked Exception을 구분하는 방법은 직접적으로 Exception 클래스를 상속받는 경우 Checked Exception 으로 보면 되며 RuntimeException을 상속받는 경우 Unchecked Exception으로 보면 쉽습니다.


1. Checked Exception

반드시 try - catch 구문을 사용해야지 컴파일되는 예외이며 직접적으로 Exception 클래스를 상속받는 예외입니다.


1-1. IOException

InputStream.java

public abstract class InputStream implements Closeable {
    ...
    public int read(byte b[]) throws IOException {
        return read(b, 0, b.length);
    }
    ...
}

입력과 출력과 관련된 예외이고 주로 throws를 통해 메서드에 선언되어 있으며 반드시 예외 처리를 해야 컴파일이 됩니다. 주로 InputStream, OutputStream 관련 메서드를 사용할 때 IOException과 관련한 예외처리를 해야 합니다.


1-2. InterruptedException

Thread.java

public class Thread implements Runnable {
    ...
    public static void sleep(long millis, int nanos) throws InterruptedException {
    ...
}

    public final synchronized void join(long millis) throws InterruptedException {
    ...
    }
    ...
}

스레드와 관련된 예외이고 주로 throws를 통해 메서드에 선언되어 있으며 반드시 예외 처리를 해야 컴파일이 됩니다. 주로 Thread 관련 메서드를 사용할 때 InterruptedException과 관련한 예외처리를 해야 합니다.


2. Unchecked Exception

강제적으로 try - catch 구문을 사용하지 않아도 되는 예외이며 프로그램 실행도중 발생할 수 있는 예외들로 구성되어 있습니다.


2-1. RuntimeException

Unchecked Exception의 최상위 클래스로 Exception 클래스를 직접적으로 상속받은 클래스이나 특수하게 RuntimeException을 상속 받는 예외들은 try - catch 구문에 대한 강제성이 없습니다.

이러한 예외들은 예외가 발생할 가능성이 높을 때 방어코드를 사용하거나 또는 try - catch 구문으로 회피하는 방식을 택할 수 있습니다.


2-2. NullPointerException
String text = null;
System.out.println(text.isEmpty()); 
// NullPointerException 발생

RuntimeException을 상속 받는 예외입니다. 참조 자료형 변수에 인스턴스가 저장되어 있지 않고 null 값이 저장되어 있을 때, 인스턴스 메서드를 호출하거나, 변수의 접근 시 발생할 수 있습니다.


2-3. ClassCastException
class Warrior {
}

class SuperWarrior extends Warrior {
}

Warrior warrior = new Warrior();
SuperWarrior superWarrior = (SuperWarrior) warrior;
// 생성된 인스턴스는 Warrior 이므로 SuperWarrior로 형 변환시
// ClassCastException 발생

RuntimeException을 상속 받는 예외입니다. 객체 형 변환시 올바르지 않은 객체로 형 변환 할 경우 발생할 수 있습니다.


2. 어떤 예외가 발생하는지 확인하는 방법


예외 발생 가능성이 높다고 했을 때 어떻게 적절한 Exception을 찾아낼까요?

방법은 간단합니다.


case 1

int num = -1;

int[] array = new int[3];
System.out.println(array[num]);

일부로 예외가 발생하도록 코드를 작성해봅니다.

그리고 코드를 실행하면 아래와 같은 예외가 발생합니다.

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException : -1
	at Main.main(Main.java:12)

Exception 내용을 보면 ArrayIndexOutOfBoundsException라고 작성되어있습니다.

이것이 잘못된 인덱스로 배열로 접근할 때 발생하는 예외입니다.

이 내용을 근거로 코드를 재작성해봅시다.

int num = -1;

int[] array = new int[3];
try {
    System.out.println(array[num]);
} catch (ArrayIndexOutOfBoundsException ex) {
    System.out.println("잘못된 인덱스입니다.");
}

이렇게 하면 어떤 예외가 발생하는 지 확인할 수 있습니다.


case 2

Scanner scanner = new Scanner(system.in);

int value = scanner.nextInt();
String text = scanner.nextLine();

Scanner 클래스는 이용자가 특정한 입력을 했을 때 입력을 기준으로 문자 또는 숫자 또는 바이트 등 다양한 자료형으로 입력값을 반환 받을 수 있는 클래스입니다. 그러므로 우리는 사용자의 키보드를 제어할 수 없을 뿐더러, 시스템에 숫자가 입력될지 문자가 입력될지 알 수 없습니다.

우리가 의도한 프로그램이 실행될 때 사용자에 의한 예외로 인한 프로그램 종료를 방지하기 위해서는 적절한 예외를 찾아주는 것이 좋습니다.

Scanner scanner = new Scanner(system.in);

// 문자 입력해보기
int value = scanner.nextInt();

발생하는 에러는 다음과 같습니다.

Exception in thread "main" java.util.InputMismatchException
	at java.util.Scanner.throwFor(Scanner.java:864)
	at java.util.Scanner.next(Scanner.java:1485)
	at java.util.Scanner.nextInt(Scanner.java:2117)
	at java.util.Scanner.nextInt(Scanner.java:2076)
	at Main.main(Main.java:10)

Exception 내용을 보면 InputMismatchException라고 작성되어있습니다.

이것이 문자를 입력 받았을 때, 정수형으로 변환시 발생하는 예외입니다.

Scanner scanner = new Scanner(system.in);

try {
    int value = scanner.nextInt();
} catch (InputMismatchException ex) {
    System.out.println("잘못된 입력입니다");
}

이렇게 예외처리 해주면 됩니다.


3. RuntimeException 클래스로 예외 사항을 대응하기


모든 예외를 체크할 수는 없으나 어떠한 예외가 발생할 가능성이 높다고 생각했을 때 RuntimeException 클래스를 통해 예외에 대응할 수 있습니다.

int num = -1;

int[] array = new int[3];
try {
    System.out.println(array[num]);
} catch (RuntimeException ex) {
    System.out.println("잘못된 인덱스입니다.");
}

RuntimeException 클래스는 프로그램 실행도중 발생하는 예외와 관련된 슈퍼 클래스이기 때문에 RuntimeException을 이용하여 예외에 대응할 수 있습니다.

다만 예외의 종류가 좁혀진다면 예외 종류에 따라 대응이 달라져야 하므로 적절한 RuntimeException 클래스를 찾아서 대응하는 것이 가장 좋습니다.

더 좋은건 예외가 발생하지 않도록 프로그래밍 하는 것 입니다.


4. 커스텀 예외 던지기


이미 만들어진 예외가 아니라 직접 예외를 적용하기 위해 클래스를 만들 수 있습니다.

Unchecked Exception을 만들기 위한 CustomException

public class CustomException extends RuntimeException {
    public CustomException() {
        super("커스텀 예외다!");
    }
}
public class ExceptionTest {
    String name;

    public void setName(String name) {
        if (null == name) {
            throw new CustomException();
        }
    }
}

해당 코드는 setName 메서드를 호출 시 매개변수 값이 null로 전달 받았을 때 CustomException을 호출하는 방법입니다. CustomExceptionRuntimeException을 상속 받았기 때문에 Unchecked Exception 입니다. 그러므로 강제적으로 try - catch 구문을 사용하지 않아도 됩니다.

(throw 키워드를 이용하여 고의적으로 CustomException을 던질 수 있습니다.)

그러나 우리가 만든 코드를 누군가가 이용한다고 했을 때 코드 이용자가 꼭 예외 사항을 대응하길 바란다고 생각한다면 이렇게 처리해도 됩니다.

Checked Exception을 만들기 위한 CustomException

public class CustomException extends Exception {
    // Exception 클래스를 상속받는다.

    public CustomException() {
        super("커스텀 예외다!");
    }
}
public class ExceptionTest {
    String name;

    public void setName(String name) throws CustomException {
        if (null == name) {
            throw new CustomException();
        }
    }
}

CustomExceptionException 클래스를 상속 받았습니다.

그리고 메서드에 throws 키워드를 이용하고 CustomException 클래스를 명시했습니다.

이 뜻은 해당 메서드는 Checked exception을 대응해야 한다는 의미로 이 메서드를 사용 시 try - catch 구문을 명시적으로 작성하도록 강제한다는 의미입니다.

결론적으로 Checked exception을 만들 때는 Exception 클래스를 상속 받고, Unchecked exception을 만들 때는 RuntimeException 클래스를 상속 받는 것이 좋습니다.

어떻게 보면 큰차이는 없지만 의미상 차이가 있으므로, 가급적 언어 스펙에 맞게 코드를 작성하시는 것이 좋습니다.


5. [실습해보기] 예외 처리


1. Unchecked Exception

case 1

코드 작성

public class Main {
    public static void main(String[] args) {
        int index = -1;
        int[] array = {1, 2, 3};
        System.out.println(array[index]);
        System.out.println("프로그램 종료");
    }
}

출력

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: -1

비정상적인 index로 배열에 접근했으므로 예외가 발생합니다. 그러므로 ArrayIndexOutOfBoundsException와 관련된 예외 처리를 해봅시다.


코드 변경

public class Main {
    public static void main(String[] args) {
        int index = -1;
        int[] array = {1, 2, 3};

        try {
            System.out.println(array[index]);
        } catch (ArrayIndexOutOfBoundsException ex) {
            System.out.println("예외 발생");
        }
        System.out.println("프로그램 종료");
    }
}

출력

예외 발생
프로그램 종료

예외가 발생 시 catch 구문으로 이동하여 실행 후 프로그램이 종료되지 않고 그다음 명령어를 실행 후 프로그램이 종료됩니다.


case 2

코드 작성

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        while (true) {
            Scanner scanner = new Scanner(System.in);
            int dividend;
            int divisor;

            System.out.println("피제수를 입력해주세요.");
            dividend = scanner.nextInt();
            System.out.println("제수를 입력해주세요.");
            divisor = scanner.nextInt();
            int quotient = dividend / divisor;
            System.out.printf("%d / %d = %d\n", dividend, divisor, quotient);
        }
    }
}

두 수를 입력하여 몫을 구하는 나눗셈 프로그램입니다. (Scanner 객체를 사용하므로 import를 해주어야 합니다)


입력

0
0

출력

Exception in thread "main" java.lang.ArithmeticException: / by zero

피제수와 제수를 0으로 하면 나눌 수 없으므로 ArithmeticException관련 예외가 발생합니다.


1차 코드 변경

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        while (true) {
            Scanner scanner = new Scanner(System.in);
            int dividend;
            int divisor;

            try {
                System.out.println("피제수를 입력해주세요.");
                dividend = scanner.nextInt();
                System.out.println("제수를 입력해주세요.");
                divisor = scanner.nextInt();
                int quotient = dividend / divisor;
                System.out.printf("%d / %d = %d\n", dividend, divisor, quotient);
            } catch(ArithmeticException ex) {
                System.out.println("0으로 나눌 수 없습니다.");
            }
        }
    }
}

try - catch 구문으로 예외 처리를 해줍시다.


입력

0
0

출력

0으로 나눌 수 없습니다.

예외가 발생했으나 예외 처리가 되어있으므로 프로그램은 종료되지 않습니다.

이번엔 문자를 입력해봅시다.


입력

출력

Exception in thread "main" java.util.InputMismatchException

정수로 변환하는 과정에서 문자를 정수로 바꿀 수 없으므로 InputMismatchException 예외가 발생합니다.


2차 코드 변경

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

public class Main {
    public static void main(String[] args) {
        while (true) {
            Scanner scanner = new Scanner(System.in);
            int dividend;
            int divisor;

            try {
                System.out.println("피제수를 입력해주세요.");
                dividend = scanner.nextInt();
                System.out.println("제수를 입력해주세요.");
                divisor = scanner.nextInt();
                int quotient = dividend / divisor;
                System.out.printf("%d / %d = %d\n", dividend, divisor, quotient);
            } catch(ArithmeticException ex) {
                System.out.println("0으로 나눌 수 없습니다.");
            } catch(InputMismatchException ex) {
                System.out.println("문자를 입력할 수 없습니다.");
            }
        }
    }
}

InputMismatchException 관련 예외 처리를 해줍시다. (다만 해당 예외 처리는 import java.util.InputMismatchException를 작성해 주어야 합니다.)


입력

출력

문자를 입력할 수 없습니다.

예외가 발생했으나 예외 처리가 되어있으므로 프로그램은 종료되지 않습니다.


2. Checked Exception

Checked Exception은 예외 처리가 되어있지 않으면 컴파일이 되지 않습니다.


case 1

코드 작성

public class Main {
    public static void main(String[] args) {
        byte[] numArray = {'1', '2', '3', '4'};
        System.out.write(numArray);
    }
}

System.out.write() 메서드는 바이트 배열을 전달 받아 문자를 출력하는 메서드입니다.


출력

Main.java:10: error: unreported exception IOException; must be caught or declared to be thrown
System.out.write(numArray); 1 error

System.out.write() 메서드는 Checked Exception인 IOException이 선언된 메서드입니다. 그러므로 반드시 try - catch 구문을 작성해주어야 합니다.


코드 변경

import java.io.IOException;

public class Main {
    public static void main(String[] args) {
        byte[] numArray = {'1', '2', '3', '4'};
        try {
            System.out.write(numArray);
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
}

IOException 관련 예외 처리를 해줍시다. (다만 해당 예외 처리는 import java.io.IOException을 작성해 주어야 합니다.)


출력

1234

try - catch 구문을 처리했으므로 정상적으로 컴파일이 되고 프로그램이 실행됩니다.

도전자 질문
작성된 질문이 없습니다
이용약관|개인정보취급방침
알유티씨클래스|대표, 개인정보보호책임자 : 이병록
이메일 : cs@codelatte.io
사업자등록번호 : 824-06-01921
통신판매업신고 : 2021-성남분당C-0740
주소 : 경기도 성남시 분당구 대왕판교로645번길 12, 9층 24호
파일
파일파일
Root
파일

Output
root$
Lesson List button
코스자바로 배우는 프로그래밍
hamburger button
강의예외처리최종수정일 2021-11-21
아이콘약 4분

프로그램 이용자나 소스 코드 이용자는 소스 코드 작성자가 작성한 의도대로 행동하지 않을 수 있습니다. 이것을 예외 사항이라고 합니다. 이러한 예외 사항을 어떻게 대응할 수 있을까요? 이번 강의에서는 예외 사항을 대응하는 법에 대해 배웁니다.

추가 노트

예외 처리를 잘 하는 방법은 프로그램 사용자의 입장에서 생각하는 것입니다. 우리가 만든 프로그램은 스스로 사용하기 위해 만들 수도 있지만 대부분은 사용자를 위해서 만들게 됩니다. 실습과 연구를 많이 할수록 더 많은 문제에 미리 대응할 수 있습니다. 또한 지금 당장은 이해가 되지 않는다고 하더라도 코딩하다 보면 깨닫게 되는 부분도 있으므로 마음을 조급하게 먹지 않아도 됩니다.


목차


  1. 예외

  2. 어떤 예외가 발생하는지 확인하는 방법

  3. RuntimeException 클래스로 예외 사항을 대응하기

  4. 커스텀 예외 던지기

  5. [실습해보기] 예외 처리

1. 예외


Throwable

모든 에러와 예외에 대한 최상위 클래스입니다. Object 클래스를 상속받고 있으며 Error와 Exception 하위 클래스들을 가지고 있습니다. 일반적으로는 해당 클래스를 직접적으로 이용할 일은 없습니다. 그러므로 있다는 것만 알고 넘어갑시다.


Error


프로그램 실행 도중 해결할 수 있는 문제가 아니라 이후에 발견되어 처리해야 하는 문제들이 Error 클래스와 연관되어 있습니다. 코드상으로 별도의 예외 처리를 할 수 없습니다.


1. OutOfMemoryError

자바 가상 머신이 메모리가 부족하여 인스턴스를 할당할 수 없고 가비지 컬렉터가 메모리를 사용할 수 없을 때 발생합니다.


2. StackOverflowError

스레드의 Stack 메모리가 꽉 찼을 경우 발생합니다. (이후의 강의에서 Stack 메모리가 무엇인지 알게 됩니다)


3. VirtualMachineError

자바 가상 머신에 문제가 생겼거나 실행되는데 리소스가 부족할 경우 발생됩니다.


Exception


프로그램 실행 도중 종료될 수 있는 문제와 연관되어 예외 처리를 선택적으로 하거나, 꼭 해야 하는 클래스들의 슈퍼 클래스입니다. Exception에는 Checked Exception과 Unchecked Exception이 있으며 Checked Exception은 반드시 예외 처리를 해야지 컴파일이 가능하나 Unchecked Exception은 예외 처리가 선택입니다.

*Checked Exception과 Unchecked Exception을 구분하는 방법은 직접적으로 Exception 클래스를 상속받는 경우 Checked Exception 으로 보면 되며 RuntimeException을 상속받는 경우 Unchecked Exception으로 보면 쉽습니다.


1. Checked Exception

반드시 try - catch 구문을 사용해야지 컴파일되는 예외이며 직접적으로 Exception 클래스를 상속받는 예외입니다.


1-1. IOException

InputStream.java

public abstract class InputStream implements Closeable {
    ...
    public int read(byte b[]) throws IOException {
        return read(b, 0, b.length);
    }
    ...
}

입력과 출력과 관련된 예외이고 주로 throws를 통해 메서드에 선언되어 있으며 반드시 예외 처리를 해야 컴파일이 됩니다. 주로 InputStream, OutputStream 관련 메서드를 사용할 때 IOException과 관련한 예외처리를 해야 합니다.


1-2. InterruptedException

Thread.java

public class Thread implements Runnable {
    ...
    public static void sleep(long millis, int nanos) throws InterruptedException {
    ...
}

    public final synchronized void join(long millis) throws InterruptedException {
    ...
    }
    ...
}

스레드와 관련된 예외이고 주로 throws를 통해 메서드에 선언되어 있으며 반드시 예외 처리를 해야 컴파일이 됩니다. 주로 Thread 관련 메서드를 사용할 때 InterruptedException과 관련한 예외처리를 해야 합니다.


2. Unchecked Exception

강제적으로 try - catch 구문을 사용하지 않아도 되는 예외이며 프로그램 실행도중 발생할 수 있는 예외들로 구성되어 있습니다.


2-1. RuntimeException

Unchecked Exception의 최상위 클래스로 Exception 클래스를 직접적으로 상속받은 클래스이나 특수하게 RuntimeException을 상속 받는 예외들은 try - catch 구문에 대한 강제성이 없습니다.

이러한 예외들은 예외가 발생할 가능성이 높을 때 방어코드를 사용하거나 또는 try - catch 구문으로 회피하는 방식을 택할 수 있습니다.


2-2. NullPointerException
String text = null;
System.out.println(text.isEmpty()); 
// NullPointerException 발생

RuntimeException을 상속 받는 예외입니다. 참조 자료형 변수에 인스턴스가 저장되어 있지 않고 null 값이 저장되어 있을 때, 인스턴스 메서드를 호출하거나, 변수의 접근 시 발생할 수 있습니다.


2-3. ClassCastException
class Warrior {
}

class SuperWarrior extends Warrior {
}

Warrior warrior = new Warrior();
SuperWarrior superWarrior = (SuperWarrior) warrior;
// 생성된 인스턴스는 Warrior 이므로 SuperWarrior로 형 변환시
// ClassCastException 발생

RuntimeException을 상속 받는 예외입니다. 객체 형 변환시 올바르지 않은 객체로 형 변환 할 경우 발생할 수 있습니다.


2. 어떤 예외가 발생하는지 확인하는 방법


예외 발생 가능성이 높다고 했을 때 어떻게 적절한 Exception을 찾아낼까요?

방법은 간단합니다.


case 1

int num = -1;

int[] array = new int[3];
System.out.println(array[num]);

일부로 예외가 발생하도록 코드를 작성해봅니다.

그리고 코드를 실행하면 아래와 같은 예외가 발생합니다.

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException : -1
	at Main.main(Main.java:12)

Exception 내용을 보면 ArrayIndexOutOfBoundsException라고 작성되어있습니다.

이것이 잘못된 인덱스로 배열로 접근할 때 발생하는 예외입니다.

이 내용을 근거로 코드를 재작성해봅시다.

int num = -1;

int[] array = new int[3];
try {
    System.out.println(array[num]);
} catch (ArrayIndexOutOfBoundsException ex) {
    System.out.println("잘못된 인덱스입니다.");
}

이렇게 하면 어떤 예외가 발생하는 지 확인할 수 있습니다.


case 2

Scanner scanner = new Scanner(system.in);

int value = scanner.nextInt();
String text = scanner.nextLine();

Scanner 클래스는 이용자가 특정한 입력을 했을 때 입력을 기준으로 문자 또는 숫자 또는 바이트 등 다양한 자료형으로 입력값을 반환 받을 수 있는 클래스입니다. 그러므로 우리는 사용자의 키보드를 제어할 수 없을 뿐더러, 시스템에 숫자가 입력될지 문자가 입력될지 알 수 없습니다.

우리가 의도한 프로그램이 실행될 때 사용자에 의한 예외로 인한 프로그램 종료를 방지하기 위해서는 적절한 예외를 찾아주는 것이 좋습니다.

Scanner scanner = new Scanner(system.in);

// 문자 입력해보기
int value = scanner.nextInt();

발생하는 에러는 다음과 같습니다.

Exception in thread "main" java.util.InputMismatchException
	at java.util.Scanner.throwFor(Scanner.java:864)
	at java.util.Scanner.next(Scanner.java:1485)
	at java.util.Scanner.nextInt(Scanner.java:2117)
	at java.util.Scanner.nextInt(Scanner.java:2076)
	at Main.main(Main.java:10)

Exception 내용을 보면 InputMismatchException라고 작성되어있습니다.

이것이 문자를 입력 받았을 때, 정수형으로 변환시 발생하는 예외입니다.

Scanner scanner = new Scanner(system.in);

try {
    int value = scanner.nextInt();
} catch (InputMismatchException ex) {
    System.out.println("잘못된 입력입니다");
}

이렇게 예외처리 해주면 됩니다.


3. RuntimeException 클래스로 예외 사항을 대응하기


모든 예외를 체크할 수는 없으나 어떠한 예외가 발생할 가능성이 높다고 생각했을 때 RuntimeException 클래스를 통해 예외에 대응할 수 있습니다.

int num = -1;

int[] array = new int[3];
try {
    System.out.println(array[num]);
} catch (RuntimeException ex) {
    System.out.println("잘못된 인덱스입니다.");
}

RuntimeException 클래스는 프로그램 실행도중 발생하는 예외와 관련된 슈퍼 클래스이기 때문에 RuntimeException을 이용하여 예외에 대응할 수 있습니다.

다만 예외의 종류가 좁혀진다면 예외 종류에 따라 대응이 달라져야 하므로 적절한 RuntimeException 클래스를 찾아서 대응하는 것이 가장 좋습니다.

더 좋은건 예외가 발생하지 않도록 프로그래밍 하는 것 입니다.


4. 커스텀 예외 던지기


이미 만들어진 예외가 아니라 직접 예외를 적용하기 위해 클래스를 만들 수 있습니다.

Unchecked Exception을 만들기 위한 CustomException

public class CustomException extends RuntimeException {
    public CustomException() {
        super("커스텀 예외다!");
    }
}
public class ExceptionTest {
    String name;

    public void setName(String name) {
        if (null == name) {
            throw new CustomException();
        }
    }
}

해당 코드는 setName 메서드를 호출 시 매개변수 값이 null로 전달 받았을 때 CustomException을 호출하는 방법입니다. CustomExceptionRuntimeException을 상속 받았기 때문에 Unchecked Exception 입니다. 그러므로 강제적으로 try - catch 구문을 사용하지 않아도 됩니다.

(throw 키워드를 이용하여 고의적으로 CustomException을 던질 수 있습니다.)

그러나 우리가 만든 코드를 누군가가 이용한다고 했을 때 코드 이용자가 꼭 예외 사항을 대응하길 바란다고 생각한다면 이렇게 처리해도 됩니다.

Checked Exception을 만들기 위한 CustomException

public class CustomException extends Exception {
    // Exception 클래스를 상속받는다.

    public CustomException() {
        super("커스텀 예외다!");
    }
}
public class ExceptionTest {
    String name;

    public void setName(String name) throws CustomException {
        if (null == name) {
            throw new CustomException();
        }
    }
}

CustomExceptionException 클래스를 상속 받았습니다.

그리고 메서드에 throws 키워드를 이용하고 CustomException 클래스를 명시했습니다.

이 뜻은 해당 메서드는 Checked exception을 대응해야 한다는 의미로 이 메서드를 사용 시 try - catch 구문을 명시적으로 작성하도록 강제한다는 의미입니다.

결론적으로 Checked exception을 만들 때는 Exception 클래스를 상속 받고, Unchecked exception을 만들 때는 RuntimeException 클래스를 상속 받는 것이 좋습니다.

어떻게 보면 큰차이는 없지만 의미상 차이가 있으므로, 가급적 언어 스펙에 맞게 코드를 작성하시는 것이 좋습니다.


5. [실습해보기] 예외 처리


1. Unchecked Exception

case 1

코드 작성

public class Main {
    public static void main(String[] args) {
        int index = -1;
        int[] array = {1, 2, 3};
        System.out.println(array[index]);
        System.out.println("프로그램 종료");
    }
}

출력

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: -1

비정상적인 index로 배열에 접근했으므로 예외가 발생합니다. 그러므로 ArrayIndexOutOfBoundsException와 관련된 예외 처리를 해봅시다.


코드 변경

public class Main {
    public static void main(String[] args) {
        int index = -1;
        int[] array = {1, 2, 3};

        try {
            System.out.println(array[index]);
        } catch (ArrayIndexOutOfBoundsException ex) {
            System.out.println("예외 발생");
        }
        System.out.println("프로그램 종료");
    }
}

출력

예외 발생
프로그램 종료

예외가 발생 시 catch 구문으로 이동하여 실행 후 프로그램이 종료되지 않고 그다음 명령어를 실행 후 프로그램이 종료됩니다.


case 2

코드 작성

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        while (true) {
            Scanner scanner = new Scanner(System.in);
            int dividend;
            int divisor;

            System.out.println("피제수를 입력해주세요.");
            dividend = scanner.nextInt();
            System.out.println("제수를 입력해주세요.");
            divisor = scanner.nextInt();
            int quotient = dividend / divisor;
            System.out.printf("%d / %d = %d\n", dividend, divisor, quotient);
        }
    }
}

두 수를 입력하여 몫을 구하는 나눗셈 프로그램입니다. (Scanner 객체를 사용하므로 import를 해주어야 합니다)


입력

0
0

출력

Exception in thread "main" java.lang.ArithmeticException: / by zero

피제수와 제수를 0으로 하면 나눌 수 없으므로 ArithmeticException관련 예외가 발생합니다.


1차 코드 변경

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        while (true) {
            Scanner scanner = new Scanner(System.in);
            int dividend;
            int divisor;

            try {
                System.out.println("피제수를 입력해주세요.");
                dividend = scanner.nextInt();
                System.out.println("제수를 입력해주세요.");
                divisor = scanner.nextInt();
                int quotient = dividend / divisor;
                System.out.printf("%d / %d = %d\n", dividend, divisor, quotient);
            } catch(ArithmeticException ex) {
                System.out.println("0으로 나눌 수 없습니다.");
            }
        }
    }
}

try - catch 구문으로 예외 처리를 해줍시다.


입력

0
0

출력

0으로 나눌 수 없습니다.

예외가 발생했으나 예외 처리가 되어있으므로 프로그램은 종료되지 않습니다.

이번엔 문자를 입력해봅시다.


입력

출력

Exception in thread "main" java.util.InputMismatchException

정수로 변환하는 과정에서 문자를 정수로 바꿀 수 없으므로 InputMismatchException 예외가 발생합니다.


2차 코드 변경

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

public class Main {
    public static void main(String[] args) {
        while (true) {
            Scanner scanner = new Scanner(System.in);
            int dividend;
            int divisor;

            try {
                System.out.println("피제수를 입력해주세요.");
                dividend = scanner.nextInt();
                System.out.println("제수를 입력해주세요.");
                divisor = scanner.nextInt();
                int quotient = dividend / divisor;
                System.out.printf("%d / %d = %d\n", dividend, divisor, quotient);
            } catch(ArithmeticException ex) {
                System.out.println("0으로 나눌 수 없습니다.");
            } catch(InputMismatchException ex) {
                System.out.println("문자를 입력할 수 없습니다.");
            }
        }
    }
}

InputMismatchException 관련 예외 처리를 해줍시다. (다만 해당 예외 처리는 import java.util.InputMismatchException를 작성해 주어야 합니다.)


입력

출력

문자를 입력할 수 없습니다.

예외가 발생했으나 예외 처리가 되어있으므로 프로그램은 종료되지 않습니다.


2. Checked Exception

Checked Exception은 예외 처리가 되어있지 않으면 컴파일이 되지 않습니다.


case 1

코드 작성

public class Main {
    public static void main(String[] args) {
        byte[] numArray = {'1', '2', '3', '4'};
        System.out.write(numArray);
    }
}

System.out.write() 메서드는 바이트 배열을 전달 받아 문자를 출력하는 메서드입니다.


출력

Main.java:10: error: unreported exception IOException; must be caught or declared to be thrown
System.out.write(numArray); 1 error

System.out.write() 메서드는 Checked Exception인 IOException이 선언된 메서드입니다. 그러므로 반드시 try - catch 구문을 작성해주어야 합니다.


코드 변경

import java.io.IOException;

public class Main {
    public static void main(String[] args) {
        byte[] numArray = {'1', '2', '3', '4'};
        try {
            System.out.write(numArray);
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
}

IOException 관련 예외 처리를 해줍시다. (다만 해당 예외 처리는 import java.io.IOException을 작성해 주어야 합니다.)


출력

1234

try - catch 구문을 처리했으므로 정상적으로 컴파일이 되고 프로그램이 실행됩니다.

도전자 질문
작성된 질문이 없습니다
이용약관|개인정보취급방침
알유티씨클래스|대표, 개인정보보호책임자 : 이병록
이메일 : cs@codelatte.io|운영시간 09:00 - 18:00(평일)
사업자등록번호 : 824-06-01921|통신판매업신고 : 2021-성남분당C-0740
주소 : 경기도 성남시 분당구 대왕판교로645번길 12, 9층 24호(경기창조혁신센터)
파일
파일파일
Root
파일

Output
root$