- Error(오류)와 Exception(예외사항)

Error(오류) 프로그램이 실행될 수 없는 오류
프로그램이 실행중에 처리할 수 없음(코드를 고쳐야 실행 가능)
ex.오타
Exception(예외사항) 프로그램 실행 중에 발생하는 오류
수습 코드를 통해 실향할 수 있는 오류

 

- 예외처리

수습 코드를 작성하여 사전에 예외로 인한 프로그램의 비정상적 종료를 미연에 방지하는 작업

 

- 주요 예외 사항

ArithmeticException 수학적으로 해결할 수 없는 예외
NullPointException 인스턴스가 생성되지 않았다.
ArrayIndexOutOfBoundsException 배열 범위 밖
ex. 0~9까지인데 10번 사용할 경우 
NumberFormatException 숫자로 변환할 수 없음
ex. Scanner 사용해서 다 문자열로 받아서 숫자로 변환할 때 숫자가 아니여서 변환할 수 없을 경우(one, 하나, ... 입력시)
IOException 입출력 예외(파일 입출력 포함)
SQLException DB 처리 관련 예외

 

- 예외 사항의 처리

try
(시도하다)
예외 사항이 발생될 수 있는(가정) 코드를 작성하는 부분.
정상적으로 처리될 수도 있으며, 코드를 작성할 때는 잘 처리될 것으로 생각하며 작성함.
catch
(예외사항을 잡아서 처리하다)
try부분에서 예외사항이 발생되면 처리해야할 작업 코드를 작성하는 부분(문제에 대한 출력문 등...)
catch 부분은 예외사항에 따라 여거개가 존재할 수 있음.
finally
(반드시 마지막에 실행하다)
생략할 수 있는 부분. 예외가 없어도, 예외가 있어도 마지막에 실행되야하는 코드를 작성하는 부분.
마지막에 실행할 작업이 없으면 작성하지 않아도 됨.

 

- 처리 순서

1. 메소드 안에서 자체적으로 처리 try, catch 구문을 사용
2. 호출한 메소드에서 처리하도록 예외를 넘김 반환형 메소드() throws 예외사항 { ... }
메소드를 호출한 위치에 try, catch를 사용하여 예외를 처리해야함.

 

- Multi-catch

catch부분은 여러개를 작성할 수 있음.

try {
	//숫자 입력 처리
    //나눗셈 처리
} catch (NumberFormatException ne) { //(1)
	... //숫자를 입력해야 합니다.
} catch (ArithmeticException ae) { //(2)
	... //0으로 나눌 수 없습니다.
} catch (Exception e) { //(3)
	... //그 외의 예외사항 처리
}

작성 순서대로 실행됨.

(1)이 아니면 (2), (2)도 아니면 (3) catch 부분 실행.

 

마지막에 큰 범위의 예외사항이 와야함.

 

-호출하는 메소드에게 예외사항 전달

throws Exception 클래스1, Exception 클래스2.., Exception 클래스n

 

메소드 선언 뒤쪽에 throws 키워드로 사용하여 예외사항 클래스를 입력하면 호출한 메소드에 발생한 예외사항을 넘길 수 있음

 

다양한 예외사항을 처리해야 할 경우 ','로 구분하여 여러 개의 예외사항 클래스를 입력할 수 있음.

 

-예외사항 일부러 만들기

예외 사항 인스턴스를 만들어서 보내기.

Exception 클래스로 예외사항 인스턴스를 생성

 

- 생성 시 메시지로 사용할 문자열 추가

Exception ex = new Exception("메시지");

 

- throw 키워드를 사용하여 예외 인스턴스 전달

throw ex;

 

이 때 메소드는 예외를 전달하기 때문에 throws로 예외를 선언해야 함.

public void method() throws Exception { ... }

 

- 에러 코드와 메시지를 갖는 예외 클래스 만들기(작성 단계)

