티스토리 뷰

728x90
반응형

이번 게시물은 try-catch문을 활용한 예외 처리에 대해 알아보려 한다.

try-catch 문은 다음과 같은 형태로 작성한다.

 

try-catch-finally문 작성방법

try{
	//예외 발생 가능성이 있는 문장
}catch(오류 코드){
	//오류가 발생했을 때 수행할 내용 
}finally{
	//오류 발생과 관계없이 항상 수행되는 코드
}

예제로 빠르게 살펴보자.


"한 가지 오류에 대한 try-catch문 작성하기"

 

예제 1

 

숫자 형식의 문자열을 입력받아 문자열을 실제 숫자(실수)로 변환 후에, 100을 더해 출력하는 프로그래밍을 해보자.

 

//숫자 형식의 문자열을 입력받는다. "10", "20", "10.1" 등등
String inputNum = scan.nextLine();
double num = Double.parseDouble(inputNum);
//변환한 숫자에 100을 더하고 
double result = num+100;
//더한 결과 값을 출력한다.
System.out.println("입력한 숫자 + 100 : "+result);

위와 같이 코드를 작성할 수 있다.

하지만, 숫자 대신 다른 문자가 입력되었을 때 parseDouble()에서 오류가 발생한다.

콘솔창을 보면 NumberFormatException이 발생했음을 알 수 있다.

 

 

따라서, try-catch문을 활용해 코드를 다음과 같이 수정할 수 있다.

//숫자 형식의 문자열을 입력받는다. "10", "20", "10.1" 등등
String inputNum = scan.nextLine();
try {
	//입력한 문자열을 실제 숫자(실수)로 변환한다.
	double num = Double.parseDouble(inputNum);
	//변환한 숫자에 100을 더하고 
	double result = num+100;
	//더한 결과 값을 출력한다.
	System.out.println("입력한 숫자 + 100 : "+result);
			
}catch(NumberFormatException nfe) {
	//NumberFormatException type의 예외 발생하면 실행되는 블럭
			
	//예외 정보를 콘솔에 출력하기
	nfe.printStackTrace();
}

printStackTrace()메소드는 예외 정보를 콘솔창에 출력해준다.

getMessage() 메소드는 오류 관련 메세지 String을 반환한다.


전체 코드

MainClass01.java

package test.main;

import java.util.Scanner;

public class MainClass01 {
	public static void main(String[] args) {
		Scanner scan = new Scanner(System.in);
		System.out.print("숫자 입력:");
		//숫자 형식의 문자열을 입력받는다. "10", "20", "10.1" 등등
		String inputNum = scan.nextLine();
		try {
			//입력한 문자열을 실제 숫자(실수)로 변환한다.
			double num = Double.parseDouble(inputNum);
			//변환한 숫자에 100을 더하고 
			double result = num+100;
			//더한 결과 값을 출력한다.
			System.out.println("입력한 숫자 + 100 : "+result);
			
		}catch(NumberFormatException nfe) {
			//NumberFormatException type의 예외 발생하면 실행되는 블럭
			
			//예외 정보를 콘솔에 출력하기
			nfe.printStackTrace();
			System.out.println(nfe.getMessage());
		}
		
		
		System.out.println("main 메소드가 종료 됩니다.");
	}
}

예제 2

 

예제 1을 "q"가 입력되기 전까지 계속해서 값을 출력하도록 코드를 수정해보자.


MainClass02.java

package test.main;

import java.util.Scanner;

public class MainClass02 {
	public static void main(String[] args) {
		Scanner scan = new Scanner(System.in);
		
		while(true) {
			System.out.print("숫자 입력 종료(q):");
			//숫자 형식의 문자열을 입력받는다. "10", "20", "10.1" 등등
			String inputNum = scan.nextLine();
			if(inputNum.equals("q")) {
				break;
			}
			try {
				//입력한 문자열을 실제 숫자(실수)로 변환한다.
				double num = Double.parseDouble(inputNum);
				//변환한 숫자에 100을 더하고 
				double result = num+100;
				//더한 결과 값을 출력한다.
				System.out.println("입력한 숫자 + 100 : "+result);
				
			}catch(NumberFormatException nfe) {
				System.out.println("문자가 아닌 숫자를 입력해주세요.");
				
			}
			
		}
				
	
		System.out.println("main 메소드가 종료 됩니다.");
	}
}

