본문 바로가기
Web/JAVA

예외 처리(exception handling)

by 당진개발자 2024. 1. 22.

1. 에러와 예외

1) 에러(Error) : 프로그램을 잘 못 작성한 경우

  - 메모리 부족, Stack Overflow등

  - 디버깅으로 코드 개선

2) 예외(Exception) : 프로그램을 잘못 작성한 경우, 프로그램의 작성 의도와 달리 사용되는 경우

  - null인 객체의 사용, 1/0, 읽으려는 파일이 없음

  - 디버깅으로 코드 개선, 예외 처리 코드로 상황 수습

 


 

2. 예외 처리(exception handling)

예외 발생 시 프로그램의 비 정상 종료를 막고 정상적인 실행 상태를 유지하는 것 (예외 감지, 발생 시 동작 코드 작성)

1) 예외 종류

  - checked exception : 예외에 대한 대처 코드가 없으면 컴파일 진행 X, Exception은 checked

  - unchecked exception(runtime exception 상속) : 예외에 대한 대처 코드가 없더라도 컴파일은 진행 O

2) try ~ catch ~ finally 예외 처리

  - 다중 try ~ catch시 상속관계에서는 작음 범위에서 큰 범위 순으로 정의

  - 상속 관계가 없을 때는 순서 무관

public class UseInstaller {
    public static void main(String[] args) {
    	InstallApp app = new InstallApp();
    	try {
    		app.copy();
        	app.install();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			app.delete();
		}
        System.out.println("설치 종료");
    }
}

 

3) Throwable의 주요 메서드

  - getMessage() : 발생된 예외에 대한 구체적인 메세지를 반환

  - getCause() : 예외의 원인이 되는 Throwable 객체 또는 null을 반환

  - printStackTrace() : 예외가 발생된 메서드가 호출되기까지의 메소드 호출 스택을 출력, 디버깅 수단

 


 

3. throws

※ method에서 처리해야 할 하나 이상의 예외를 호출한 곳으로 전달(처리 위임)

1) checked exception과 throws, unchecked exception과 throws

  - checked exception은 항상 throws로 던져줘야 함, 명시적 예외 처리

  - unchecked exception는 따로 throws를 안해도 자동으로 호출 부분에 던져진다, 묵시적 예외 처리

  - 메서드 재정의 시 조상 클래스 메서드가 던지는 예외보다 부모 예외를 던질 수 없다.

ex) 부모에서 ClassNotFoundException을 던지기 자식에서 Exception 던지기 >> 오류 발생

public class ThrowsTest {
	public static void main(String[] args) {
		try {
			methodCall1();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (ArithmeticException e) {
			e.printStackTrace();
		}
		System.out.println("done");
	}

	private static void methodCall1() throws ClassNotFoundException {
		methodCall2();
	}

	private static void methodCall2() throws ClassNotFoundException {
		uncheckedExceptionMethod();
		checkedExceptionMethod();
	}

	@SuppressWarnings("unused")
	private static void checkedExceptionMethod() throws ClassNotFoundException {
		Class.forName("Hello");
	}

	@SuppressWarnings("unused")
	private static void uncheckedExceptionMethod() {
		int i = 1 / 0;
	}

}

 

- 하위 계층에서 발생한 예외는 상위 계층에 맞는 예외로 바꿔서 던져야 한다.

package com.ssafy.day6.c_throws;

import javax.management.RuntimeErrorException;

public class ExceptionChaining {
	public static void main(String[] args) {
		OnlineShop shop = new OnlineShop();
		// TODO: 03. shop을 통해 주문해보자.
		shop.order();
		// END
		System.out.println("상품 주문 사용 완료!");
	}
}

class OnlineShop {

	public void order() {
		try {
			packaging();
			delivery();
			System.out.println("상품이 정상적으로 배송 되었습니다.");
		} catch (RuntimeException e) {
			throw new IllegalStateException(e);
		}
		// TODO: 02. 주문 처리 과정에서 발생하는 예외를 처리하고 IllegalStateException을 발생시켜보자.

		// END
	}

	private void packaging() {
		System.out.println("상품을 포장합니다.");
	}

	private void delivery() {
		deliveryToWareHouse();
		deliveryToCustomer();
	}

	private void deliveryToWareHouse() {
		System.out.println("물류 창고로 배송합니다.");
	}

	private void deliveryToCustomer() {
		System.out.println("고객에게 배송합니다.");
		// TODO: 01. 임의로 RuntimeException 계열의 예외를 발생시켜 보자.
		throw new RuntimeException("도로가 결빙입니다.");
		// END
	}

}

 

2) 로그 분석과 예외의 추적

  -  printStackTrace는 메서드 호출 스택 정보 조회 가능

  - 예외 종류, 예외 원인, 디버깅 출발점은 꼭 확인해야 함.

 


 

4. 사용자 정의 예외

※ API에 정의된 exception이외에 필요에 따라 사용자 정의 예외 클래스 작성

1) 장점

  - 객체의 활용 - 필요한 추가 정보, 기능 활용 가능

  - 코드의 재사용 - 동일한 상황에서 예외 객체 재사용 가능

  - throws 메커니즘의 이용 - 중간 호출 단계에서 return 불필요

//public class LottoException extends RuntimeException { // unchecked
public class LottoException extends Exception{ // checked
	public LottoException() {
    	super("예외가 발생했습니다!");
    }
}

package com.ssafy.day6.d_custom;

import java.util.Random;

public class LottoTest {
	static int makeNumber() {
		Random r = new Random();
		int num = r.nextInt(10000);
		return num;
	}
	
	private static void lottoService() throws LottoException {
		int num = makeNumber(); // 1 ~ 45의 수가 아니면 에러 발생 시키자!
		if (num < 1 || num > 45) {
			throw new LottoException();	// 에외의 강제 발생
		}
	}
	
	public static void main(String[] args) {
		try {
			lottoService();
		} catch (LottoException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
		System.out.println("정상종료 처리됨");
	}
}