🎥Back/자바의 정석

[JAVA의 정석] 프로그램오류. try-catch

i_zzy 2024. 2. 18. 18:04

이 글은 유튜브 '자바의 정석 - 기초편'을 보고 정리한 글입니다. 

 

 

📂content

1. 프로그램 오류

- 컴파일 에러 (compile-time error) : 컴파일 할 때 발생하는 에러

- 런타임 에러 (runtime error) : 실행 할 때 발생하는 에러

  => 실행이 되다가 실행 중 문제 발생 

에러 (error)

프로그램 코드에 의해서 수습될 수 없는 심각한 오류

예) Out of Memory Error

 

예외 (exception)

프로그램 코드에 의해서 수습될 수 있는 다소 미약한 오류

 에러는 어쩔 수 없지만, 예외는 처리하자! 

 

- 논리적 에러 (logical error) : 작성 의도와 다르게 동작 

  => 잘 동작은 하는데 개발자가 원하는대로 동작x

자바 컴파일러가 하는 일
1. 구문 체크
2. 번역
3. 최적화 예) int i = 3 +5; 
4. 생략된 코드 추가 

 

- 예외처리의 정의와 목적

예외처리(exception handling)의

정의 

프로그램 실행 시 발생할 수 있는 예외의 발생에 대비한 코드를 작성하는 것

목적

프로그램의 비정상 종료를 막고, 정상적인 실행상태를 유지하는 것

 

 

 

2. 예외 클래스의 계층 구조

Throwable : 클래스. 오류의 조상

Execption클래스들

사용자의 실수와 같은 외적인 요인에 의해 발생하는 에러 (예외처리 선택)

RuntimeException클래스들

프로그래머의 실수로 발생하는 예외 (예외처리 필수)

 

 

 

3. 예외 처리하기. try - catch문

try {
	//예외가 발생할 가능성이 있는 문장들을 넣는다.
} catch (Exception1 e1) {
	//Exception1이 발생했을 경우, 이를 처리하기 위한 문장을 적는다. 
} catch (Exception2 e2) {
	//Exception2가 발생했을 경우, 이를 처리하기 위한 문장을 적는다. 
} catch (ExceptionN eN) {
	//ExceptionN이 발생했을 경우, 이를 처리하기 위한 문장을 적는다. 
}

 

if문과 달리, try블럭이나 catch블럭 내에 포함된 문장이 하나뿐이어도 괄호{}를 생략할 수 없다. 

 

 

 

4. try - catch문에서의 흐름

① try블럭 내에서 예외가 발생한 경우,

1. 발생한 예외와 일치하는 catch블럭이 있는지 확인한다.

2. 일치하는 catch블럭을 찾게 되면, 그 catch블럭 내의 문장들을 수행하고 전체 try-catch문을 빠져나가서 그 다음 문장을 계속해서 수행한다. 만일 일치하는 catch블럭을 찾지 못하면, 예외는 처리되지 못한다. 

 

② try블럭 내에서 예외가 발생하지 않은 경우,

1. catch블럭을 거치지 않고 전체 try-catch문을 빠져나가서 수행을 계속한다. 

 

 

⍟실습

더보기

- 예외 발생 X 

class Ex8_1 {
	public static void main(String args[]) {
			System.out.println(1);			
			try {
				System.out.println(2);
				System.out.println(3);
			} catch (Exception e)    {
				System.out.println(4); //실행 안 됨
			} //try-catch의 끝
			System.out.println(5);
	}
}

/*
결과
1
2
3
5
*/

 

 

- 예외 발생 O

class Ex8_2 {
	public static void main(String args[]) {
			System.out.println(1);
			try {
				System.out.println(0/0); //예외발생! 
				System.out.println(2); 	// 실행되지 않는다.
			} catch (ArithmeticException ae)	{
				System.out.println(3);
			}	// try-catch의 끝
			System.out.println(4);
	}	// main메서드의 끝
}

/*
결과
1
3
4
*/

 

 

 

5. 예외의 발생과 catch블럭

- 예외가 발생하면, 이를 처리할 catch블럭을 찾아 내려감

 

⍟실습

더보기

Ex8_4

class Ex8_4 {
	public static void main(String args[]) {
		System.out.println(1);			
		System.out.println(2);
		try {
			System.out.println(3);
			System.out.println(0/0); // 0으로 나눠서 고의로 ArithmeticException 발생
			System.out.println(4); 	// 실행되지 않는다.
		} catch (ArithmeticException ae)	{
			if (ae instanceof ArithmeticException) 
				System.out.println("true");	
			System.out.println("ArithmeticException");
		} catch (Exception e){
        	// ArithmeticException을 제외한 모든 예외가 처리된다. 
			System.out.println("Exception");
		}	// try-catch의 끝
		System.out.println(6);
	}	// main메서드의 끝
}

/*
결과
1
2
3
true
ArithmeticException
6
*/

 

 

 

6. printStackTrace()와 getMessage()

printStackTrace()

예외발생 당시의 호출스택(Call Stack)에 있었던 메서드의 정보와 예외 메시지를 화면에 출력한다. 

 

getMessage() 

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

예외가 발생하면 해당 예외 객체가 발생한다. 
이 객체에는 예외 정보와 printStackTrace(), getMessage()와 같은 메소드가 들어가 있다. 

 

try {
	...
	System.out.println(0/0); // 예외발생!!
	...
} catch (ArithmeticException ae){
	ae.printStackTrace();
	System.out.println(ae.getMessage());	
} catch (Exception e){
	...
}
ae는 참조변수. 따라서 예외객체의 주소가 들어가있다. 참조변수 ae의 유효범위는 해당 {} 안에서만 사용가능하다.  

 

 

⍟실습

더보기

Ex8_5

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
java.lang.ArithmeticException : / by zero at Ex8_5.main(Ex8_5.java:8)
예외메시지 : / by zero
6

 

 

 

7. 멀티 catch 블럭 

- 내용이 같은 catch블럭을 하나로 합친 것(JDK1.7부터)

내용이 동일해서 중복을 제거하기 위해 2번 이미지처럼 코드를 바꾼다.

주의 사항
1. 멀티 catch에 쓰이는 두 예외 클래스가 부모-자식이면 굳이 멀티catch 블럭을 쓸 필요가 없다. 
    instance of로 예외 클래스를 판단하기 때문이다. 즉, 꼭 일치하는 것을 판단하는 것이 아니다. 
2. 멀티 catch에서 해당 에러에만 실행되는 메소드를 쓰지 말아라 
try {
	...
} catch (ExceptionA | ExceptionB e){
	e.methodA(); // 에러. ExceptionA에 선언된 methodA()는 호출불가
    
    if(e instanceof ExceptionA){
    	ExceptionA e1 = (ExceptionA)e; // 형변환
        e1.methodA(); // OK. ExceptionA에 선언된 메서드 호출가능
    } else { // if(e instanceof ExceptionB)
    	...

 

 

 

📣 comment

구글링해보니 printStackTrace()의 경우는 보안성이나 오버헤드 등의 여러가지 문제로 사용하는 것을 지양한다고 한다. 마치 수업에서는 `System.out.println()` 을 사용하지만 현업에서 `System.out.println()`을 사용하지 않는 것처럼 말이다. 

그래서 대신에 log framework를 사용해야한다고 한다. 

 

 

 

 

 

 

출처