while문을 사용하여 "q"가 입력되었을 때 while문을 빠져나오도록 break를 작성하였다.


"여러 에러에 대한 try-catch문 작성하기"

 

예제 3 

 

"나눌 수"와  "나누어지는 수"를 입력 받아, 입력받은 문자열을 정수로 변환하고, 나눈 몫과 나머지를 출력하는 프로그래밍을 해보자.

 

1. 우선 오류를 고려하지 않고 코드를 작성해보자.

Scanner scan = new Scanner(System.in);
System.out.print("나눌 수 입력: ");
String inputNum1 = scan.nextLine();
System.out.print("나누어 지는 수 입력: ");
String inputNum2 = scan.nextLine();

//입력한 문자열을 정수로 변환하고
int num1 = Integer.parseInt(inputNum1);
int num2 = Integer.parseInt(inputNum2);
//num2를 num1으로 나눈 몫
int result = num2/num1;
//num2를 num1으로 나눈 나머지
int result2 = num2%num1;
			
System.out.println(num2+" 를 "+num1+" 으로 나눈 몫: "+result);
System.out.println(num2+" 를 "+num1+" 으로 나눈 나머지: "+result2);

2. 이제, 발생할 수 있는 오류에 대해 생각해보자.

1) 분모가 0인 경우

2) 숫자가 아닌 다른 문자가 입력된 경우

 

2번의 경우 위의 NumberFormatException이 발생한다.

 

1번일 경우를 직접 test 해보면, ArithmeticException 이 발생함을 알 수 있다.

 

따라서, try-catch문으로 아래와 같이 코드를 수정할 수 있다.


MainClass03.java

package test.main;

import java.util.Scanner;

public class MainClass03 {
	public static void main(String[] args) {
		Scanner scan = new Scanner(System.in);
		System.out.print("나눌 수 입력: ");
		String inputNum1 = scan.nextLine();
		System.out.print("나누어 지는 수 입력: ");
		String inputNum2 = scan.nextLine();
		
		try {
			//입력한 문자열을 정수로 변환하고
			int num1 = Integer.parseInt(inputNum1);
			int num2 = Integer.parseInt(inputNum2);
			//num2를 num1으로 나눈 몫
			int result = num2/num1;
			//num2를 num1으로 나눈 나머지
			int result2 = num2%num1;
			
			System.out.println(num2+" 를 "+num1+" 으로 나눈 몫: "+result);
			System.out.println(num2+" 를 "+num1+" 으로 나눈 나머지: "+result2);
			
			System.out.println("작업 성공입니다.");
		}catch(NumberFormatException nfe) {
			nfe.printStackTrace();
		}catch(ArithmeticException ae){
			ae.printStackTrace();
		}finally { //예외가 발생 하던 안하던 실행이 보장되는 블럭
			System.out.println("무언가 마무리 작업을 합니다.");
			
		}
		
		System.out.println("main 메소드가 정상 종료 됩니다.");
	}
}

catch문은 에러 갯수대로 여러 개 쓸 수 있다.


"어떤 에러가 발생할지 알 수 없을 때 예외처리"

 

예제 4

 

그동안 실행을 해보고, 어떤 오류가 일어나는지 확인한 후, 그 오류에 대한 예외처리를 해주었다.

하지만, 어떤 오류가 또 발생할지 모르고 오류의 갯수가 많을 수도 있다.

그럴때는, 모든 오류의 부모 클래스인 Exception을 catch문에 전달하여 모든 오류들에 대한 처리를 한다.

따라서, 위의 MainClass03.java를 수정하여 MainClass04.java와 같이 작성할 수 있다.


MainClass04.java

package test.main;

import java.util.Scanner;

