[JAVA]예외(Exception)

김나영·2022년 8월 4일
0
post-thumbnail
  • Error
    • 컴퓨터 내부 문제 ( out of memory )
    • 시스템 수정으로 문제를 해결
  • Exception
    • 자바 내 잘못된 코드
    • 코드 수정으로 문제 해결

예외 (Exception)

  • 프로그램의 실행 중 발생하는 여러 가지 오류를 의미함
  • 예외가 발생하면 프로그램이 강제로 종료됨
  • 예외가 발생하더라도 프로그램이 종료되지 않도록 예외처리를 해야 함
  • try - catch문을 이용해서 예외 발생으로 인해 프로그램이 종료되는 것을 회피할 수 있음.

* 예외발생 예시

* Exception의 구조

  • Exception 클래스
    • 모든 예외 클래스의 슈퍼클래스
    • 명시적 예외 처리 여부에 따라 Checked / Unchecked Exception으로 구분
  • Checked Exception
    • RuntimeException 클래스의 자식클래스가 아닌 모든 예외 클래스
    • 반드시 try - catch 문으로 예외 처리를 해야 함
    • IOException, SQLException 등
  • Unchecked Exception
    • RuntimeException 클래스의 자식클래스로 등록된 모든 예외 클래스
    • try - catch문이 없어도 실행 가능
    • NullPointerException, NumberFormatException 등

Try-Catch

  • 예외를 처리할 때 사용하는 코드
  • 실행할 코드는 try 블록에 두고 예외를 처리할 코드는 catch 블록에 두는 방식
  • try 블록의 코드를 실행하다가 예외가 발생되면 발생된 예외는 자동으로 catch 블록으로 전달됨
  • 모든 예외는 자바 클래스로 만들어져 있음

형식

try {
	실행 코드
} catch (예외 타입 선언) {
	예외 처리 코드
}

예외 처리 흐름

  • 정상 흐름 : 1 → 2 → 3 → 5 순으로 진행
    try{
    	① 정상 실행 코드
        ② 정상 실행 코드
        ③ 정상 실행 코드
    } catch(예외 타입 선언) {
    	~~④예외 처리 코드~~
    }try - catch 이후 코드
  • 예외 흐름 : 1 → 2 → 4 → 5 순으로 진행
    try {
    	① 정상 실행 코드
        **② 예외 발생 코드**
        ~~③ 정상 실행 코드~~
    } catch (예외 타입 선언) {
    	④예외 처리 코드
    }try - catch 이후 코드

다중 catch 블록

  • 하나의 try 블록에 여러개의 catch 블록이 추가될 수 있음
  • try 블록에서 발생된 예외는 우선 첫 번째 catch 블록을 방문함
  • 첫 번째 catch 블록이 처리하지 못하면 다시 두 번째 catch 블록을 방문함

형식

try	{
	실행 코드
} catch (예외 타입 선언1) {    // 예외 발생시 1차 방문
	예외 처리 코드 1				↓예외 타입이 안 맞으면 이동
} catch (예외 타입 선언2) {	 // 2차 방문
	예외 처리 코드 2
}
  • 예외 클래스들의 상속 관계를 파악한 뒤 catch 블록을 작성해야 함
  • 슈퍼클래스 타입인 Exception이나 RuntimeException의 경우에는 마지막 catch 블록에서 처리

잘못된 catch 블록

try	{
   //
} catch (Exception e) { 
   // 모든 예외를 처리 했기 때문에
} catch (IOException e) {
   // 실행 불가
}

정상적인 catch 블록

try	{
   //
} catch (IOException e) { 
   // IOException만 처리하고 다른 예외는 두 번째 catch 블록이 처리함
} catch (Exception e) {
   // IOException 이외의 예외 처리 담당
}

finally 블록

  • try - catch문 마지막에 추가하는 블록
  • 예외 발생 여부와 상관 없이 항상 마지막에 실행되는 블록
  • 필요 없는 경우 finally블록은 생략할 수 있음
  • 주로 어떤 자원을 반납 (close) 할 때 사용

형식

try {
	실행 코드
} catch (예외 타입 선언) {
	예외 처리 코드
} finally {
	무조건 실행되는 코드
}

기본

finally

throw

  • 개발자가 직접 예외를 던지는 경우에 사용
  • 예외 객체를 만들어서 직접 throw할 수 있다.
  • 자바는 예외로 인식하지 않지만 실제로는 예외인 경우에 주로 사용된다.
  • 개발자가 직접 만든 예외클래스를 던지는 것도 가능함

형식

