Java

Exception(예외처리)

haejujung 2024. 4. 29. 17:38

1. 예외 처리에 대해서 알아 보자.

자바 프로그래밍에서의 예외 처리(Exception Handling)는 프로그램 실행 중 발생할 수 있는 예상치 못한 상황(예외)을 관리하는 방법입니다. 예외 처리를 통해 프로그램의 비정상적인 종료를 막고, 예외 상황을 보다 적절하게 처리하여 프로그램의 안정성과 신뢰성을 높일 수 있습니다.

try {
    // 예외가 발생할 수 있는 코드
} catch (ExceptionType1 e) {
    // ExceptionType1 예외를 처리하는 코드
} catch (ExceptionType2 e) {
    // ExceptionType2 예외를 처리하는 코드
}

 

try {
    // 예외가 발생할 수 있는 코드
} catch (Exception e) {
    // 예외 처리 코드
} finally {
    // 항상 실행되는 코드
}

finally 블록: try 블록의 실행 여부와 관계없이 항상 실행되어야 하는 코드(예: 자원 해제 로직)를 포함합니다. finally 블록은 모든 catch 블록 다음에 옵니다.

if (someCondition) {
    throw new Exception("Custom Error Message");
}

----------------------------------------------------------------

public void someMethod() throws IOException, NullPointerException {
    // 예외가 발생할 수 있는 코드
}

 

모든 예외 클래스의 최상위 클래스는 Exception 클래스이다.

 

2. 프로그램에서의 오류와 예외처리 방법

컴파일 오류(compile error)

프로그램 코드 작성 중 발생하는 문법적 오류

최근에는 개발 환경(eclipse)에서 대부분의 컴파일 오류는 detection 됨

실행 오류(runtime error)

실행 중인 프로그램이 의도 하지 않은 동작(bug)을 하거나 프로그램이 중지 되는 오류

실행 오류는 비정상 종료가 되는 경우 시스템의 심각한 장애를

예외 처리의 중요성

● 프로그램의 비정상 종료를 피하여 시스템이 원할이 실행되도록 함

● 실행 오류가 발생한 경우 오류의 과정을 재현하는 것은 현실적으로 힘들다

● 오류가 발생한 경우 log를 남겨서 추후 log 분석을 통해 그 원인을 파악하여 bug를 수정하는 것이 중요

오류와 예외 클래스

● 시스템 오류(error) : 가상 머신에서 발생, 프로그래머가 처리 할 수 없는 오류임

동적 메모리가 없는 경우, 스택 메모리 오버플로우등

● 예외(Exception) :프로그램에서 제어 할 수 있는 오류

읽어들이려는 파일이 존재하지 않거나, 네트웍이나 DB연결이 안되는 경우등

자바는 안전성이 중요한 언어로 대부분 프로그램에서 발생하는 오류에 대해 문법적으로 예외 처리를 해야함

 

(try-catch 문)

package useful.ch03;

public class ArrayExceptionHandling {

	// 메인 쓰래드
	public static void main(String[] args) {

		// 런타임 에러
		int[] arr = { 1, 2, 3, 4, 5 };

		try {

			for (int i = 0; i < 10; i++) {
				System.out.println(arr[i]);
				// 예외가 발생할 수 있는 코드를 넣어서 수행 시킨다.
			}
		} catch (ArrayIndexOutOfBoundsException e) {
			System.out.println("배열에 크기를 인덱스가 벗어 났습니다.");
			System.out.println(e.getMessage());

		}
		
		System.out.println("비정상 종료 되지 않았어요!");


	} // end of main

} // end of class

: 실행 오류(runtime error) 발생될 가능성이 있는 코드에 예외 처리를 할 수 있다.

 

(try-catch-finally 문)

package useful.ch03;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class FileExceptionHandling {

	// 메인 쓰레드
	public static void main(String[] args) {

		FileInputStream fis = null;

		try {
			fis = new FileInputStream("demo.txt");
//			return;
		} catch (FileNotFoundException e) {
			System.out.println("catch 구문 실행!!");
			
			// 오류추적하는코드
//			e.printStackTrace();
		} finally {
			// 반드시 수행 되어야 하는 코드 영역
			// 심지어 return 키워드를 만나더라도 여기는 수행이 된다.
			System.out.println("finally 블록 수행");
			
			try {
				fis.close();// 닫는 시점에 fis. <-- 객체가 생성 안될 경우도 존재함 
			} catch (IOException e) {
				e.printStackTrace();
			} 
		}
		
		System.out.println("비정상 종료 되지 않았어요~");

	} // end of main

} // end of class

package useful.ch03;

import java.util.Scanner;

public class FinallyHandling {

	public static void main(String[] args) {
		
		// try-catch-finally 
		// 언제 finally 사용해야 해? 
		// 자원을 반드시 닫아 주어야 할 때 등등... 
		Scanner scanner = new Scanner(System.in);
		
		try {
			int result = scanner.nextInt();
			System.out.println("result : " + result);
			// scanner 의 자원을 다 사용 했다면 자원을 해제해야 된다.
		} finally {
			scanner.close();
			System.out.println("자원 해제 완료");
		}

	}

}

 

throws 예외 처리 던지기(미루기)

package useful.ch03;

public class ThrowsHandling {