1. Exception 클래스를 상속하여 새로운 클래스(MyException) 작성
2. 작성한 새로운 클래스로 인스턴스 생성
3. 생성 시 메시지, 에러코드 등 값 추가
4. 새로 만든 예외사항임을 알려야함. throws 뒤에 클래스 이름을 작성.
5. 메소드를 호출하는 곳에서 새로운 클래스로 catch 처리. catch 부분에서 새로운 클래스의 정보를 출력 및 처리.

 

예제)

com.dto.package > Infomation.java

package com.dto;

public class Information {
	private String name;
	private String info;
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getInfo() {
		return info;
	}
	public void setInfo(String info) {
		this.info = info;
	}
}

 

com.package > ExceptionTest.java

package com;

import java.util.Scanner;

import com.dto.Information;

public class ExceptionTest {
	
	static Information info = new Information();
	
	public static void main(String[] args) {
		Scanner scan = new Scanner(System.in);
		
		System.out.print("이름 : ");
		info.setName(scan.nextLine());
		System.out.print("정보 : ");
		info.setInfo(scan.nextLine());
	}
}

static Informationinfo = new Information();에서 =new Information()을 붙이기 전에는 참조변수(선언만 되어있고 아무것도 없는 상태이기 때문에) NullPointerException이 발생한다.

 

 

com.package > CalculatorTest.java

1. 덧셈(예외 사항 자체 처리)

package com;

import java.util.Scanner;

public class CalculatorTest {

