예외처리(Exception)

JOY🌱·2023년 1월 6일
0

☕ Java

목록 보기
33/40
post-thumbnail

💁‍♀️ 예외처리(Exception)란,
프로그램 실행 시 발생할 수 있는 예외에 대비하는 것으로 프로그램의 비정상적인 종료를 막고 실행 상태를 유지하는 것


👀 예외처리 방법

📍 예외처리 방법

1) throws로 위임 : Exception 처리를 호출한 메소드에게 위임
2) try-catch로 처리 : Exception이 발생한 곳에서 직접 처리

◼ ExceptionTest Class

public class ExceptionTest {

	>>> 예외를 발생시키는 메소드
	public void checkEnoughMoney(int price, int money) throws Exception { 
		
		System.out.println("가지고 계신 돈은 " + money + "원 입니다.");
		
		if(money >= price) {
			System.out.println("상품을 구입하기 위한 금액이 충분합니다.");
		} else {
			>>> 강제로 예외를 발생시킴
			>>> 예외를 발생시킨 뒤 메소드 헤드에 throws 구문을 추가
			>>> 예외를 발생시킨 쪽에서는 throws로 예외에 대한 책임을 위임해서 
            >>> 해당 예외에 대한 처리를 강제화
			throw new Exception();
            >>> throws로 떠넘겼기 때문에 아래 프로그램 종료 식이 실행되지 않음
		}
		
		// 예외가 발생하지 않은 경우에만 실행
		System.out.println("즐거운 쇼핑하세요.");
	}

1) throws로 위임

public static void main(String[] args) throws Exception {

	ExceptionTest et = new ExceptionTest();
		
	// 정상 동작 
	et.checkEnoughMoney(10000, 50000);
		
	// 예외 발생
	et.checkEnoughMoney(50000, 10000); 
    >>> throws로 떠넘겼기 때문에 아래 프로그램 종료 구문이 실행되지 않음
    >>> 메소드 내부에서 예외 발생 시 이후 구문은 동작하지않고 호출한 곳으로 되돌아 옴
		
	>>> 이 메인 메소드 또한 예외를 처리하지않고 위임했기 때문에 프로그램은 비정상적으로 
    >>> 종료되고 아래 구문은 출력되지 않음
	System.out.println("프로그램을 종료합니다.");
}

💻 Mini Console

가지고 계신 돈은 50000원 입니다.
상품을 구입하기 위한 금액이 충분합니다.
즐거운 쇼핑하세요.
가지고 계신 돈은 10000원 입니다.
Exception in thread "main" java.lang.Exception
	at com.greedy.section01.exception.ExceptionTest.checkEnoughMoney(ExceptionTest.java:16)
	at com.greedy.section01.exception.Application1.main(Application1.java:19)

2) try-catch로 처리

public static void main(String[] args) {
		
	ExceptionTest et = new ExceptionTest();
		
	try {		
		>>> 예외 발생 가능성이 있는 메소드는 try 블럭 안에서 호출
		et.checkEnoughMoney(10000, 50000); // 정상 동작
		et.checkEnoughMoney(50000, 10000); // 예외 발생
		>>> 예외가 발생한 위치 하단 코드는 동작 X
		System.out.println("============== 상품 구입 가능 =============");
        
	>>> 던져진 예외를 얘가 잡아줌
	} catch (Exception e) { 
		>>> 위의 메소드 호출 시 예외가 발생하는 경우 catch 블럭의 코드를 실행
		System.out.println("============== 상품 구입 불가 =============");
	}
		
		>>> catch 블럭 동작 후 프로그램 정상 흐름으로 돌아옴
		System.out.println("프로그램을 종료합니다.");
}

💻 Mini Console

가지고 계신 돈은 50000원 입니다.
상품을 구입하기 위한 금액이 충분합니다.
즐거운 쇼핑하세요.
가지고 계신 돈은 10000원 입니다.
============== 상품 구입 불가 =============
프로그램을 종료합니다.

👀 사용자 정의 예외

💁‍♀️ 사용자 정의 예외란,
자바 표준 API가 제공하는 예외 클래스만으로 다양한 종류의 예외를 다 표현할 수 없으므로, 직접 예외를 정의하여 사용하는 것

  • 예외 클래스의 이름만으로 어떤 예외가 발생했는지 알 수 있도록 사용자 정의 예외를 사용

◼ ExceptionTest Class

public class ExceptionTest {

