티스토리 뷰
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 |