JAVA(5)-예외처리

Wooney98·2022년 11월 8일
1

JAVA

목록 보기
5/8
post-thumbnail

예외처리

try-catch-finally문을 사용한다

  • try : 예외가 발생할 가능성이 있는 실행문을 넣어준다.
  • catch : 예외를 처리할 코드를 넣는다.
  • finally : 예외 발생 여부와 상관없이 무조건 실행되어야 하는 코드를 넣는다.
try{
	//예외가 발생될만한 코드
}catch(FileNotFoundException e){	//FileNotFoundException이 발생했다면

}catch(IOException e){ //IOException이 발생했다면

}catch(Exception e){	//Exception이 발생했다면

}finally{	
	///어떤 예외가 발생하던 말던 무조건 실행
}
//만약 정수를 입력받아야 하는데 다른 값이 들어온다면?
while(true) {
			try {
				System.out.println("곱하고자 하는 두 수 입력 >> ");
				int n = scan.nextInt();
				int m = scan.nextInt();
				System.out.println(n + "x" + m + "=" + n*m);
			}catch (Exception e) {
				// TODO: handle exception
				System.out.println("실수는 입력할 수 없습니다");
				break;
			}
		}
  • 정수를 숫자로 변경하는데 int형이 아닌 다른 형식의 숫자가 들어올 경우 NumberFormatException을 사용한다.
String[] stringNumber = {"23","12","3.141592","998"};
		
		int i=0;
		try {
			for(i=0; i<stringNumber.length; i++) {
				int j = Integer.parseInt(stringNumber[i]);
				System.out.println("숫자로 변환된 값은: "+j);
			}
		}catch (NumberFormatException e) {
			// TODO: handle exception
			System.out.println(stringNumber[i]+"는 정수로 변환할 수 없습니다");
		}
  • 정수를 입력받아야 하는데 문자가 들어오면 InputMismatchException 을 사용한다.

scan은 입력값을 버퍼에 저장하는데 만약 다른 값이 들어온 채로 catch문을 실행하게 되면 버퍼 안에 exception에 대한 입력값이 남아있게 된다. 그래서 catch문에서 버퍼에 들어있는 입력값을 지우기 위해 scan.next( )를 사용한다. scan.next( )를 사용하게 되면 키보드 입력을 받은 버퍼의 내용을 빼서 이것을 변수에 할당하면 그 변수 안에 값이 들어가는 형식으로 사용하는데 변수에 할당하지 않고 그냥 사용하면 버퍼안에 있는 값을 버리는 개념으로 사용된다.

Scanner scan = new Scanner(System.in);
		System.out.println("정수 3개 입력하세요");
		int sum = 0, n=0;
		for (int i=0; i<3; i++) {
			System.out.println(i+">>");
			try { //예외가 실행될 수 있는 코드를 작성.
				n = scan.nextInt();
			}catch (InputMismatchException e) { //예외가 들어왔을 시 실행되는 코드
				// TODO: handle exception
				System.out.println("정수가 아닙니다. 다시 입력하세요");
				scan.next(); 
                //입력 스트림에 있는 정수가 아닌 토큰을 버림. 키보드의 값을 버퍼에 임시로 저장하는데 
                //내가 잘못 저장한 것을 버려야 하기 때문에 사용한다
				//만약 scan.next()를 쓰지 않으면 다음 입력받을 때 내가 잘못입력한 값 + 정수값이 버퍼에 
                //저장되기 때문에 또 exception이 발생한다. 이것을 방지하기 위해 버퍼에 있는 값을 버린다.
				//scan.next()는 키보드의 담긴 값을 가져온다는 의미이기 때문에 어느 변수에 저장되지 
                //않으면 버퍼안에 있는 입력 내용이 사라진다.
                
				i--; //인덱스 증가하지 않도록 미리 감소
				continue; //다음루프 시작. 근데 이미 i의 값을 1 감소시켜서 다시 실행됨
			}
			sum += n;
		}

