exception handling

logY·2023년 1월 25일
0

Java

목록 보기
3/4

예외의 처리

에러와 예외

  • 어떤 원인에 의해 오동작 하거나 비정상적으로 종료되는 경우
    • 심각도에 따른 분류
      • Error
        • 메모리 부족, stack overflow와 같이 일단 발생하면 복구할 수 없는 상황😢
        • 프로그램의 비 정상적 종료를 막을 수 없음 → 디버깅 필요
      • Exception
        • 읽으려는 파일이 없거나, 네트워크 연결이 안 되는 등 수습될 수 있는 비교적 상태가 약한 것들
        • 프로그램 코드에 의해 수습 될 수 있는 상황

예외 클래스의 계층

  • checked exception
    • 예외에 대한 대처 코드가 없으면 컴파일이 진행되지 않음
    • unchecked exception(RuntimeException의 하위 클래스)
    • 예외에 대한 대처 코드가 없더라도 컴파일은 진행됨 → 갑자기 프로그램이 종료되버린다구…ㅠㅠ

try~catch 구문


try {
	// 예외가 발생할 수 있는 코드
}
catch(XXXException e) {
	// 예외가 발생했을 때 처리할 코드
}

ㅇㅎ JVM이 예외를 처리하는구나!!!

그러면 try~catch 문에서의 흐름은 어떻게 될까?

  1. try 블록에서 예외가 발생하면 JVM이 해당 Exception 클래스의 객체를 생성 후 던짐(throw) → 자바는 예외처리도 클래스로 하는구나! 😀더
  2. 던져진 exception을 처리할 수 있는 catch 블록에서 받은 후 처리
    • 적당한 catch 블록을 만나지 못하면 예외처리는 실패
  3. 정상적으로 처리되면 try~catch블록을 벗어나 다음 문장 진행
  4. try 블록에서 어떠한 예외도 발생하지 않은 경우
    • catch문을 거치지 않고 try~catch 블록의 다음 흐름 문장을 실행

💡 예외의 종류는 너무 많다… 그리고 이름도 길다… 하지만!! 예외 이름의 패턴이 존재하는데 `XXXException`의 형태로 되어있다고 보면된당….(어차피 eclipse가 알려주겠지~~~ 😝)

다중 exception handling

여러 개의 예외가 발생할 수도 있다!?
어떻게 예외를 처리할 수 있는지 알아보자!!!

try 블록에서 여러 종류의 예외가 발생할 경우

  • 하나의 try 블록에 여러 개의 catch 블록 추가 가능
    • 예외를 종류별로 catch 블록으로 구성할 수 있다!!
💡 여기서!!! Exception이라는 오류는 모든 오류를 처리할 수 있다. 이것 또한 다형성 때문!!!!

다중 catch문장 작성 순서는 어떻게 될까?

  • JVM이 던진 예외는 catch문장을 찾을 때는 다형성이 적용된다… (다형성이 뭐였더라…)
  • 상위 타입의 예외가 먼저 선언되는 경우 뒤에 등장하는 catch블록은 동작할 기회가 없다 (작성하지를 말자… 🥲) → 이건 에러가 발생(컴파일 에러)
  • 다형성이 적용되기 때문에 동일한 로직의 예외처리는 부모의 예외처리에서 끝낼 수 있겠군… 👍
  • 상속 관계에서는 작은 범위(자식)에서 큰 범위(조상) 순으로 정의

아뉘 다형성이 존재하면 그냥 Exception으로 때려 넣으면 되는 거 아님??? 😡

💡 예외 발생 여부가 중요한것이 아니라 예외가 발생시 어떻게 처리할 것인지가 중요하다!!!

어떤 오류가 발생했을까?

try~catch~finally 구문을 이용한 예외 처리

finally는 예외 발생 여부와 상관 없이 언제나 실행

try~catch문에서 겹치는 내용을 finally에 작성해주면 되는구나!!!!

💡 겹치는 내용을 굳이 `finally`에서 실행하는 이유는???

try~catch문에서 return을 만나게 되면 바로 함수가 종료되기 때문에 try~catch문 밖의 코드는 실행되지 않지만, finally를 사용하게 되면 return을 하기 전에 finally 안의 코드를 먼저 실행하게 된다!!!

