예외 처리(try - catch)

김용민·2023년 4월 4일
0

예외와 오류

예외와 오류를 비슷한 걸로 생각 할 수가 있는데 디테일하게 보자면 문제를 고칠 수 있는가 없는가로 구분할 수 있다

  • exception(예외)
    코드 수정에 따라 처리할 수 있는 문제점을 말함

  • Error(오류)
    코드와 무관하게 원일을 알 수 없는 문제점

오류는 어떻게 못한다고 하더라도 그러면 예외는 java에서 어떻게 처리할까?

예외 처리 과정

자바에서는 예외도 클래스로 규정하여, 예외 객체가 발생하고, 이를 처리해야 한다 그럼 간단한 예시로 살펴보자

Scanner sc = new Scanner(System.in);
int num;
String input;

System.out.print("정수를 입력");
num = Integer.parseInt(sc.nextLine());

위처럼 코드를 작성했을 경우에 예외가 어떤 경우가 있을까?

1) 약 21억에 달하는 int의 범위를 초과한 수를 넣었을때
2) int가 아닌 다른 자료형을 넣었을 때

잠깐 생각해 봐도 이렇게 생각할 수 있다

만약에 일부러 이렇게 진행이 된다고 하면
콘솔창에 1)번에 해당하는 예외를 띄우면

위와 같이 java.lang.NumberFormatException이 뜬다
이것도 하나의 클래스로 자료형이 맞지 않는 값을 입력하거나 했을때 뜨는 예외 처리 클래스다

그럼 이 예외처리 클래스 없이 만약에 다른 자료형이나 범위를 넘어가는 값을 입력했을때 오류를 띄울려면 어떻게 해야할까?

그 처리를 만약에 숫자가 아닌 다른 문자나, .을 포함하고 있을 경우를 걸러보자

public static void main(String[] args) {
	Scanner sc = new Scanner(System.in);
    int num;
    String input;
    
    System.out.print("정수를 입력 : ");
    input = sc.nextLine();
    
    boolean isDight = true;
    // 입력받은 문자열을 받아서 각자리의 아스키코드가 0 이하 , 9 이상일때
    for(int i = 0 ; i < input.length(); i++){
    	if(input.charAt(i) < '0' || input.charAt(i) > '9'){
        	isDigit = false;
            break;
        }
    }
    
    // 숫자가 아닐때...
    if(isDigit == false) {
    	System.out.println("숫자만 입력하셔야 합니다!");
    }
    // 실수형으로 쓴다고 .이 들어갈때
    else if ( input.contains(".")){
    	System.out.println("실수는 입력하실수 없습니다!");
    }
    // 위의 조건이 다 아니면 num에 input을 int형으로 변환해서 넣고 출력한다
    else {
    	num = Integer.parseInt(sc.nextLine());
        System.out.println("입력하신 숫자 : " + num); 
    }
    
}

그럼 이렇게 적으면 되는데 굳이 왜 예외처리 클래스를 따로 둔걸까?

그 이유는 if문이 보통 분기를 나타낼때 주로 사용하는데 예외를 처리할 때도 if, 분기를 나타낼때도 if를 사용하게 된다면 코드가 짧을때는 문제가 없으나 코드가 길어지고 프로그램이 커지게 되면 문제가 생기게 된다. 그래서 예외 처리 클래스를 이용해 처리하게 된다

그러면 이제 예외처리 클래스를 통해서 예외를 처리하는 방법을 알아보자

간단한 try - catch문 사용법

package exception;

import java.util.Scanner;

public class Ex02 {
	//try catch 사용법과 finally 사용법 예외
	public static void main(String[] args) {

		Scanner sc = new Scanner(System.in);
		int num;

		System.out.print("정수 입력 : ");
		try {	// 예외가 발생할 수 있는 코드를 시도한다
			num = Integer.parseInt(sc.nextLine());
			System.out.println("num : " + num);
		} catch (NumberFormatException e) {	// 예상되는 예외가 발생하면 아래 코드를 수행한다
        // NumberFormatException -> 자료형에 맞지 않게 들어갔을 경우
			System.out.println("정수로 변환할 수 없는 값을 입력했습니다!!");
			System.out.println(e);	// e.toString();
			e.printStackTrace();	// 예외 발생 상황을 상세하게 추적하여 출력한다 (기본값)
			
		} finally {	// 예외 발생 여부에 상관없이 마지막에 반드시 실행한다
			System.out.println("프로그램을 종료합니다");
			sc.close();
		}

	}
}

간단하게는 이렇게 사용한다