public class MainClass04 {
	public static void main(String[] args) {
		Scanner scan = new Scanner(System.in);
		System.out.print("나눌 수 입력: ");
		String inputNum1 = scan.nextLine();
		System.out.print("나누어 지는 수 입력: ");
		String inputNum2 = scan.nextLine();
		
		try {
			//입력한 문자열을 정수로 변환하고
			int num1 = Integer.parseInt(inputNum1);
			int num2 = Integer.parseInt(inputNum2);
			//num2를 num1으로 나눈 몫
			int result = num2/num1;
			//num2를 num1으로 나눈 나머지
			int result2 = num2%num1;
			
			System.out.println(num2+" 를 "+num1+" 으로 나눈 몫: "+result);
			System.out.println(num2+" 를 "+num1+" 으로 나눈 나머지: "+result2);
			
			System.out.println("작업 성공입니다.");
		}catch(Exception e) {
			e.printStackTrace();
		}finally { //예외가 발생 하던 안하던 실행이 보장되는 블럭
			System.out.println("무언가 마무리 작업을 합니다.");	
		}
		
		System.out.println("main 메소드가 정상 종료 됩니다.");
	}
}

  


"작업 단위 Thread와 Compile 시 발생하는 예외의 처리" 

 

예제 5

 

스레드하나의 프로세스 내부에서 독립적으로 실행되는 하나의 작업 단위를 뜻한다. 

JVM에 의해 하나의 프로세스가 실행되고, main() 안의 코드들이 하나의 스레드이다.

스레드를 또 만들려면, Thread 클래스를 상속하거나 Runnable 인터페이스를 구현하면 된다.

 

위에서 다룬 오류들은 RuntimeException, 즉 Runtime 시에 발생하는 오류들이었다.

이러한 오류들은, try-catch문으로 예외처리를 하지 않아도 실행까지 문제가 없고, 경우에 따라 오류가 발생할 수도, 발생하지 않을 수도 있다.

하지만 Compile 시에 발생하는 오류들은 반드시 try-catch문을 작성해야 한다. 작성하지 않으면 문법적으로 오류이다.

즉, RuntimeException을 상속받지 않는 Exception은 반드시 try ~ catch 블럭으로 예외 처리를 해야한다.

 

예시로 Thread.sleep() 메소드가 있다.

Thread.sleep() 메소드는 원하는 시간만큼 실행의 흐름을 잡아주는 역할을 한다.

이 메소드는 반드시 try-catch 블럭으로 묶어주어야 한다. 

MainClass05는 5초 이후에 "main 메소드가 종료 됩니다." 가 출력되도록 구현한 코드이다.


MainClass05.java

package test.main;

public class MainClass05 {
	public static void main(String[] args) {
		System.out.println("main 메소드가 시작 되었습니다.");
		try {
			//스레드(작업단위, 실행순서) 5초 잡아두기 
			Thread.sleep(5000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		
		System.out.println("main 메소드가 종료 됩니다.");
	}

}

"파일 객체의 생성과 예외처리"

 

예제 6

 

test.txt 파일을 다음 경로에 생성해보자.

 

1) 파일 객체 생성

File f1 = new File("C:/developer/myFolder/test.txt");

 

2) 파일 만들기

f1.createNewFile();

이 코드를 작성하면, 빨간 줄이 뜨며 오류가 발생하는 모습을 볼 수 있다.

커서를 갖다 두면, "Surround with try/catch"가 뜨는데, 이것을 클릭하면 자동으로 try-catch문이 작성된다.

 

따라서, 전체 코드는 다음과 같다.


전체 코드

MainClass06.java

package test.main;

import java.io.File;
import java.io.IOException;