	public void checkEnoughMoney(int price, int money) throws PriceNegativeException, MoneyNegativeException, NotEnoughMoneyException  { 
    // : 나를 호출할 때 이 세 가지 Exception이 생길 수 있음
	>>> throw Exception - 3개의 예외 클래스는 모두 Exception 클래스의 후손이므로 
    >>> Exception만으로도 작성할 수 있음 (다형성)
		
		// 상품 가격이 음수인지 확인하고 음수인 경우 예외 발생
		if(price < 0) {
			throw new PriceNegativeException("상품 가격은 음수일 수 없습니다."); // 생성자를 부르고 불러 throwable의 detailMessage = message에 이 문장이 저장
		}
		
		// 가진 돈도 음수인지 확인하고 음수인 경우 예외 발생
		if(money < 0) {
			throw new MoneyNegativeException("가지고 있는 돈은 음수일 수 없습니다.");
		}
		
		// 위의 두 값이 정상 입력 되었더라도 상품 가격이 가진 돈보다 큰 경우 예외 발생
		if(money < price) {
			throw new NotEnoughMoneyException("가진 돈 보다 상품 가격이 더 비쌉니다.");
		}
		
		// 모든 조건을 만족하는 경우 정상적으로 물건 구입 가능
		System.out.println("가진 돈이 충분합니다. 즐거운 쇼핑 하세요~");
}

◼ 3 type of Exceptions

[1] PriceNegativeException Class

public class PriceNegativeException extends Exception {

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

[2] MoneyNegativeException Class

public class MoneyNegativeException extends Exception {

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

[3] NotEnoughMoneyException Class

public class NotEnoughMoneyException extends Exception {

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

◼ Application Class

public static void main(String[] args) {

		ExceptionTest et = new ExceptionTest();
		
		>>> 각각의 예외 상황에 다른 조치가 필요할 경우 예외마다 catch 블럭을 나눠서 작성
//		try {
//			et.checkEnoughMoney(50000, 30000);
//		} catch (PriceNegativeException e) {
//			e.printStackTrace();
//		} catch (MoneyNegativeException e) {
//			e.printStackTrace();
//		} catch (NotEnoughMoneyException e) {
//			e.printStackTrace();
//		}
		
		>>> 모든 예외 상황에 같은 조치를 할 경우 catch 블럭을 multi-catch 블럭으로 작성
		try {
			// 상품 가격보다 가진 돈이 적은 경우
//			et.checkEnoughMoney(50000, 30000);
	
			// 상품 가격을 음수로 입력한 경우
//			et.checkEnoughMoney(-50000, 30000);
			
			// 가진 돈을 음수로 입력한 경우
//			et.checkEnoughMoney(50000, -30000);
			
			// 정상 동작
			et.checkEnoughMoney(30000, 50000);
			
		} catch (PriceNegativeException | MoneyNegativeException | NotEnoughMoneyException e) {
			e.printStackTrace(); 
            >>> printStackTrace() : 콘솔 창에 예외를 출력해주는 메소드
		}
		>>> 예외가 발생하더라도 catch 블럭 실행 후 정상 흐름으로 돌아옴
		System.out.println("프로그램을 종료합니다.");
	}

💻 Mini Console
상품 가격보다 가진 돈이 적은 경우

com.greedy.section02.userexception.exception.NotEnoughMoneyException: 가진 돈 보다 상품 가격이 더 비쌉니다.
	at com.greedy.section02.userexception.ExceptionTest.checkEnoughMoney(ExceptionTest.java:30)
	at com.greedy.section02.userexception.Application1.main(Application1.java:38)
프로그램을 종료합니다.

상품 가격을 음수로 입력한 경우

com.greedy.section02.userexception.exception.PriceNegativeException: 상품 가격은 음수일 수 없습니다.
	at com.greedy.section02.userexception.ExceptionTest.checkEnoughMoney(ExceptionTest.java:20)
	at com.greedy.section02.userexception.Application1.main(Application1.java:41)
프로그램을 종료합니다.

가진 돈을 음수로 입력한 경우

com.greedy.section02.userexception.exception.MoneyNegativeException: 가지고 있는 돈은 음수일 수 없습니다.
	at com.greedy.section02.userexception.ExceptionTest.checkEnoughMoney(ExceptionTest.java:25)
	at com.greedy.section02.userexception.Application1.main(Application1.java:44)
프로그램을 종료합니다.

정상 동작

가진 돈이 충분합니다. 즐거운 쇼핑 하세요~
프로그램을 종료합니다.

👀 finally & try-with-resource

1) finally로 예외 처리

💁‍♀️ finally란,
예외 처리 구문과 상관 없이 반드시 수행해야 하는 경우 작성하며, 보통 사용한 자원을 반납할 목적으로 사용

>>> finally 블럭에서 사용하려면 레퍼런스 변수를 try 블럭 밖에서 선언해야함 
BufferedReader in = null;
		
>>> FileReader을 사용하려면 Exception을 처리해야함 (따라서 try&catch 생성!)
try {
	in = new BufferedReader(new FileReader("test.dat")); 
    >>> in : test.dat라는 파일을 읽어오게끔하는 객체
			
	String s;
			
	>>> readLine() 메소드도 IOExceptionthrows 하므로 catch 블럭을 추가해서 예외 처리 구문을 작성해야함
	while((s = in.readLine()) != null) { // : in을 통해 한 줄을 읽어오겠음
		System.out.println(s); // : 읽은 내용을 출력하겠음
	}
			
} catch (FileNotFoundException | EOFException e) {
		>>> FileNotFoundException : 해당 파일을 찾지 못 한 예외

	>>> FileNotFoundExceptionEOFException을 동시에 처리 (multi-catch)
	>>> 같은 레벨의 자손을 한 번에 처리 가능
	e.printStackTrace();
    
} catch (IOException e) { // 
		>>> IOException : 입출력에 관해 추상화된 예외로 FileNOtFoundExceptionIOException의 후손
	
	e.printStackTrace();
    
} finally {
    
	try {
		>>> close() : 입출력에 사용한 스트림을 닫아주는 메소드
		>>> IOExcetion을 위임한 메소드이기 때문에 finally 블럭 안이이더라도 예외처리를 중첩으로 해야함
				
		if(in != null)	// : null이 아닐 때, close 
        >>> null일 경우 위에서 in을 통해 생성조차 안되었기 때문에 close할 필요도 없음
        
			in.close();		>>> if(in != null)라는 조건이 없으면  java.lang.NullPointerException 에러
	} catch (IOException e) {
		e.printStackTrace();
	} 
}

📌 Ref.

* FileReader라는 클래스의 생성자에 예외를 throws 해놓음. 따라서 사용하는 쪽에서 반드시 예외처리를 
  해야하기 때문에 try-catch 블럭 안에서 생성자를 호출하여 인스턴스를 생성해야함
* catch 블럭은 여러 개를 작성할 시 상위 타입이 하단에 오고 후손 타입이 먼저 작성되어야함. 
  상위 타입이 위에 오면 다형성 적용에 의해 아래 catch 블럭까지 도달하지 못 함 
  (상속관계를 고려하여 위치 설정해야함)
* NullPointerException은 unchecked exception이므로 보통 if 구문으로 해결 가능

2) try-with-resource로 예외 처리

💁‍♀️ try-with-resource란,
close 해야하는 인스턴스의 경우, try 옆에 괄호 안에서 생성하면 해당 try-catch 블럭이 완료될 때 자동으로 close 처리

try (BufferedReader in = new BufferedReader(new FileReader("test.dat"))) {
			
} catch (FileNotFoundException e) {
	e.printStackTrace();
} catch (IOException e) {
	e.printStackTrace();
}

>>> 위와 완전히 동일한 식이지만 훨씬 간결함

👀 예외처리와 오버라이딩

◼ Super Class

public class SuperClass {

	// 예외를 던지는 메소드 하나 작성
	public void method() throws IOException {}
}

◼ Sub Class

public class SubClass extends SuperClass {

[1] 같은 예외를 던져주는 구문으로 오버라이딩 할 수 있음
	@Override
	public void method() throws IOException {}
[2] 부모의 예외처리 클래스보다 상위의 예외로는 후손 클래스에서 오버라이딩 할 수 없음
//	@Override
//	public void method() throws Exception {}
[3] 부모의 예외처리 클래스보다 더 하위에 있는 예외
	(, 더 구체적인 예외)인 경우에는 오버라이딩 할 수 있음
	@Override
	public void method() throws FileNotFoundException {}
[4] 예외 없이 오버라이딩 할 수 있음
	@Override
	public void method() {}

profile
Tiny little habits make me

0개의 댓글

관련 채용 정보