물론 예외처리 클래스를 커스텀으로도 만들 수 있다 !

내가 원하는 예외처리 클래스를 만들어보자!

점수를 Scanner로 입력 받는데 0 ~ 100점을 벗어난 범위를 입력 받으면 예외를 일으키는 클래스를 만들어 봅시다 !

// 예외 클래스 이므로 거의 모든 예외 클래스의 상위 클래스인 Exception을 상속 받는다
class ScoreOutOfBoundsException extends Exception{
	// 필드
    private int score;
    
    public ScoreOutOfBoundsException(int score){
    	this.score = score;
    }
    
    @Override
    public String toString(){
    	// 호출한 객체의 클래스의 이름을 가져온다(this.getclass().getName())
    	return this.getclass().getName() +  " : " + score + " : 점수가 범위를 벗어났습니다(0~100)";
    }
}

class Example{
public static void main(String[] args){
	Scanner sc = new Scanner(System.in);
    int score 
    
    try{
    	System.out.print("정수 입력 : "); 
    	score = Integer.parseInt(sc.nextLine());
        
        // 입력한 점수가 0 미만 100 초과면 점수 범위 벗어난 예외를 만들어 
        // throw(예외를 일부러 발생시키는 명령어)한다
        if(score < 0 || score > 100) {
        	ScoreOutOfBoundsException e = new ScoreOutOfBoundsException(score);
            throw e;
        }
    }catch(ScoreOutOfBoundsException e) {
    // 만약 점수 범위 벗어난 예외(ScoreOutOfBoundsException)이 뜨면 catch종속문을 실행
    	System.err.println(e);
    }finally{
    	//예외 처리에 상관없이 스캐너를 닫아준다
    	sc.close();
    }
}
}

이걸 실행해서 오류를 띄워보자~

요로케 범위를 벗어난 값을 넣게 되면 오류를 띄운다
(빨갛게 나오는건 System.err.println)

throws

만약에 이러한 경우 말고 큰 프로그램에서 같은 예외가 계속 발생해서 try-catch문을 계속 쓰면 어떻게 될까?

실행을 되겠지만 프로그램이 커질 수록 코드의 가독성이 떨어지게 되고, 유지보수를 떨어지게 만드는 결과를 만든다

그래서 이제부터 설명하는 throws를 사용해서 메서드에 옆에 붙혀서 어떤 종류의 오류를 자신의 상위 클래스로 전가한다

그 간단한 예시를 살펴보자

class Timer {
	private double minute;

	public Timer(double minute) {
		this.minute = minute;
	}
	
	public void start() throws Exception {	// 발생하는 예외를 caller에게 전가시킨다
		for(int i = (int)(minute * 60); i != -1; i--) {
			System.out.printf("[%02d : %02d]\n", i / 60, i % 60);
			Thread.sleep(1000);     // 스레드를 제어하는 과정에서 예외가 발생할 수 있다
		}
	}
	
}

public class Example {
	// throws를 사용하는 간단한 예시
	public static void main(String[] args) {
		// throws : 현재 함수(callee)에서 발생한 예외를 caller에게 전가시킨다
		Scanner sc = new Scanner(System.in);
		double minute;
		
		System.out.print("타이머 시간 입력 (분) : ");
		minute = Double.parseDouble(sc.nextLine());
		
		Timer ob = new Timer(minute);
		try {
			ob.start();
		} catch (Exception e) {
			e.printStackTrace();
			// print : 출력, stack : 쌓이는 구조(함수스택), trace : 경로, 추적
		}
		
		sc.close();
		
		// 프로그램마다 다른 상황을 가지는데, 규정된 예외만 처리할 수 있다면 유연성이 떨어진다
		// 따라서, 내가 직접 예외 상황을 규정하고 객체를 생성하여 던지는 throw가 필요하다
	}
}

서브 클래스에서 발생한 예외들을 슈퍼 메서드로 전가해서 모아서 처리하는 방식이고

main 메서드가 만약에 예외를 전가하게 되면 JVM(Java Virture Machine)이 처리하게 되고

거의 다 처리하겠지만 만약 처리하지 못하면 그 예외를 OS(Operating System)에 전가하게 되고

정말 희박하게 OS로 예외를 처리하지 못했다면 블루스크린이 떠버린다!(위험)

이런식이라고 보면 된다!

마치며

예외 처리에 대해서 간단하게 알아보았다

물론 깊게 들어간다면 더 알아 볼건 많겠지만 간단하게 쓸수 있을 정도로만 알아보았다

이상이다

(。・∀・)ノ゙

profile
안녕하세요

0개의 댓글