관리 메뉴

나구리의 개발공부기록

자바의 정석 기초편 ch8 - 7 ~ 10[printStackTrace(), 멀티 catch블럭, 예외 발생 시키기] 본문

유튜브 공부/JAVA의 정석 기초편(유튜브)

자바의 정석 기초편 ch8 - 7 ~ 10[printStackTrace(), 멀티 catch블럭, 예외 발생 시키기]

소소한나구리 2023. 12. 4. 15:04

1) 예외 정보 확인

  • 예외가 발생하면 예외 객체가 생성이 되는데 해당 객체의 메서드들을 통해 예외의 정보를 확인할 수 있음

(1) printStackTrace()

  • 예외 발생 당시의 호출스택에 있었던 메서드의 정보와 예외 메시지를 화면에 출력

(2) getMessage()

  • 발생한 예외클래스의 인스턴스에 저장된 메시지를 얻을 수 있음

(1) 예제

  • printStackTrace() 메서드를 호출하여 예외 정보를 출력
  • getMessage() 메서드를 호출하여 예외 메시지를 출력
class Ex8_5 {
	public static void main(String args[]) {
		System.out.println(1);			
		System.out.println(2);

		try {
			System.out.println(3);
			System.out.println(0/0); // 예외발생!! - 예외객체 생성(예외의 정보가 들어있음)
			System.out.println(4);   // 실행되지 않음
            
		} catch (ArithmeticException ae)	{
			ae.printStackTrace();
			System.out.println("예외메시지 : " + ae.getMessage());
            
		}	// try-catch의 끝

		System.out.println(6);
	}	// main메서드의 끝
}

출력결과
1
2
3
// ae.printStackTrace(); 메서드 출력 결과 - 예외 정보
java.lang.ArithmeticException: / by zero
	at ex8_5.main(ex8_5.java:8)
// ae.getMessage(); 메서드 출력 결과 - String으로 메시지 반환
예외메시지 : / by zero
6

2) 멀티 catch블럭

  • 내용이 같은 catch블럭을 하나로 합친 것(JDK1.7 부터가능)
  • 코드의 중복을 제거할 수 있음

(1) 주의사항

  • 부모자식 관계인 경우 멀티 catch 블럭을 활용하면 컴파일 에러가 발생함
  • 조상 타입으로 예외를 처리하면 이미 하위의 예외는 처리가 되어 버리기 때문에 애초에 멀티블럭으로 예외를 처리하는 의미가 없음 
  • 멀티 catch블럭을 사용할 경우 선언된 예외가 공통으로 가지는 메서드만 호출할 수 있음

(2) 예제

  • 멀티 캐치 블럭을 사용한 경우 선언된 예외가 부모자식이면 예외가 발생하므로 조상타입으로 예외를 처리
  • 멀티 캐치 블럭의 선언된 예외의 공통 메서드가 아닌 각각의 메서드를 호출하려고하면 다시 한번 if문으로 예외가 맞는지 확인하는 조건을 처리해야함
  • 이런 경우에는 오히려 각각의 catch문으로 적용하는게 좋음
try {
	...
} catch (ExceptionA e) {
	e.printStackTrace();
} catch (ExceptionB e2) {
	e2.printStackTrace();
}

// 위의 동일한 예외를 처리하는 catch문을 멀티캐치블럭으로 변경

try {
	...
} catch (ExceptionA | ExceptionB e) {
	e.printStackTrace();
}

// 주의점1
try {
	...
} catch (ExceptionA | ExceptionB e) { // 두 타입이 부모 자식 관계인 경우 -> 컴파일 에러 발생
} catch (ExceptionA e) {  // 조상 타입으로 예외 처리를해도 그 하위 예외는 모두 처리되기 때문
	e.printStackTrace();
}

// 주의점2
try {
	...
} catch (ExceptionA | ExceptionB e) {
	e.methodA();    // ExceptionA의 메서드만 호출 -> 에러
                    // ExceptionA,B의 공통멤버만 사용 가능
    
    // 꼭 사용 해야 한다면 아래처럼 사용
    if(e instanceof ExceptionA) {       // instanceof로 확인 후 맞으면 실행
    	ExceptionA e1 = (ExceptionA)e;  // 형변환
        e1.methodA();	// ExceptionA에 선언된 메서드 호출 가능
    } else { // if(e instanceof ExceptionB)
    .....
}

3) 예외 발생 시키기