	static Scanner scan = new Scanner(System.in);
	public static void main(String[] args) {

		String menu = "";

		while(true) {
			System.out.println();
			System.out.println("예외처리 계산기");
			System.out.println("1. 덧셈");
			System.out.println("2. 뺄셈");
			System.out.println("3. 나눗셈");
			System.out.println("4. 예외 발생");
			System.out.println("0. 종료");
			System.out.print("선택>> ");

			menu = scan.nextLine();

			if(menu.equals("0")) {
				System.out.println("종료");
				break;
			}

			switch(menu) {
			case "1":// 덧셈 처리(예외사항 자체 처리)
				add();
				break;
			
	private static void add() {
		int n1, n2, rs;
		String str;

		System.out.println("덧셈 연산");//서브 타이틀

		try {
			System.out.print("첫번째 수 : ");
			str = scan.nextLine();
			n1 = Integer.parseInt(str);
			System.out.print("두번째 수 : ");
			str = scan.nextLine();
			n2 = Integer.parseInt(str);

			rs = n1 + n2;

			System.out.println("계산 결과 : " + rs);
		} catch(Exception ne) {
			System.out.println("숫자를 입력해 주세요.");
		} finally {
			System.out.println("덧셈 연산이 끝났습니다.");
		}
	}//add 끝
	

어떤 예외사항일지 모를 경우에는 가장 높은 Exception으로 모든걸 받아서 사용할 수 있음.

인스턴스로 모든게 처리된다. 즉, 예외 사항도 인스턴스이다.

 

2. 뺄셈(예외 사항 떠넘기기)

case "2":// 뺄셈 처리(예외사항 떠넘기기)
				try {
					subManage();
				} catch (NumberFormatException e) {
					System.out.println("숫자를 입력해 주세요.");} catch (Exception e) {
                    System.out.println("숫자를 입력해 주세요.");					
				}
				break;

	private static void sub() throws NumberFormatException, Exception {
		int n1, n2, rs;
		String str;

		System.out.println("뺄셈 연산");
		
			System.out.print("첫번째 수 : ");
			str = scan.nextLine();
			n1 = Integer.parseInt(str);
			System.out.print("두번째 수 : ");
			str = scan.nextLine();
			n2 = Integer.parseInt(str);

			rs = n1 - n2;

			System.out.println("계산 결과 : " + rs);
	}
    
    	public static void subManage() throws NumberFormatException, Exception{
		sub();		
	}
}

sub에서 전달되는 걸 subManage가 받아서 전달하는 흐름을 만들기 위해 subManage();를 작성해준다.

오류 발생시 가장 가까운 catch문이 받고, 아니면 다른 예외사항으로 다시 던진다.

다른 예외사항 발생할 경우를 대비해서 catch (Exception e)를 만들어준다.

Exception이 더 크기 때문에 나중에 써줘야함(먼저 작은 범위인 NumberFormatException부터 사용한다.)

 

NumberformatException, Exception에 대한 try, catch는 case문에 적어준다.

메소드 부른 곳에서 처리하기 때문에 메소드 이름 뒤에 throws exception을 작성해준다.

 

3. 나눗셈(자체처리, 떠넘기기)

			case "3":// 나눗셈 처리(자체 처리도 하고 떠넘기기도 하고)
				try {
					div();
				} catch (NumberFormatException e) {
					System.out.println("숫자를 입력해주세요.");
				}
				break;
                
       	private static void div() throws NumberFormatException{
		int n1, n2, rs;
		String str;

		System.out.println("나눗셈 연산");//서브 타이틀
		
			System.out.print("첫번째 수 : ");
			str = scan.nextLine();
			n1 = Integer.parseInt(str);
			System.out.print("두번째 수 : ");
			str = scan.nextLine();
			n2 = Integer.parseInt(str);
			
			try {
			rs = n1 / n2;
			} catch (ArithmeticException e) {
				System.out.println("0으로 나눌 수 없습니다.");
				rs = 0;
			}
			System.out.println("계산 결과 : " + rs);
	}

Exception으로만 하면 위에서 처리해야할 부분까지 전체 처리해주므로 오류 발생함.

if문 사전에 비교(true, false)
try~catch문 무조건 계산을 실행하고 봄, 안되면 예외사항으로 실행
if문 대신 try~catch문 사용하는 이유 if문은 연산이 필요하지만, 예외사항은 연산이 필요없기 때문에 사용한다.

 

4. 에외 사항 일부러 발생시켜서 처리하기

			case "4":// 예외를 일부러 발생 시켜서 처리해보기.
				try {
					makeException();
				} catch (MyException e) {
					System.out.println(e.getMessage());
					System.out.println("에러코드 : " + e.getErrCode());
				}
				break;
			default:
				break;
			}
		}
	}
    

	private static void makeException() throws MyException{
		MyException myexp =
				new MyException("페이지를 찾을 수 없습니다.", 404);
		
		throw myexp;
	}

'이런 예외사항이 발생할 수도 있다.'라는 가정을 해두는 것이다. 

여러 예외를 줄 수 있기 때문에 throws로 사용하며, 특정 문구를 가진 예외 인스턴스 만든다.

Exception myexp = new Exception("일부러 만든 예외사항~");

만든 예외를 던졌을 때 실제로 던져지는 부분은 case "4"의 try~catch문에서 받게된다.

실제로 사용하는 것은 throw myexp;이다. 이 경우 하나만 던지기 대문에 throw로 사용한다.

 

5. 예외 코드 저장 필드

class MyException extends Exception{
	private final int ERR_CODE;
	
	public MyException(String msg, int eCode) {
		super(msg);
		ERR_CODE = eCode;
	}
	
	public int getErrCode() {
		return ERR_CODE;
	}
}

super(msg)를 사용하기 때문에 부모 클래스의 메시지 출력한다.

return ERR_CODE는 에러코드만 받아서 상수값으로 넘긴다.

 

-etc

try~catch문 안에 try~catch문을 중첩으로 사용할 수 있음. 하지만 중첩하는 일은 거의 없다.

finally안에 catch 넣어서 사용하는 경우는 종종 있다.

 

굳이 예외처리 어렵게 (상위로 보내서) 할 필요 없다. method안에서 try~catch 사용해서 예외사항 처리하는게 더 좋음.

+ Recent posts