티스토리 뷰

1. 예외처리 개요

1-1. 예외 처리 정의 및 사용 이유

1-1-1. 예외 처리란?

💡 오류(Error)와 예외(Exception)
오류 : 시스템 상에서 프로그램에 심각한 문제가 발생하여 실행중인 프로그램이 종료되는 것.
          개발자가 미리 예측하거나 코드로 처리하는 것이 불가능
          (ex. JVM 에러, 정전, 컴퓨터 자체 하드웨어적인 문제 등)

예외 : 개발자가 미리 예측하고 처리할 수 있는 미약한 오류.
          오류와 마찬가지로 실행중인 프로그램을 종료시키는 것이 일반적

예외 상황의 경우는 개발자가 적절히 처리하여 코드의 흐름을 컨트롤(비정상적인 종료를 할 수도 있고 그렇지 않게 할 수도 있게) 할 수 있다.

1-1-2. 예외 처리를 사용하는 이유

💡 오류나 예외는 사용자에게 좋지 않은 사용 경험을 제공. 하지만 미리 예측하고 컨트롤 할 수 있는 예외를 처리함으로써 프로그램이 예상치 못한 상황에 봉착하지 않도록 코드의 안정성과 신뢰성을 높여 이를 미연에 방지하거나 의도한 방향으로 컨트롤 할 수 있다.
또한 개발 시에도 디버깅을 용이하게 해서 예외가 발생한 원인과 위치도 쉽게 파악할 수 있어 용이

2. 예외 클래스의 종류

2-1. 예외 클래스의 계층구조

  • 오류와 예외는 모두 Throwable을 상속 받는다.
  • 예외의 최상위 클래스는 Exception 클래스.
  • Unchecked Exception 계열은 기본적 이미 처리되어 있고 실행 중인 프로그램이 종료되게 작성.
  • Checked Exception 계열은 반드시 예외 처리를 해야 하고 하지 않으면 컴파일 에러가 발생.
  • RuntimeException 타입의 예외들은 런타임 시점에 해당 예외 클래스 타입의 Exception이 발생.

2-2. RuntimeException 후손 클래스 몇 가지

  • ArithmeticException
    0으로 나누는 경우 발생
  • ArrayIndexOutOfBoundsException
    배열의 index 범위를 넘어서 참조하는 경우 발생
  • NullPointerException
    인스턴스가 참조되지 않은 상태(Null)로 인스턴스에 접근하는 경우 발생
  • ClassCastException
    형변환(Cast 연산자 사용) 시 자료형에 문제가 있을 때 발생
  • NegativeArraySizeException
    배열 크기를 음수로 지정한 경우 발생

3. 예외 처리 방법

package com.ohgiraffers.section01.exception;

public class Application {

    /* 설명. try-catch 대신 throws로 처리하면 메소드를 호출한 대상에게 예외처리를 위임한다. */
//    public static void main(String[] args) throws Exception {
public static void main(String[] args) {

    /* 수업목표. 예외에 대해 이해하고 이를 처리하기 위한 문법을 활용할 수 있다. */
    /* 필기.
        *   1. throws를 통한 위임
        *   2. try-catch를 통한 처리
        *  */

        ExceptionTest et = new ExceptionTest();

        /* 설명. try-catch를 통해 예외상황을 원하는 의도대로 처리할 수 있다. */
        try {

            /* 설명. 우리가 처리할 예외가 발생할 수 있는 적당한 범위를 try 블럭으로 감싼다. */
            et.checkEnoughMoney(10000, 50000);
            et.checkEnoughMoney(50000, 10000);             // 오류 발생!!!!!
            System.out.println("이전에 문제가 없었으면 실행될 추력 구문");   // 문제가 있으면 출력 되지 않음.
        } catch (Exception e) {

            /* 설명. 우리가 원하는 방식대로 try 블럭에서 발생한 예외 타입 객체를 활용해서 처리할 수 있다. */
            /* 설명. try 블럭에서 예외가 발생하지 않으면 실행되지 않는 블럭 */
            System.out.println("뭔가 예외가 발생했나 보네?");
            System.out.println("그 예외는 " + e.getMessage() + "!!!!");
            System.out.println("돈 좀 넉넉히 들고 다니지!~");

            /* 설명. 내가 원하는 시점에 프로그램을 종료할 수 있음 */
//            System.exit(0);               // 프로그램 종료

            /* 설명. JVM 처럼 우리도 예외가 각각 어떤 흐름으로 발생하는지 처리할 수 있음 */
            e.printStackTrace();                // 프로그램 종료하는 기능은 없음
        }
        // 메소드 안에서 처리를 해야하기 때문에 메인에서 처리하기 힘들다....
        // 메인에서 처리하기 위해 try-catch 사용!

//        et.checkEnoughMoney(50000,10000);   // JVM이 처리 / throws 할 때 잠깐 활용한 구문
//                                            // main에서 throws Exception 사용 시
//        try {
//            int num = 10;
//            System.out.println(num / 0);
//        } catch (ArithmeticException e) {
//
//            /* 설명. unchecked exception도 우리가 처리할 수 있고 exception 객체까지 활용할 수 있다. */
//            System.out.println("잘 좀 나누지~ 0이 뭐냐~");
//            System.out.println(e.getMessage() + "라잖아~");
//        }
        System.out.println("프로그램을 종료합니다.");
    }
}
package com.ohgiraffers.section01.exception;

