본문 바로가기
들은 강의

[생활코딩 자바2] - 6. JAVA 예외(checked exception, Finally, Resource, Try with Resource)

by hotdog7778 2023. 6. 6.

쉽게 배우는 자바2[생활코딩] - 공부 기록

해당 강의는 https://www.boostcourse.org/cs128 에서 무료로 수강 할 수 있다.


1. 수업소개

들어가기 전에

여러분의 프로그램에서 예상하지 못한 여러 오류가 발생했던 적이 있나요?

이번 시간부터는 예외에 대해서 알아봅니다.

학습 목표

자바의 예외에 대해서 알아봅니다.

핵심 단어

  • 예외(Exception)

강의 내용

우리의 프로그램은 여러 **오류(Error)**를 낼 수 있습니다.

애초에 문법이 잘못되어서 컴파일부터 오류를 낼 수도 있고,

정전, 시스템 오류와 같은 경우도 있습니다.

한편 이러한 오류들과는 다른 것들이 있을 수 있습니다.

예상한 범위를 벗어나는 방식으로 프로그램을 동작시켜서 예상치 못한 결과를 낼 수 있습니다.

이를테면 있을 것이라고 생각한 파일을 여는 작업을 하는데, 실제로는 파일이 없다거나

나눗셈을 하는 프로그램에서 나누는 숫자에 0을 넣어서 돌린다거나,

배열을 다루는 프로그램에서 범위를 벗어난 인덱스를 호출한다거나 하는 상황이 있습니다.

이러한 경우는 자바에서는 **예외(Exception)**라고 부릅니다.

예외는 어쩔 수 없는 숙명인 오류와는 달리 피할 수 있게 만들 수 있습니다.

유비무환의 자세로 예외를 잘 처리하면 튼튼한 프로그램을 만들 수 있습니다.

2. 예외의 발생

학습 목표

예외가 발생하는 상황을 알아봅니다.

핵심 단어

  • 예외(Exception)
  • ArithmeticException

강의 내용

public class ExceptionApp {

	public static void main(String[] args) {
		System.out.println(1);
		System.out.println(2/0); 
		// Exception in thread "main" java.lang.ArithmeticException: / by zero
		// at ExceptionApp.main(ExceptionApp.java:6)

		System.out.println(3);

	}

}

3. 예외의 처리

들어가기 전에

예외가 발생하면 프로그램이 바로 중지되어야 할까요?

그렇게 된다면 사용자 입장에서는 까다로운 오류 투성이 프로그램으로 보일 것입니다.

프로그램을 어떻게든 돌아가게 만들기 위해서 발생할 것으로 예상되는 예외를 어떻게 처리해야 할까요?

이번 시간에는 예외의 처리에 대해서 알아봅니다.

학습 목표

try catch 문으로 예외를 처리하는 방법에 대해서 알아봅니다.

핵심 단어

  • 예외 처리(Exception Handling)
  • try catch

강의 내용

public class ExceptionApp {

	public static void main(String[] args) {
		System.out.println(1);
		
		int[] scores = {10,20,30};
//		try {
//			System.out.println(scores[3]); //3이 index
//			//Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
//			//at ExceptionApp.main(ExceptionApp.java:7)
//		} catch(ArrayIndexOutOfBoundsException e) {
//			System.out.println("없는 값을 찾고네있네요.");
//		}
		
		try {
			System.out.println(scores[3]); //3이 index
//			//Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
//			//at ExceptionApp.main(ExceptionApp.java:7)
			System.out.println(2 / 0); 
			// Exception in thread "main" java.lang.ArithmeticException: / by zero
			// at ExceptionApp.main(ExceptionApp.java:6)
			System.out.println(3);
			System.out.println(4);
			System.out.println(5);
		} catch(ArithmeticException e) {
			System.out.println("잘못된 계산이네요.");
		} catch(ArrayIndexOutOfBoundsException e) {
			System.out.println("없는 값을 찾고네있네요.");
		} //try를 합치니 먼저 발생한 익셉션만 실행되고 이후에 작업은 실행되지 않
		System.out.println(3);

	}

}

4. 예외의 우선순위

들어가기 전에

발생할 법한 예외를 예측해서 적절히 처리하면 참 좋겠지만

예외상황마다 개별적으로 취해야 할 작업이 없다면,

단순히 예외를 일일이 예측하는 게 귀찮다면,

어떤 예외가 나올지 예측할 수 없다면 어떻게 해야 할까요?

이번 시간에는 좀 더 예외 상황을 포괄적으로 처리하기 위해서

예외의 우선순위가 어떻게 되는지 알아보도록 합니다.

핵심 단어

  • 예외
  • Exception 클래스

학습 목표

예외의 우선순위에 대해서 알아봅니다.

강의 내용

public class ExceptionApp {