(1) 예외 발생 방법

  • 직접 객체 생성하는 방법과 똑같이 연산자 new를 사용해서 발생시키려는 예외 클래스의 객체를 만든 후 참조변수를 throw로 던짐
  • Exception e = new Exception();
  • throw e;
  • throw new Exception(); 으로 한 번에 예외를 던질 수도 있음
  • 객체 생성시 인자로 에러메시지를 작성할 수 있음

(2) 예제

  • Exception 예외를 고의로 생성하여 throw 연산자로 발생된 예외를 던짐
class Ex8_6 {
	public static void main(String args[]) {
		try {
			Exception e = new Exception("고의로 발생시켰음."); // 에러메시지 작성
			throw e;	 // 예외를 발생시킴
			
			//  throw new Exception("고의로 발생시켰음."); 위 두줄을 한줄로 할 수 있음

		} catch (Exception e)	{
			System.out.println("에러 메시지 : " + e.getMessage()); // 에러메시지 출력
			e.printStackTrace();	// 에러정보 출력
		}
        
		System.out.println("프로그램이 정상 종료되었음.");
	}
}


출력결과

//에러메시지 출력 e.getMessage();
에러 메시지 : 고의로 발생시켰음.
//에러 정보 출력 e.printStackTrace();
java.lang.Exception: 고의로 발생시켰음.
	at ex8_6.main(ex8_6.java:4)
프로그램이 정상 종료되었음.

 

4) checked예외

  • Exceptions과 그 자손을 통칭함
  • 컴파일러가 예외 처리 여부를 체크하기 때문에 예외처리를 필수로 해야하는 예외
  • 프로그램 실행 전에 에러 여부를 미리 할 수 있으므로 친절한 예외로 인식되어있지만 이로인해 불편한점도 다소 존재하는 부분도 있음
  • 이부분은 애플리케이션을 실제 개발해보아야 알 수 있음 -> 스프링 강의내용 참고
class Ex8_7 {
	public static void main(String[] args) {
		throw new Exception();		// Exception(checked예외)을 고의로 발생
        // 컴파일러가 예외 처리 여부를 체크
	}
}

// 컴파일 에러 발생 -> 예외 처리가 필수

class ex8_7 {
	public static void main(String[] args) {
		try {
			throw new Exception();
			
		} catch(Exception e) {	// 예외 처리
			// 체크드 예외는 꼭 예외를 처리해야 프로그램이 실행 됨
		}
	}
}

 

5) unchecked예외

  • RuntimeException과 그자손을 통칭함
  • 컴파일러가 예외 처리 여부를 체크 하지 않으므로 예외를 선택적으로 처리할 수 있음
  • checked 에러로 인해 코드에 try-catch로 모두 도배되지 않도록 할 수 있음, 즉 해당 예외를 처리하고자 하는 곳에서 정상흐름으로 반환하던지, 아니면 예외를 프로그램 밖으로 던져 오류메시지를 출력할 것인지 선택할 수 있음
  • 이부분도 실제 애플리케이션을 개발해봐야 흐름을 알 수 있음 -> 스프링 강의 내용 참고
class Ex8_8 {
	public static void main(String[] args) {
		throw new RuntimeException();	// RuntimeException(unchecked예외)을 고의로 발생
        // 컴파일러가 예외 처리를 안함 -> 예외 처리를 선택할 수 있음
	}
}

// 실행 시 런타임에러(실행에러)가 발생하여 비정상종료 발생

public class ex8_8 {
	public static void main(String[] args) {
		try { // 예외처리를 선택
			throw new RuntimeException(); // 런타임 예외
			
		} catch (RuntimeException e) {    // 런타임 예외를 처리하여 정상흐름으로 변경
			System.out.println("예외발생");
		}
	}
}

 

(1) 예외 계층 구조 간단히 복습

  • 컴파일에러와 런타임에러(실행 에러)가 있으며 컴파일 에러는 IDE에서 에러를 미리 확인할 수 있고 무조건 예외를 처리해야 프로그램이 실행되지만 런타임 에러는 선택적으로 예외를 처리할 수 있음
  • Error : 심각
  • Exception: 덜심각
    • Exception과 RuntimeException을 제외한 자손 : 체크드 예외 필수, 컴파일러 체크 (try - catch  필수)
    • RuntimeException과 자손 : 언체크드 예외 (try - catch 선택)
  • 논리적 에러: 프로그래밍 실수

 

** 출처 : 남궁성의 정석코딩_자바의정석_기초편 유튜브 강의