public class ExceptionTest {

    public void checkEnoughMoney(int price, int money) throws Exception {
        System.out.println("가지고 계신 돈은 " + money + "원 입니다.");

        if (money >= price) {
            System.out.println(price + "원 상품을 구입하기 위한 금액이 충분합니다.");
            return;
        }

//        System.out.println("호주머니 상황이 딱하군요.");
        throw new Exception("호주머니 상황이 딱하군요.");      // 여기에 매개변수는? -> 활용 가능(e.getMessage())
                                                        // 다형성 적용 가능 (ArithmeticException 이라 해도 가능)
    }
}

3-1. throws로 위임

💡 Exception이 발생하는 메소드(또는 생성자)를 호출한 상위 메소드에게 처리를 위임하는 방식.

 

3-2. try-catch(또는 try-catch-finally)로 처리

💡 발생한 Exception을 직접 처리하는 방식.

  • try 블럭
    • 예외(Exception)가 발생할 가능성이 있는 코드를 포함하여 작성하는 블럭
  • catch 블럭
    • try 블럭에서 예외 발생 시 해당 예외 타입(Exception 클래스 타입)에 대한 처리를 기술하는 블럭.
    • 여러 개의 catch 블럭을 이어서 사용할 수 있다.
    • 상위 타입의 예외를 처리하는 catch 블럭이 아래 쪽에 위치해야 함.
  • finally 블럭
    • 예외 발생 여부와 상관 없이 꼭 실행되어 처리해야 할 코드가 있으면 작성하는 블럭.
    • 주로 java.io나 java.sql 패키지의 메소드 처리 시 자원 반납을 위해 사용.

3-3. 오버라이딩 시 예외 발생 가능 범위

  • 상속 시 오버라이딩하는 메소드는 부모 클래스의 원본 메소드보다 더 상위 타입의 예외를 발생 시키면 안된다.
package com.ohgiraffers.section04.override;

import java.io.IOException;

public class Application {
    public static void main(String[] args) {
//        SuperClass sc = new SuperClass();

        /* 설명. 다형성 적용 시 */
        SuperClass sc = new SubClass();
        try {

            /* 설명. 동적 바인딩에 의해 자식의 오버라이딩한 메소드가 실행 된다면(동적 바인딩) */
            sc.method();
        } catch (IOException e) {           // 부모의 method()만 고려해 처리한 예외처리가 문제 될 수 있다.
            throw new RuntimeException(e);
        }
    }
}
package com.ohgiraffers.section04.override;

import java.io.IOException;

public class SuperClass {
    public void method() throws IOException {

    }
}
package com.ohgiraffers.section04.override;

import java.io.FileNotFoundException;
import java.io.IOException;

public class SubClass extends SuperClass {

    /* 설명. 부모 메소드의 예외와 같은 범위 처리(pass) */
    @Override
    public void method() throws IOException {
        super.method();
    }

    /* 설명. 부모 메소드와 달리 예외를 발생시키지 않는다면(pass) */
    @Override
    public void method() {
    }

    /* 설명. 부모 메소드보다 더 낮은(적은) 범위의 예외 발생(pass) */
    @Override
    public void method() throws FileNotFoundException {
    }