	public static void main(String[] args) {
		System.out.println(1);
		
		int[] scores = {10,20,30};
//		try {
//			System.out.println(scores[3]); //3이 index
//			//Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
//			//at ExceptionApp.main(ExceptionApp.java:7)
//		} catch(ArrayIndexOutOfBoundsException e) {
//			System.out.println("없는 값을 찾고네있네요.");
//		}
		
		try {
			System.out.println(scores[3]); //3이 index
//			//Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
//			//at ExceptionApp.main(ExceptionApp.java:7)
			System.out.println(2 / 0); 
			// Exception in thread "main" java.lang.ArithmeticException: / by zero
			// at ExceptionApp.main(ExceptionApp.java:6)
			System.out.println(3);
			System.out.println(4);
			System.out.println(5);
		} catch(Exception e) { //Exception은 ArithmeticException과 ArrayIndexOutOfBoundsException 의 부모격이다.
			System.out.println("뭔가 이상합니다. 오류가 발생했습니다.");
		}
		
		System.out.println(3);

	}

}

5. e의 비밀

들어가기 전에

catch 문에 있는 e 변수는 무엇일까요?

이번 시간에는 e로 무엇을 할 수 있는지 알아봅니다.

학습 목표

Exception 변수 e에 대해서 알아봅니다.

핵심 단어

  • Throwable 클래스

강의 내용

catch 문의 변수 e도 인스턴스인데 이것을 이용해서 무엇인가 할 수 있을까요?

예외들의 인스턴스에는 예외가 발생한 원인, 어디서 발생했는지 등에 대한 정보들이 들어 있습니다.

이것들을 이용하면 프로그램의 어디서 왜 예외가 발생했는지 손쉽게 알 수 있습니다.

getMessage 메소드를 이용하면 예외 상황에 대한 디테일한 정보를 얻을 수 있습니다.

다만, 이러한 정보를 통해, 코드의 내용이나 구조 등을 나쁜 의도를 가진 사람들에게 노출할 수도 있기 때문에

보통 이러한 정보를 사용자가 직접 볼 수 있게 구성하지는 않고,

서버 측에서 로그 파일 등을 이용해 관리자만 볼 수 있게 처리합니다.

자세한 메소드의 종류는 Throwable 클래스의 설명서에서 확인할 수 있습니다.

public class ExceptionApp {

	public static void main(String[] args) {
		System.out.println(1);
		
		int[] scores = {10,20,30};
//		try {
//			System.out.println(scores[3]); //3이 index
//			//Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
//			//at ExceptionApp.main(ExceptionApp.java:7)
//		} catch(ArrayIndexOutOfBoundsException e) {
//			System.out.println("없는 값을 찾고네있네요.");
//		}
		
		try {
			System.out.println(2);
//			System.out.println(scores[3]); //3이 index
//			//Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
//			//at ExceptionApp.main(ExceptionApp.java:7)
			System.out.println(3);
			System.out.println(2 / 0); 
			// Exception in thread "main" java.lang.ArithmeticException: / by zero
			// at ExceptionApp.main(ExceptionApp.java:6)
			System.out.println(4);
		} catch(ArithmeticException e) {
			System.out.println("잘못된 계산을 하고 계시네요"+e.getMessage()); //e라는 변수안에 무슨에러가 난건지에 대한 정보가 저장되어 있음.
			e.printStackTrace(); //에러메세지 출력 
		} catch(Exception e) { //Exception은 ArithmeticException과 ArrayIndexOutOfBoundsException 의 부모격이다.
			System.out.println("뭔가 이상합니다. 오류가 발생했습니다.");
		}
		
		System.out.println(5);

	}

}

6. Checked exception vs Unchecked exception

들어가기 전에

어떤 Exception은 사용자가 try catch로 잡아내지 않더라도 무사히 컴파일이 되기도 하고

어떤 Exception은 try catch 또는 메소드 단위에서 throws를 이용해서 잡지 않으면 컴파일이 되지 않습니다.

이번 시간에는 Exception의 분류에 대해서 알아봅니다.

학습 목표

checked Exception과 unchecked Exception에 대해서 알아봅니다.

핵심 단어

  • checked, unchecked Exception

강의 내용

우리가 만들었던 프로그램은 ArithmeticException, ArrayIndexOutOfBoundsException 같은 경우는

try catch 문으로 잡아내지 않아서 프로그램이 뻗는다고 할지라도

컴파일해서 실행할 수 있기는 했습니다.

이러한 Exception들을 unchecked Exception이라고 부릅니다.

unchecked Exception은 모두 RuntimeException 클래스로부터 상속된 예외들입니다.

하지만 try catch 문 등으로 잡아내지 않으면 프로그램이 컴파일도 안되는 예외들도 있습니다.

이러한 예외들을 checked Exception이라고 부릅니다.

Throwable로부터 상속된 모든 클래스에서 RuntimeException을 제외한 모든 에러와 예외들이

checked Exception에 속합니다.

checked Exception은 반드시 예외 처리를 해 주어야 합니다.

만약 IOException을 처리하지 않는다면 제대로 컴파일이 되지 않는 모습을 볼 수 있습니다.

import java.io.FileWriter;
import java.io.IOException;

public class CheckedExceptionApp {