try{
	if(예외 상황이면) {
    	throw new RuntimeException("예외 메시지");
    }          // 예외를 발생시켜서 덤짐 (throw)
} catch(RuntimeException e {
	System.out.println(e.getMesssage());  // 예외메세지
}

-throw로 만든 예외 메세지는 getMessage로 확인 가능

class Exception{
	private String message;
    pulic Exception(String message){
    	this.message = message;
    }
    public String getMessage() {
    	return message;
    }
}
class RuntimeException extends Exception{
	public RuntimeException (String message) {
    	super(message);
    }
}
Exception e = new RuntimeException("나이는 0이상 100이하만 가능합니다.");
System.out.ptintln(e.getMessage());

throws

  • 메소드에서 예외를 처리하는 방식
    • 메소드 내부에 try-catch문을 두고 직접 처리하는 방식
    • 메소드 외부로 예외를 던져서 메소드를 호출하는 곳에서 try-catch문으로 처리하는 방식
  • 메소드 외부로 예외를 던질 때 throws문을 이용해 던지는 예외를 명시함
  • 2개 이상의 예외를 명시할 수 있기 때문에 throw가 아닌 throws 라고 함

기존 throw 문

public class ThrowsEx{
	public static void method() {
    	try{
        	메소드 내부 코드
        } catch(Exception e) {
        	예외 처리 코드
        }
    }
    public static void main(String[] args) {
    	method();
    }
}

throws 사용 문

public class ThrowsEx{
	public static void method() throws Exception {
    	메소드 내부 코드
    }
    public static void main(String[] args) {
    	try {
        	method();
        } catch(Exception e){
        	예외 처리 코드
        }
    }
}

* ParkingLot

import java.util.InputMismatchException;
import java.util.Scanner;
public class ParkingLot {	
	private Car[] cars;
	private int idx;
	private Scanner sc;	
	public ParkingLot() {
		cars = new Car[10];
		sc = new Scanner(System.in);
	}
	public void addCar() throws RuntimeException{		
			if(idx == cars.length) {
				throw new RuntimeException("FULL");
			}
	}	
	public void deleteCar() throws RuntimeException {			
			if(idx == 0) {
				throw new RuntimeException("EMPTY");
		}		
	}	
	public void findCar()  throws RuntimeException{
			if(idx == 0) {
				throw new RuntimeException("EMPTY");
			}		
	}	
	public void printAllCars() throws RuntimeException {
			if(idx == 0) {
				throw new RuntimeException("EMPTY");
			}		
	}	
	public void manage() {		
		while(true) {
			try {		
					System.out.print("1.추가 2.제거 3.조회 4.전체목록 0.종료 >>> ");
					int choice = sc.nextInt();
					switch(choice) {
					case 1: addCar(); break;
					case 2: deleteCar();break;
					case 3: findCar();break;
					case 4: printAllCars();break;
					case 0: return;
					default : throw new RuntimeException("Bad Request");
					}
			} catch (InputMismatchException e){
				sc.next();
				System.out.println("처리 명령은 정수(1~4,0) 입니다.");			
			} catch(RuntimeException e) {
				System.out.println(e.getMessage());
			}
		}			
	}	
	public static void main(String[] args) {		
		new ParkingLot().manage();		
	}	
}

MyException class

  • 사용자가 정의한 예외 클래스
  • Exception 클래스를 상속 받는다.

Serializable 인터페이스 : 이 인터페이스를 구현하면 직렬화가 가능. serialVersionUID값을 가져야 함 (추천)

Throwable 클래스 : serialVersionUID 값이 필요함

Exception 클래스 : serialVersionUID 값이 필요함

MyException 클래스 : serialVersionUID 값이 필요함

MyException 클래스

public class MyException extends Exception{
	private static final long serialVersionUID = -7774118171104436322L;
	private int errorCode;
	public MyException(String message, int errorCode) {
		super(message);
		this.errorCode = errorCode;
	}
	public int getErrorCode() {
		return errorCode;
	}
	public void setErrorCode(int errorCode) {
		this.errorCode = errorCode;
	}
}

ParkingLot 클래스

import java.util.InputMismatchException;
import java.util.Scanner;
public class ParkingLot {
	private Car[] cars;
	private int idx;
	private Scanner sc;	
	public ParkingLot() { 
		cars = new Car[10];
		sc = new Scanner(System.in);
	}
	public void addCar() throws MyException {
		if(idx == cars.length) {
			throw new MyException("FULL", 1000);   // 에러코드 1000  RuntimeException의 자식이 아니기 때문에 addCar 옆에 throws MyException 추가 필요		
		}
	}	
	public void deleteCar() throws MyException{
		if ( idx == 0) {
			throw new MyException("EMPTY", 2000);   // 에러코드 2000
		}
	}	
	public void manage() {
		while (true) {
			try {
				System.out.println("1.추가 2.삭제 0.종료 >>> ");
				int choice  = sc.nextInt();
				switch (choice) {
				case 1 : addCar(); break;
				case 2 : deleteCar(); break;
				case 0 : return;
				default : throw new RuntimeException("Bad Request");
				}
			} catch ( MyException e) {
				System.out.println(e.getMessage() + "[" + e.getErrorCode() + "]");
			} catch ( InputMismatchException e ) {
				sc.next();
				System.out.println("처리 명령은 정수만 가능");
			} catch ( RuntimeException e ) {
				System.out.println(e.getMessage());
			}
		}
	}		
	public static void main(String[] args) {
		new ParkingLot().manage();
	}	
}
profile
응애 나 애기 개발자

0개의 댓글