본문 바로가기
뒷북 정리 (국비 교육)/java

[Java] step14. Exception

by 규글 2022. 4. 24.

step14. Exception

- 01

		Scanner scan=new Scanner(System.in);
		System.out.println("숫자 입력:");
		// 숫자 형식의 문자열을 입력 받는다.  "10" "20" "10.1" 등등
		String inputNum=scan.nextLine();
        
		// 입력한 숫자를 실제 숫자로 바꾼다.
		double num=Double.parseDouble(inputNum);
		// 입력한 숫자에 100 을 더한다.
		double result=num+100;
		System.out.println("입력한 숫자 + 100 : "+result);
		
		System.out.println("main 메소드가 종료 됩니다.");

 이런 예시가 있다고 해보자. 만약에 입력한 것이 숫자가 아니라 문자라고 하면 오류가 날 것이다. java에서의 이런 오류를 Exception (예외)이라고 한다. 예외가 발생했다는 것이다. 지금 발생한 예외는 NumberFormatException이다. 이런 예외가 발생하니까 갑자기 실행 순서가 다른 곳으로 가버리고, 해당 13번째 줄 아래는 순서가 오지 않는다.

 그런데 이렇게 상상해보자. 순서가 오지 않은 곳에 중요한 작업이 있었다면 어떨까? 어떤 예외가 발생할지 예상해서 해당 예외를 직접 처리하게 되면 실행 순서가 다른 곳으로 뛰는 것을 방지할 수 있다. 그 방법은 다음과 같다.

 

		Scanner scan=new Scanner(System.in);
		System.out.println("숫자 입력:");
		// 숫자 형식의 문자열을 입력 받는다.  "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) {
			System.out.println("숫자 형식에 맞게 입력 하세요.");
			// 예외 메세지만 따로 얻어내고 싶다면
			String str = nfe.getMessage();
			System.out.println(str);
			
			// 예외 정보를 콘솔창에 출력하기
			nfe.printStackTrace();
		}
		
		System.out.println("main 메소드가 종료 됩니다.");

 

 try를 작성하고 예외가 발생할 수 있을 부분을 중괄호 { }로 묶는다. 그리고 catch( )를 이어서 작성하고 중괄호 { } 로 묶은 다음, 소괄호 ( ) 안에 예외에 해당하는 객체를 적어준다. 그리고 중괄호 { } 안에 예외가 발생했을 시 동작할 내용을 작성한다. 예외가 발생하지 않는다면 try 안쪽의 동작이, 예외가 발생한다면 catch 안쪽의 동작이 수행된다.

 printStackTrace( ) method는 예외 정보를 출력해준다. 그 중에서 예외 메시지만 따로 얻어내고 싶다면 getMessage( ) method를 사용하면 된다. 예시에서는 변수에 담아 출력했으나, 변수에 담지 않아도 된다.

 예외 처리를 하는 것과 하지 않는 것은 천지차이라고 했다. 실행의 흐름 자체가 달라지기 때문이다.

 

- 02

/*
 *  RuntimeException 을 상속 받은 Exception 종류는
 *  try ~ catch 블럭으로 묶어주지 않아도 문법 오류가 발생하지 않는다.
 *  따라서 필요시 선택적으로 try ~ catch 블럭으로 묶어주면 된다. 
 */

 ArithmeticException은 산수 문제에 대한 예외이다. 자세히 보면 Exception을 부모로 가진다. 모든 예외는 Exception을 부모로 가진다. Exception 중에 RuntimeException을 상속받았다면 try~catch로 묶지 않아도 문법적인 오류는 발생하지 않는다. 필요에 따라서 사용해주면 되는 것이다. 이 RuntimeException은 실행 중에 발생하는 오류로, 실행을 직접 해봐야만 알 수 있는 예외이다.

 

		Scanner scan=new Scanner(System.in);
		
		System.out.println("나눌수 입력:");
		String inputNum1=scan.nextLine();
		System.out.println("나누어 지는수 입력:");
		String inputNum2=scan.nextLine();
		try {
			int num1=Integer.parseInt(inputNum1);
			int num2=Integer.parseInt(inputNum2);
			
			int result=num2/num1; // 몫
			int result2=num2%num1; // 나머지
			System.out.println(num2+" 를 "+num1+" 으로 나눈 몫 :"+result);
			System.out.println(num2+" 를 "+num1+" 으로 나눈 나머지:"+result2);
		}catch(NumberFormatException nfe) {
			System.out.println("숫자 형식으로 입력 하세요.");
		}catch(ArithmeticException ae) {
			System.out.println("어떤 수를 0으로 나눌수는 없어요");
		}catch(Exception e) {
			System.out.println("Exception 이 발생했습니다.");
		}finally {// 예외가 발생 하던 안하던 반드시 실행이 보장되는 블럭
			System.out.println("무언가 마무리 작업을 해요~");
		}
		
		System.out.println("main  메소드가 정상 종료 됩니다.");

 그리고 catch는 여러 가지로 묶을 수 있다. 계속해서 catch를 이어 붙일 수 있는데, 예를 들어 발생할 수 있을 것이라 예상하는 exception의 종류가 여러 개일 수 있다. 그럴 때 계속해서 붙일 수 있다. 그리고 finally는 예외 발생과 상관 없이 무조건 수행하는 부분이다. 이 finally는 마무리 작업인데 중간에 존재하게 되면, 이후 catch로 연결된 다른 예외에 대한 내용이 수행되지 않기 때문에 항상 마지막에 작성해야 한다.

 