	public static void main(String[] args) {
		
		try {
			// IO익셉션이 발생하는 코드를 만들어봄.
			FileWriter f = new FileWriter(fileName:"data.txt");
			f.write(str:"Hello");
			f.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

}

7. Finally와 Resource 다루기

들어가기 전에

FileWriter 객체의 경우 파일 작업이 다 끝나고 나면 close를 이용해서 파일을 닫아주는 작업을 했습니다.

try 문에서 FileWriter 객체를 만들고, 닫는 작업까지 다 넣었을 때,

그 중간의 파일 작업에서 예외가 발생한다면 어떻게 될까요?

그럼 파일을 닫아주는 작업을 실행하지 못할 것입니다.

이번 시간에는 이런 경우에 어떻게 처리하면 좋을지 finally 문에 대해서 알아봅니다.

학습 목표

finally 문에 대해서 알아봅니다.

핵심 단어

  • 자원(Resource)
  • finally

강의 내용

finally 문

그런데, try 문에서 오류가 발생하면 이후에 작업이 있더라도 catch 문으로 넘어갑니다.

그래서 자원을 놓아주는 작업을 try 문에 넣게 되면,

예외가 발생했을 때 자원을 놓아주는 작업을 하지 못하게 됩니다.

그래서 예외가 발생했든, 발생하지 않았든 자원을 일단 잡았으면 놓아주는 작업을 실행하도록 해야 합니다.

이런 경우에 사용하는 형식이 finally 문입니다.

finally 문은 try 문에서 예외가 발생했거나 발생하지 않았거나 무조건 실행됩니다.

import java.io.FileWriter;
import java.io.IOException;

public class CheckedExceptionApp {

	public static void main(String[] args) {
		
		FileWriter f = null;
		try {
			// IO익셉션이 발생하는 코드를 만들어봄.
			f = new FileWriter("data.txt");
			f.write("Hello");
			//close를 하기 전에 예ㅚ가 발생할 수 있기 때문에 finally로 처리해야 합니다. 
			f.close();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if(f != null) {
				try {
					f.close();
				} catch(IOException e) {
					e.printStackTrace();
				}
			}
		}
	}

}

8. Try with Resource

들어가기 전에

자원을 잡고, 놓아주는 작업을 try catch finally 문으로 만드는 과정은 상당히 복잡합니다.

그래서 자원을 잡고, 놓아주는 작업을 간단한 형식으로 만들 필요성이 생겼습니다.

이번 시간에는 try-with-resource 구문을 이용하여 자원 사용을 간단하게 하는 방법을 알아봅니다.

학습 목표

try-with-resource 구문을 이용하여 자원의 예외 처리를 간단하게 할 수 있습니다.

핵심 단어

  • try-with-resource 문

강의 내용

try-with-resource 문

Java SE 7 이전에는 우리가 지난 시간에 만들었던 코드와 같이 finally 문을 이용하여

자원을 놓아주는 작업을 진행하였습니다.

하지만 Java SE 7부터 try-with-resource 문이 등장하여 자원 관리를 훨씬 단순하게 할 수 있게 되었습니다.

클래스가 AutoCloseable 인터페이스를 상속한다면 try-with-resource 문에 사용할 수 있습니다.

import java.io.FileWriter;
import java.io.IOException;

public class TryWithResource {

	public static void main(String[] args) {
		
		// try with resource statements
		try (FileWriter f = new FileWriter("data.txt")){
			f.write("Hello"); 
			// f.close(); 자동으로 해주니까 필요 없음 		
		} catch(IOException e) {
			e.printStackTrace();
		}
	}
}

9. 수업을 마치며

들어가기 전에

여기까지 오시느라 수고 많았습니다.

이번 시간에는 앞으로 배울 만한 주제들에 대해서 알아봅니다.

학습 목표

앞으로 배울 만한 주제들에 대해서 알아봅니다.

핵심 단어

  • throw 구문
  • throws 구문

강의 내용

throw Exception

지금까지는 남들이 발생시키는 예외에 대해서 처리하는 방법에 대해서 배워 보았다면

우리가 우리의 코드에서 예외를 발생시킬 수도 있습니다.

이렇게 문제 상황이 발생했을 때, throw 구문을 통해서 예외를 발생시킬 수도 있습니다.

이 경우에는 RuntimeException 객체를 이용하였지만, Exception 객체도 여러분이 직접 생성할 수도 있습니다.

메소드 단위로 예외 발생

try catch 문으로 예외를 처리할 수도 있지만,

우리가 만든 메소드가 우리의 설계 의도대로 돌아가지 않을 경우

메소드 자체에서 예외를 발생시킬 수도 있습니다.

폭탄돌리기처럼, 우리가 직접 예외를 처리한다기보다는 앞으로 우리의 메소드를 사용할 누군가가

예외를 처리해 주기를 바라는 것과 같습니다.

import java.io.FileWriter;
import java.io.IOException;

public class MyException {
	public static void main(String[] args) throws IOException {
		// throw new RuntimeException("무언가 문제가 있습니다. ");
		FileWriter f = new FileWriter("./data.txt");
	}
}