본문 바로가기
국비 교육/백엔드(Java, Spring)

[자바] 예외 Exception

by 육츠 2024. 1. 30.
Contents 접기

예외(Exception) 처리

- 예외도 클래스이다. (Throwable 에서 상속 받았다.)
Throwable (interface) - Exception  - RuntimeException (프로그램으로 처리할 수 있는 오류)
                                                            -  Error (예시 : 메모리 부족) 

- Exception : 실행 도중 발생할 수 있는 여러 가지 예외적인 상황 ( 코드에 의해 수습될 수 있는 미약한 오류) (오류(error))
java 에서의 오류(error) = 코드에 의해 수습될 수 없는 심각한 오류이다.

 

RuntimeException

1) 처리하지 않아도 되는 Exception =  Uncatched Exception
2) 반드시 처리해야하는 Exception = Catched Exception : 메소드를 설계할 때 부터 익셉션을 처리하도록 설계된  Exception

처리 방법  
1) 개발자가 직접 처리

try {
    // 익셉션이 발생할 코드
} catch ( Exception e ) {
    // 처리하는 코드
} catch ( Exception e ) {
    // 처리하는 코드
} finally{
   // 마지막 클린업 해주는 코드
   // finally 오기전에 System.exit(0) 을 만나면 finally 블럭까지 오지 못 한다.
   // return 을 만나면 finally 블럭을 처리하고 반환된다.
}

try {

} catch( Exception e ){

} finally {

}


- 하나의  try블록은 여러개의 exception 을 가질 수 있다.
(하나도 없는 것도 가능하다.)
- if 문과 달리 블럭 내에 포함된 문장이 하나뿐이어도 괄호를 생략하면 안된다.

 

예외 없는 상황

package myexception;

public class ExceptionTest01 {

	public static void main(String[] args) {
		String[] ary = {"1","2","abc"};
		
		int x = Integer.parseInt(ary[0]);
		int y = Integer.parseInt(ary[1]);
		
		double result = x/(double)y;
		System.out.println("연산 결과: " + result);

	}

}

 

예외 상황 1

package myexception;

public class ExceptionTest01 {

	public static void main(String[] args) {
		try {
		String[] ary = {"1","0","abc"};
		
		int x = Integer.parseInt(ary[0]);
		int y = Integer.parseInt(ary[1]);
		
		double result = x/y;
		System.out.println("연산 결과: " + result);
		} catch(ArithmeticException e) {
			System.out.println(e.getMessage());
			e.printStackTrace(); // 스택에 쌓인 오류를 추적
		}
	}

}

오류 : Exception in thread "main" java.lang.ArithmeticException: / by zero at myexception.ExceptionTest01.main(ExceptionTest01.java:13)

코드 의미
System.out.println(e.getMessage()); ' by zero ' 메세지를 출력
e.printStackTrace(); 스택에 쌓인 오류를 추적

 

오류상황 그 외

package myexception;

public class ExceptionTest01 {

	public static void main(String[] args) {
		try {
		//String[] ary = {"1","2","abc"};
		String[] ary = {"1","0","abc"};
		
		int x = Integer.parseInt(ary[0]);
		// int y = Integer.parseInt(ary[1]);
		//int y = Integer.parseInt(ary[2]);
		int y = Integer.parseInt(ary[3]);
		
		// double result = x/(double)y;
		double result = x/y;
		System.out.println("연산 결과: " + result);
		} catch(ArithmeticException e) {
			System.out.println(e.getMessage());
			e.printStackTrace(); // 스택에 쌓인 오류를 추적
		}catch(NumberFormatException e) {
			System.out.println(e.getMessage());			
			e.printStackTrace();
		}catch(ArrayIndexOutOfBoundsException e) {
			e.printStackTrace();	
			return; // 무조건 finally를 들른다. -> 반환
			// System.exit(0); // 들르지 않는다. -> 처리 안 하고 반환
		}finally {
			System.out.println("반드시 들러야 하는 블럭");
			
		}
		
		System.out.println("마지막 처리하는 코드");
		
	}

}
코드 의미
return;  무조건 finally를 들른다. 
System.exit(0);   finally 들르지 않는다.
System.out.println("마지막 처리하는 코드");
return;  -> 반환
System.exit(0); -> 처리 안 하고 반환

 

오류 직접 발생

package myexception;

public class ExceptionTest02 {