    /* 설명. 부모의 메소드보다 상위 타입의 예외 발생(fail) - 컴파일 에러 발생 */
    @Override
    public void method() throws Exception {
    }
}

 

userexception
package com.ohgiraffers.section02.userexception;

import com.ohgiraffers.section02.userexception.exception.MoneyNegativeException;
import com.ohgiraffers.section02.userexception.exception.NotEnoughMoneyException;
import com.ohgiraffers.section02.userexception.exception.PriceNegativeException;

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

        /* 수업목표. 사용자 정의형 예외클래스 정의 후 발생한 사용자 예외들을 처리할 수 있다. */
        ExceptionTest et = new ExceptionTest();
        try {
            et.checkEnoughMoney(30000,40000);
//            et.checkEnoughMoney(-30000,40000);
//            et.checkEnoughMoney(30000,-40000);
            et.checkEnoughMoney(100000,10);
        } catch (PriceNegativeException e) {
            System.out.println(e.getMessage());
        } catch (MoneyNegativeException e) {
            System.out.println(e.getMessage());
        } catch (NotEnoughMoneyException e) {
            System.out.println(e.getMessage());
        } catch (Exception e) {
            System.out.println("어떤 예외든 커몬");
            System.out.println("어떤 예외든 메시지는: " + e.getMessage());   // 부모 exception일수록 아래에 작성해야 한다.
        }
    }
}
package com.ohgiraffers.section02.userexception;

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

        /* 수업목표. finally를 활용한 try-catch문 이해하고 활용하기 */
        ExceptionTest et = new ExceptionTest();
        try {
            et.checkEnoughMoney(20000,50000);
        } catch (Exception e) {
            System.out.println("유효성 검사 시 문제 발생: " + e.getMessage());
        } finally {

            /* 설명. try 구문에서 예외가 발생하든 하지 않든 반드시 실행해야 할 구문이 있담녀 작성하는 부분 */
            System.out.println("finally 블럭의 내용 동작함...");
        }

        System.out.println("프로그램을 종료합니다.");
    }
}
package com.ohgiraffers.section02.userexception;

import com.ohgiraffers.section02.userexception.exception.MoneyNegativeException;
import com.ohgiraffers.section02.userexception.exception.NotEnoughMoneyException;
import com.ohgiraffers.section02.userexception.exception.PriceNegativeException;

public class Application3 {
    public static void main(String[] args) throws NotEnoughMoneyException, MoneyNegativeException, PriceNegativeException {

        /* 수업목표. multi-catch 구문을 이해하고 활용할 수 있다. */
        ExceptionTest2 et = new ExceptionTest2();
        try {
            et.checkEnoughMoney(20000,10);
        } catch (PriceNegativeException | MoneyNegativeException e) {
            System.out.println("두 개의 예외 처리 방식");
        } catch (NotEnoughMoneyException e) {
            System.out.println("한 개의 예외 처리 방식");
            e.printStackTrace();
        } finally {
            System.out.println("반드시 실행되어야 하는 구문");
        }

        System.out.println("프로그램 종료");

    }
}
package com.ohgiraffers.section02.userexception;

import com.ohgiraffers.section02.userexception.exception.MoneyNegativeException;
import com.ohgiraffers.section02.userexception.exception.NotEnoughMoneyException;
import com.ohgiraffers.section02.userexception.exception.PriceNegativeException;

public class ExceptionTest {

//    public void checkEnoughMoney(int price, int money) throws PriceNegativeException, MoneyNegativeException, NotEnoughMoneyException {
    public void checkEnoughMoney(int price, int money) throws Exception {   // 다형성 때문에 가능
        if (price < 0) {
            throw new PriceNegativeException("상품 가격은 음수일 수 없습니다.");
        }

        if (money < 0) {
            throw new MoneyNegativeException("가지고 있는 돈은 음수일 수 없습니다.");
        }

        if (money < price) {
            throw new NotEnoughMoneyException("가진 돈보다 상품 가격이 더 비쌉니다.");
        }

        System.out.println("가진 돈이 충분하시군요 고객님! 즐거운 쇼핑 되세요!");
    }
}
package com.ohgiraffers.section02.userexception;

import com.ohgiraffers.section02.userexception.exception.MoneyNegativeException;
import com.ohgiraffers.section02.userexception.exception.NotEnoughMoneyException;
import com.ohgiraffers.section02.userexception.exception.PriceNegativeException;