예외처리를 잘 하는 방법

1. 리소스 정리

JDBC 드라이버를 통해 DB에 접근하거나 파일을 열고 데이터를 읽어오는 경우

FileInputStream inputStream = null;

try {
	
    File file = new File("./tmp.txt");
    
    byte[] buffer = new byte[512]; // 파일을 열고 512 바이트 버퍼 생성

    inputStream = new FileInputStream(file); 
    
    inputStream.read(buffer, 0, 512);
// 파일로부터 512바이트만큼 데이터를 읽은 후
    inputStream.close();
// 파일 스트림을 닫는 코드.
} catch (FileNotFoundException e) {
    log.error(e);
} catch (IOException e) {
    log.error(e);
}

만약 IOException이 발생한다면 프로그램은 에러 로그를 찍고 진행하지만 파일 스트림은 열려있는 채로 남아있다. 만약 초당 수백명의 사용자가 접속해 사용하는 시스템이라면, 정리되지 않은 리소스가 문제를 일으킬 가능성이 있다.
따라서, try-catch로 리소스를 열었다면, finally 블록에서 리소스를 정리해야한다.

FileInputStream inputStream = null;

try {
    File file = new File("./tmp.txt");
    byte[] buffer = new byte[512];
    inputStream = new FileInputStream(file);
    inputStream.read(buffer, 0, 512);
    inputStream.close();
} catch (FileNotFoundException e) {
    log.error(e);
} catch (IOException e) {
    log.error(e);
} finally {
    if (inputStream != null) {
    try {
        inputStream.close();
    } catch (IOException e) {
        log.error(e);
    }
}

2. 자세한 예외

메소드를 정의할 때, 이 메소드에서 발생할 수 있는 예외를 throw 구문으로 명시할 수 있다.
이 때, 메소드에서 발생할 수 있는 예외는 최대한 자세히 예외를 명시하는 것이 좋다.

public void exceptableMethod() throw Exception;

public void execptableMethod() throw NumberFormatException;

첫번째 경우, Exception으로 퉁쳐버리면 이 메소드를 호출하는 쪽에서 예외처리하는 코드가 복잡해진다. 따라서 모든 경우에 대한 코드를 작성할 수 밖에 없다.

3. javadoc으로 설명

/**
 * 이 메소드는 어떨때 사용하는 메소드입니다.
 *
 * @param input 입력 값
 * @throws MyException 어떤어떤 경우에 이 예외가 발생합니다.
 */
public void myMethod(String input) throws MyException { ... }

javadoc 문서를 통해서 기술할 수 있다. 어떤 상황에서 예외가 발생할 수 있는지 글로 자세히 설명해줘야 메소드를 호출하는 쪽에서 적당한 예외코드를 작성할 수 있다. @throw 선언으로 설명하는 글을 작성하자.

4. catch 절 순서

try-catch 블럭에서 여러 예외가 발생할 수 있는 경우 좀 더 상세한 예외부터 처리해야 한다. 예외가 상속관계에 있을 경우 앞쪽 catch 절에서 더 넓은 범위의 예외를 먼저 처리해버리면, 뒤 쪽 catch 절이 쓸모없게 된다.

try {

    method();

} catch (Exception e) {

    log.error(e);

} catch (IllegalArgumentException e) {
    // 실행 안 됨
    log.error(e);

}

이렇게 처리하면 모든 예외가 Exception 절에서 걸려서 IllegalArgumentException 처리 블록은 실행이 안됨.

try {

    method();

} catch (IllegalArgumentException e) {

    log.error(e);

} catch (Exception e) {

    log.error(e);

}

따라서 순서를 상세한 예외부터 처리해야한다.

profile
👨Education Computer Engineering 🎓Expected Graduation: February 2023 📞Contact info thstjddn77@gmail.com

0개의 댓글