	public static void main(String[] args) {
		int a = 12, b = -10;
		int c = 0;
		
		try {
			c = add(a,b);
		}catch(Exception e) {
			e.printStackTrace();
			return;
		}
		System.out.println("결과는 " + c);
	}
	// y는 절대 음수일 수 없는 상황이라고 가정
	public static int add(int x, int y) throws Exception {
		if(y < 0) {
			// 강제 exception
			throw new Exception("y 값은 음수가 될 수 없습니다.");
		}
		int result = x + y;
		return result;
	}
}
코드 의미
public static int add(int x, int y) throws Exception {
    if(y < 0) {
        throw new Exception("y 값은 음수가 될 수 없습니다.");
}
키워드 throws 를 사용하여 예외 처리 선언

 

# main 바깥으로 (권장 사항은 아님)

현재 발생한 익셉션을 내부에서 해결하지 않고 바깥으로 던진 것 이다.

package myexception;

public class ExceptionTest02 {

	public static void main(String[] args) throws Exception {
		int a = 12, b = -10;
		int c = 0;

		c = add(a,b);

		System.out.println("결과는 " + c);
	}
	// y는 절대 음수일 수 없는 상황이라고 가정
	public static int add(int x, int y) throws Exception {
		if(y < 0) {
			// 강제 exception
			throw new Exception("y 값은 음수가 될 수 없습니다.");
		}
		int result = x + y;
		return result;
	}
}

 

package myexception;

public class ExceptionTest02 {

	public static void main(String[] args) {
		int a = 12, b = -10;
		int c = 0;

		c = add(a,b);

		System.out.println("결과는 " + c);
	}
	// y는 절대 음수일 수 없는 상황이라고 가정
	public static int add(int x, int y)  {
		int result = 0;

		try{
			if(y < 0)
				// 강제 exception
				throw new Exception("y 값은 음수가 될 수 없습니다.");

			result = x + y;
		} catch(Exception e) {
			e.printStackTrace();
		}

		return result;
	}
}

 

multi catch Exception

package myexception;

public class ExceptionTest01 {

	public static void main(String[] args) {
		try {
		String[] ary = {"1","0","abc"};
		
		int x = Integer.parseInt(ary[0]);
		int y = Integer.parseInt(ary[2]);
		
		double result = x/y;
		System.out.println("연산 결과: " + result);
		
		
		} catch(ArithmeticException | NumberFormatException | ArrayIndexOutOfBoundsException e) {
			
			System.out.println(e.getMessage());
			e.printStackTrace(); 
		}finally {
			System.out.println("반드시 들러야 하는 블럭");
		}
		
		
	}

}
코드 의미
catch(ArithmeticException | NumberFormatException | ArrayIndexOutOfBoundsException e) {
    ....
}
하나씩 catch 문을 쓰는게 아닌 ' | '를 사용하여 구분시켰다.

 

[문제] 키보드로부터 정수형 데이터 5개를 입력 받아 합계를 누적해서 출력하시오.

<실행 예시>
값 입력 : 1
현재까지 합계 : 1

값 입력 : 3
현재까지 합계 : 4

값 입력 : a
현재까지 합계 : 4

값 입력 : 3
현재까지 합계 : 7

값 입력 : b
현재까지 합계 : 7

 

main

package myexception;

import java.util.Scanner;

public class ExceptionTest04 {
	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		int total = 0;
		int num;


		for(int i = 0 ; i< 5; i++) {
			try {
				System.out.printf("%d 번째 값 입력 >> ", i+1);
				num = scanner.nextInt();   // 예외가 발생할 코드
				scanner.nextLine(); 
	

				total += num;
				System.out.println("현재까지 합계 = " + total);
			} 
			catch(Exception e) {
				scanner.nextLine(); 
				--i;
				continue;
			}
		}
		System.out.println("## 프로그램을 종료합니다.");
		scanner.close();
	}
}

scanner 를 사용해서 입력받으면 숫자만 들어올 수 있게 설정 되어 있다.. 이걸 까먹었었네..ㅜㅜ

 

Exception 만들기

package myexception;

// @SuppressWarnings("serial") // 시리얼 번호가 없어도 워닝을 띄우지 않게
public class MemberException extends Exception {
	
	private static final long serialVersionUID = 1L;
	// 객체 직렬화 시에 사용된다.
	
	public MemberException(String message) {
		super(message);
	} // 기본생성자 + 메세지 전달
	
	

}
package myexception;

import java.util.Scanner;

public class MemberExceptionTest {

	public static void main(String[] args)  {
		Scanner scanner = new Scanner(System.in);
		String userid;

		while(true) {
			System.out.print(">> 아이디를 2~5자 이내로 입력하세요: ");
			userid = scanner.next();
			try {
				if(userid.length() < 2 || userid.length() > 5) {
					throw new MemberException("## 아이디를 2~5자 이내로 입력하세요!!!");
				} else {
					System.out.println("Gooood~");
					break;
				}
			}catch(MemberException e) {
				System.out.println(e.getMessage());
				scanner.nextLine();
				continue;
				
			}
		}
	}

}

>> 아이디를 2~5자 이내로 입력하세요: w2e34567
## 아이디를 2~5자 이내로 입력하세요!!!

>> 아이디를 2~5자 이내로 입력하세요: cvfg
Gooood~