	// 메인 쓰레드
	public static void main(String[] args) {

		Calc calc = new Calc();

		try {
			// 던져서 강제성이 발생이 되고
			// 사용하는 사람이 직접 예외 처리 핸들링을 할 수 있다.
			calc.divide(10, 0);
		} catch (ArithmeticException e) {
			System.out.println("어떤 수를 0으로 나눌 수 없어요");
		} catch (Exception e) {
			System.out.println(e.getMessage());
		}

		Exception exception;

	} // end of main

} // end of class

class Calc {

	public int divide(int n1, int n2) throws Exception {
		// 사용자가 0을 입력하면 예외가 발생 될 수 있는 코드 영역이다.
		// 해결 방법
		// 1. 해당 메서드에서 직접 예외 처리를 구현 한다.
		// 2. 사용하는 사람이 직접 예외처리를 할 수 있도록 던져 버린다.
		return n1 / n2;
	}

}

 

사용자 정의 예외 클래스

package useful.ch03;

/*
 * 사용자 정의 예외 클래스 생성
 * 1. 클래스를 설계 --> 상속을 받아야한다
 * 2. 활용할 수 있는 클래스에서 throws와 throw를 활용
 * 3. Password 클래스에 활용
 * 4. 코드 실행 시점에서 테스트 및 예외 처리 작성
 */

public class PasswordException extends RuntimeException{
	
	public PasswordException(String message) {
		super(message);
		
	}

}

 

package useful.ch03;

public class Password {

	private String pwd;

	// getter
	public String getPwd() {
		return pwd;
	}

	// setter
	public void setPwd(String pwd) throws PasswordException {

		if (pwd == null) {
			throw new PasswordException("비밀번호는 null 값일 수 없습니다");
		}

		if (pwd.length() < 5) {
			throw new PasswordException("비밀번호는 5자 이상이어야 합니다.");
		}
		// 정규 표현식을 활용할 수 있다.
		// pwd <== a~z, A~Z ==> true
		// pwd <== a, 10, ! ==> false
		if (pwd.matches("[a-zA-Z]+")) {
			throw new PasswordException("비밀번호는 숫자나 특수문자를 포함해야 합니다.");
		}
		// [...] : 대괄호는 문자열을 나타냄
		// a-z, A-Z 모든 알파벳 문자열을 말한다.
		// + : 바로 앞에 표현식이 하나 이상은 반복되어야 한다.
		// 즉, "Hello" "world" --> true 를 반환 한다.
		// "A1" --> flase "bbb"(3글자미만) --> false
		this.pwd = pwd;
	}
}
package useful.ch03;

public class PasswordMainTest {
	// 스레드의 시작
	public static void main(String[] args) {

		Password password = new Password();
		String inputPwd = "ade";

		// 테스트 해 보니, 아래 코드는 실행 시점에 예외가 발생되는 코드.
		// 해결 1. 직접 예외 처리
		// 해결 2. 던지기

		try {
			password.setPwd(inputPwd);
		} catch (PasswordException e) {
			System.out.println("우리가 정의한 password 예외가 발생");
		} catch (Exception e) {
			System.out.println("예외 발생 : " + e.getMessage());
		}

	} // end of main

} // end of class

 

 

사용자 정의 예외 클래스 만드는 법 

1. 클래스를 설계 ---> 상속을 받아야 한다. 
2. 활용할 수 있는 클래스에서 throws와 throw 를 활용 
2 - 1 : Password 클래스에 활용 
3. 코드 실행 시점에서 테스트 및 예외 처리 작성 

-----------------------------------------------------

NickName 클래스를 설계 
-- String nick; 
-- get
-- set -> 예외를 던지는 코드를 추가하세요  
NickNameException 상속 --> RuntimeExcption 
NickNameTest 클래스로 확인 하기

 

NickNameException.java

package useful.ch03;

public class NickNameException extends RuntimeException {
	
	public NickNameException(String message) {
		super(message);
	}

}
package useful.ch03;

public class NickName {

	private String nick;

	public String getNick() {
		return nick;
	}

	public void setNick(String nick) throws NickNameException {

		if (nick == null) {
			throw new NickNameException("닉네임은 null 값일 수 없습니다");
		}

		if (nick.length() < 3 && nick.length() > 10) {
			throw new NickNameException("닉네임은 4자 이상이고 10자이하이어야 합니다");
		}
		// aaaaaa --> true --> 예외 발생 됨
		// aaaa!! --> false --> 예외 발생되지 않음
		// 사용자한테 닉네임 설정시에 특수문자를 포함하여라
		// 예외 발생 하지 않게 코드를 작성한것
		if (nick.matches("[a-zA-Z0-9]+")) {
			throw new NickNameException("닉네임은 특수문자를 포함해야 합니다 ");
		}

		this.nick = nick;
	}

}
package useful.ch03;

public class NickNameTest {
	
	public static void main(String[] args) {
		
		NickName nick = new NickName();
		
		String inputNick = "aaaaaa12";
		
		try {
			nick.setNick(inputNick);
		} catch (NickNameException e) {
			System.out.println("우리가 정의한 nickname 예외가 발생");
		} catch (Exception e) {
			System.out.println("예외 발생 : " + e.getMessage());
		}
		
		
	}

}