public class MainClass06 {
	public static void main(String[] args) {
		/*
		 * 특정 파일이나 폴더를 만들거나 제어할 수 있는 File 객체 생성
		 */
		File f1 = new File("C:/developer/myFolder/test.txt");
		try {
			f1.createNewFile();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("main 메소드가 종료 됩니다.");
	}

}

"throw로 직접(강제로) 예외 발생시키고 try-catch로 예외 처리하기"

 

예제 7

 

사용자 정의 예외 클래스를 만들어보자.

 

SleepyException.java - Exception을 상속받아 예외 메시지를 부모 생성자에 전달하는 생성자 생성

package test.mypac;

public class SleepyException extends Exception{
	//예외 메세지를 생성자의 인자로 전달받아 부모 생성자에 전달하기 
	public SleepyException(String msg) {
		super(msg);
	}
	

}

StudyUtil.java - random한 숫자를 얻어, 0이 나오면 sleepyException 예외를 발생시키는 코드

package test.mypac;

import java.util.Random;
/*
 * 직접 예외(Exception)을 발생 시키는 방법
 * 
 * throw 예외 객체 생성;
 */
public class StudyUtil {
	//공부하는 메소드
	public static void study() {
		//랜덤한 숫자를 얻어내서
		Random ran = new Random();
		int ranNum = ran.nextInt(3);
		//우연히 0이 나오면 예외를 발생시키기 
		if(ranNum==0) {
			//예외 발생 시킬 코드
		}
		System.out.println("열심히 공부합니다!!");
	}

}

0이 아니면(예외가 발생하지 않으면), "열심히 공부합니다!!"를 출력한다.

 

ranNum==0일 때 직접 예외를 발생시키는 코드를 작성해보자.

 


직접(강제로) 예외를 발생시키는 방법

throw 예외 객체 생성;

위의 방법에 따라 다음과 같이 코드를 작성할 수 있다.

throw new SleepyException("너무 졸려서 공부를 할 수가 없어요!");

 

하지만, 위의 코드를 작성하면 빨간 줄이 뜨며 오류가 나는 모습을 확인할 수 있다.


※" 왜 오류가 나는 것일까? "

 

SleepyException 클래스는 Exception을 상속받았다. 

만약 Exception 대신 RuntimeException을 상속받는다고 가정하면, RuntimeException은 문법적 오류가 발생하지 않으므로, 위의 throw new SleepyException()에서 오류가 발생하지 않는다. 

 

위의 오류를 해결하기 위해, SleepyException()에 다시 커서를 둬보자.

Add throws declaration이 뜨는 모습을 확인할 수 있다. 클릭하면, 다음과 같이 코드가 바뀐다.

 

public static void study() throws SleepyException  {
}

 

이것은, study() 메소드를 호출할 때, SleepyException 예외가 발생한다고 명시하는 코드이다.

 


전체 코드

StudyUtil.java

package test.mypac;

import java.util.Random;
/*
 * 직접 예외(Exception)을 발생 시키는 방법
 * 
 * throw 예외 객체 생성;
 * 
 */
public class StudyUtil {
	//공부하는 메소드
	public static void study() throws SleepyException  {
		//랜덤한 숫자를 얻어내서
		Random ran = new Random();
		int ranNum = ran.nextInt(3);
		//우연히 0이 나오면 예외를 발생시키기 
		if(ranNum==0) {
			throw new SleepyException("너무 졸려서 공부를 할 수가 없어요.");
		}
		System.out.println("열심히 공부합니다!!");
	}

}

이제 main에서 study() 메소드를 호출해보자.

package test.main;

import test.mypac.SleepyException;
import test.mypac.StudyUtil;

public class MainClass07 {
	public static void main(String[] args) {
		System.out.println("main 메소드가 시작 되었습니다.");
		//오류
        	StudyUtil.study();
	}
}

 

위 코드의 메소드 호출 부분에서 오류가 뜬다.

예외는 메소드를 호출하는 곳에서 try-catch문으로 처리해주는 것임을 잊지 말아야 한다.

 

따라서 다음과 같이 코드를 적을 수 있다.


MainClass07.java

package test.main;

import test.mypac.SleepyException;
import test.mypac.StudyUtil;

public class MainClass07 {
	public static void main(String[] args) {
		System.out.println("main 메소드가 시작 되었습니다.");
		
		try {
			StudyUtil.study();
		} catch (SleepyException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

 

반응형
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함