public class ExceptionTest2 {

    public void checkEnoughMoney(int price, int money) throws PriceNegativeException, MoneyNegativeException, NotEnoughMoneyException {
        if (price < 0) {
            throw new PriceNegativeException("상품 가격은 음수일 수 없습니다.");
        }

        if (money < 0) {
            throw new MoneyNegativeException("가지고 있는 돈은 음수일 수 없습니다.");
        }

        if (money < price) {
            throw new NotEnoughMoneyException("가진 돈보다 상품 가격이 더 비쌉니다.");
        }

        System.out.println("가진 돈이 충분하시군요 고객님! 즐거운 쇼핑 되세요!");
    }
}

 

 

userexception.exception
package com.ohgiraffers.section02.userexception.exception;

public class MoneyNegativeException extends Exception {

    public MoneyNegativeException(String message) {
        super(message);
    }
}
package com.ohgiraffers.section02.userexception.exception;

public class NotEnoughMoneyException extends Exception {

    public NotEnoughMoneyException(String message) {
        super(message);
    }
}
package com.ohgiraffers.section02.userexception.exception;

public class PriceNegativeException extends Exception {

    public PriceNegativeException(String message) {
        super(message);
    }
}

3-4. 예외처리를 많이 사용하는 io 패키지와 관련한 try-catch 구문

package com.ohgiraffers.section03.uses;

import java.io.*;

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

        /* 수업목표. 예외처리를 많이 사용하는 io패키지와 관련한 try-catch 구문을 이해할 수 있다. */
        /* 설명.
        *   예외 처리를 가장 많이 사용하게 되는 상황(io 패키지 관련)에서 try-catch 구문을 실제 상황과
        *   유사하게 연습해 보자.
        *   (입출력 관련 문법을 하나하나 신경쓰기 보다는 호출 흐름에 신경 쓰자.)
        * */

        /* 설명. 프로젝트 바로 아래 test.dat 파일이 있다면(File 객체 생성) 해당 경로의 절대 경로를 출력 */
        System.out.println(new File("test.dat").getAbsolutePath());

        BufferedReader br = null;       // 파일을 읽어오기 위한 통로?

        try {
            br = new BufferedReader(new FileReader("test1.dat"));
        } catch (FileNotFoundException e) {
            System.out.println("파일이 없나보네?");
        } finally {

            /* 필기.
            *   예외처리 구문과 상관없이 반드시 수행해야 하는 경우 finally에 작성하는데
            *   보통 사용한 자원(resource)을 반납할 목적으로 사용하게 된다.
            *  */
            try {

                /* 필기.
                *   스트림(입출력 관련 통로)이 생성되지 않았을 때 접근해서 close() 메소드를 호출하게 되면
                *   NullPointerException이 발생할 수 있다. 따라서 if 문을 활용해 처리한다.
                *  */
                if (br != null) {       // NullPointerException 해결하기 위해

                    /* 필기.
                    *   입출력에서 사용한 스트림을 닫아주는 메소드이다.
                    *   API에서 확인해보면 IOException을 throws하는 메소드이기 떄문에
                    *   finally 블럭 안이라도 추가 예외처리를 중첩으로 해 주어야 한다.
                    *  */
                    br.close();
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

// 실행 결과
/Users/kimjeongmo/Desktop/한화시스템 Beyond SW/lecture/01_java/chap10-exception-lecture-source/test.dat

파일이 없나보네?

3-5. try-with-resource 구문

package com.ohgiraffers.section03.uses;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

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

        /* 수업목표. try-with-resource 구문을 이해하고 활용할 수 있다.(feat. finally 안 쓰기) */
        try (BufferedReader br = new BufferedReader(new FileReader("test.dat"))) {

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

'한화시스템 > 백엔드' 카테고리의 다른 글

[BE] JAVA_입출력_파일 클래스(File Class)  (5) 2024.07.22
[BE] JAVA_입출력_개요  (1) 2024.07.22
[BE] JAVA_API_Time 패키지  (0) 2024.07.20
[BE] JAVA_API_Wrapper  (1) 2024.07.19
[BE] JAVA_API_StringBuilder & StringBuffer  (1) 2024.07.19
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2024/10   »
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
글 보관함