- 03

/*
 *  RuntimeException 을 상속 받지 않는 Exception 은 
 *  반드시 try ~ catch 블럭으로 묶어서 예외 처리를 해야한다. 
 */
		System.out.println("main 메소드가 시작 되었습니다.");
		
		try {
			Thread.sleep(5000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
		File f1=new File("c:/acorn202104/myFolder/test.txt");
		try {
			f1.createNewFile();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		System.out.println("main 메소드가 종료 됩니다.");

 RuntimeException을 상속받지 않았다면 try~catch 구문은 생략할 수 없고, 반드시 작성해주어야 하는 부분이다. 이것은 문법이다. 그리고 예시의 Thread.sleep( ); 은 해당 ms(mili-second) 동안 실행 순서를 묶어둔다. 이 친구도 RuntimeException을 상속받지 않았기 때문에 try와 catch로 묶어준 것이다.

 

 File 객체는 경로와 함께 만들어지는데, 해당 경로에 맞는 폴더를 만들고 run 하면 해당 file이 createNewFile( ) method를 통해서 만들어진다. 해당 경로가 없거나 올바르지 않으면 예외가 발생한다.

 

- 04

		Random ran=new Random();
		
		for(int i=0; i<100; i++) {
			// 0~9 사이의 랜덤한 정수를 발생시킨다.
			int ranNum=ran.nextInt(10);
			if(ranNum==5) {// 우연히 랜덤한 정수가 5 가 나오면 예외를 발생 시킨다.
				// throw 예약어와 함께 예외 객체를 생성하면 예외가 발생한다.
				throw new SleepyException("너무 졸려~~");
			}
			
			System.out.println(i+1+" 번째 작업중...");
		}
		
		System.out.println("main 메소드가 종료 됩니다.");

 하지만 특정 이유 때문에 직접 예외를 발생시키는 경우도 있을 것이라고 했다. 이때 사용하는 것이 throw 예약어이다. 예외를 던지는 것이다.

 java를 한 줄 한 줄 실행해주는 실체가 있는데, 그것은 바로 Java Virtual Machine(JVM)이다. 이 JVM이 exception을 처리해주는 것이다. 우리가 처리해주지 않으면 JVM이 처리해주는 것이라고 했다. 물론 던져주고 우리가 처리하는 것이라고 했다. 그 예외를 만드는 방법은 다음과 같다.

 

/*
 *  사용자 정의 Exception 도 만들수 있다. 
 *  실행시 발생하는 Exception 은 RuntimeException 을 상속 받아서 만들면된다.
 */
public class SleepyException extends RuntimeException{
	// 예외 메세지를 생성자의 인자로 전달받아서 
	public SleepyException(String msg) {
		super(msg); // 부모 생성자에 전달 
	}
}

 RuntimeException을 상속받아서 만들면 끝이다. 그리고 예외 메시지를 constructor의 인자로 받아서 부모 constructor에 전달해주면 된다. 그러면 throw로 던져주는 메시지가 예외 메시지가 된다.

 

- 05

public class MyUtil {
	public static void draw() {
		System.out.println("5초 동안 그림을 그려요");
		// 발생하는 Exception 을 메소드 내에서 직접 처리한 경우 
		try {
			Thread.sleep(5000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("그림 완성!");
	}
	// 메소드 안에서 발생하는 Exception 을 던져 버리는 경우
	public static void send() throws InterruptedException {
		System.out.println("5 초 동안 전송을 해요");
		Thread.sleep(5000);
		System.out.println("전송 완료");
	}
}
		MyUtil.draw();
		
		try {
			// send() 메소드에서 발생하는 Exception 을 처리 해야 한다.
			MyUtil.send();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

 MyUtil class에는 draw( ) 와 send( ) method가 있다. 이 두 method를 사용하는 것에 차이는 draw( )에는 try~catch가 있고, send( )에는 없다는 점이다. 먼저 draw( ) 는 이미 method 자체에 try~catch를 작성했기 때문에 따로 단계를 거치지 않아도 되는 반면, send( ) 는 method에서 exception을 발생시키고 있기 때문에 try~catch를 작성해줘야 한다.

 이때 send( )의 throws를 지워보면 두 가지 선택지가 나온다. 언제 어떤 것을 선택해야하는지는 지금은 알 수 없으나, 두 가지 선택지가 있다는 것만 알고 있으면 된다고 했다.

'뒷북 정리 (국비 교육) > java' 카테고리의 다른 글

[Java] step16. Thread  (0) 2022.04.25
[Java] step15. Swing  (0) 2022.04.25
[Java] step13. Util Class  (0) 2022.04.22
[Java] step12. Generic Class  (0) 2022.04.22
[Java] step11. Interface  (0) 2022.04.19

댓글