finally에서 close를 통한 자원 반납

try안에 try… 내방처럼 너무 지저분하잖아!?

try-with-resources

💡 JDK 1.7이상에서 리소스의 자동 close 처리가 된다!!(오예~~)

AutoCloseable interface를 미리 구현해야된다. → 인터페이스니까 무!조!건! 작성해줘야한다고~

사용법

public class Test07 {
	public static void main(String[] args) {
		try (FileReader fr = new FileReader("Test4.txt"); BufferedReader br = new BufferedReader(fr);) {

			while (true) {
				String line = br.readLine();

				if (line == null)
					break;
				System.out.println(line);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
public class Test07 {
	public static void main(String[] args) {
		FileReader fr = null;
		BufferedReader br = null;
		try {
			fr = new FileReader("Test4.txt");
			br = new BufferedReader(fr);
			while (true) {
				String line = br.readLine();

				if (line == null)
					break;
				System.out.println(line);
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (br != null) {
				try {
					br.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if (fr != null) {
				try {
					fr.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}

	}
}

AutoCloseable 인터페이스의 사용자 정의

class MyClose implements AutoCloseable {
	@Override
	public void close() throws Exception {
		System.out.println("MyClose - close() 호출됨");
	}
}

위와 같이 AutoCloseable을 implements를 해서 직접 구현가능하다…!!!

그리고 finally과 마찬가지로 무!조!건! close()는 실행된다!!!

예외처리의 종류

checked exception → RuntimeException의 계열이 아닌 것

반드시 예외처리를 해야한다. 즉, 컴파일 시점에서 에러를 발생시킨다. → 프로그램을 실행 시킬 수 없다.

예외 처리 방법

직접 처리

직접처리는 컴파일 시점에서 에러를 발생시킨다.

  • try
  • catch
  • finally

간접 처리

간접 처리는 런타임 시점에 에러를 발생시킨다. 즉, 컴파일 시점에 알 수 없다…ㅠㅠ 🥲

  • throws XXXException
  • System.out.println(1 / 0);과 같은 오류가 대표적
  • 런터임 시점에 에러는 거의 전부 개발자의 실수로 인해서 발생한다.

사용자 정의 예외

API에 정의된 exception이외에 필요에 따라 사용자 정의 예외 클래스

💡 사용자 정의 예외 또한 checked와 unchecked를 구별하여 정의할 수 있다. 이것 또한 예외 클래스를 상속 받아서 정의한다!!

JVM은 사용자가 정의한 예외를 알 수 없기 때문에 개발자가 직접! 예외를 발생 시켜야한다.

throw(s없음)

throw + 발생시킬 예외 객체의 형태로 직접 예외를 발생시킨다..

여기서 throw는 예외를 돈지는 역할을 한다….

💡 에러 클래스에 따라 에러를 받고 던지고를 판단하는 기준이 된다. (어렵…)

throw로 예외를 던질 때 클래스를 던지기 때문에 직접 생성하던지 기존에 생성된 클래스를 던지던지 파악해야한다.

class LottoNumberException extends RuntimeException {
}

class LottoService {
	private static final int MAX_NUM = 500;

	public int makeNumber() {
		Random r = new Random();
		int num = r.nextInt(MAX_NUM) + 1;
		if (num > 45) {
			throw new LottoNumberException();
		}
		return num;
	}
}

public class Test08 {
	public static void main(String[] args) {
		LottoService service = new LottoService();
		try {
			System.out.println(service.makeNumber());
		} catch (Exception e) {
			System.out.println("에러");
		}
	}
}

위의 코드를 보면 int makeNumber()에 throws가 없지만 에러를 던진다!!

👍 런타임 예외에서 throws의 역할은 예외 처리를 하는지 하지 않는지의 역할이 아니라 에러를 처리해야 한다는 것을 알려주는 일종의 명시이다… 즉, throws가 없더라도 런타임 예외에서는 예외가 발생하면 무조건 throw를 던진다…
profile
백엔드 개발자

0개의 댓글