에러를 처리하는 방법
Throwable
두 종류의 자식 클래스가 있음
- Error
- 프로그램 종료되어야 하는 심각한 문제 표현
- 대부분 컴퓨터나 JVM이 시스템적으로 동작할 수 없는 상황
- 대표적인 에러 OOM
Java는 JVM 내 Heap이라는 메모리 공간을 운영체제로 할당 받아 사용함 할당 받을 수 있는 최대 메모리 이상 사용하게 되면 JVM 다운 이 경우 OutOfMemoryError가 나면서 프로그램 종료됨 Java의 대표적인 에러 상황 : OOM
Exception
- 프로그램이 종료되지는 않지만 예외나 문제상황 표현하기 위해 사용
새로운 예외 정의하고 싶다면 Throwable 또는 그 하위에 있는 예외 클래스를 상속받아 정의
catch문은 여러가지 예외에 대해 중복 catch 블럭을 사용하여 이어서 쓸 수 있는데
앞에 있는 catch문에 잡혀서 그 블록을 실행했다면 그 뒤에 있는 catch문에는 잡히지 않음 (catch문들로는 전파 되지 않음)
즉, 에러가 앞에서 잡혔으면 뒤에선 잡히지 않는다는 것∴ 좁은 범위의 예외부터 앞에 선언하는 것이 좋음
- 좁은 범위란 상속관계에서 자식 클래스에 위치 할수록 좁은 범위
예를 들어서 IOException이 발생할 것 같아 예외처리를 하고, 그 외의 예외도 예외처리를 하고 싶다면 IOException을 catch 하는 구문을 먼저 Exception 을 catch하는 구문을 그 뒤에 작성
모든 Exceptiondms getMessage를 가짐
- getMessage에는 Exception 예외의 이유 설명하는 글자가 담겨 있음
public class Main { public static void main(String[] args) { int number = 10; int result; for (int i = 10; i >= 0; i--) { try { result = number / i; System.out.println(result); } catch (Exception e) { System.out.println("Exception발생: " + e.getMessage()); // getMessage } finally { System.out.println("항상 실행되는 finally 구문"); } } } }
0으로 나눠지는 경우 catch문이 실행
1 항상 실행되는 finally 구문 1 항상 실행되는 finally 구문 1 항상 실행되는 finally 구문 1 항상 실행되는 finally 구문 1 항상 실행되는 finally 구문 2 항상 실행되는 finally 구문 2 항상 실행되는 finally 구문 3 항상 실행되는 finally 구문 5 항상 실행되는 finally 구문 10 항상 실행되는 finally 구문 Exception발생: / by zero 항상 실행되는 finally 구문
catch문 작성 전
- FileOutputStream, write, flush에 빨간줄
- 다루지 않은 예외가 FileOutputStream을 만들 때 FileNotFoundException이라는게 만들어 질 수 있고
- write, flush 할 때에는 IOException이 발생할 수 있다고 미리 경고하는 것
catch문 작성 후
- 빨간 줄 사라짐
- FileOutputStream은 크게 보면 IOException에 해당하기 때문에 catch문에서 다 걸림
try 괄호 안에는 AutoClosable 인터페이스 구현한 클래스만 올 수 있음
- AutoClosable 인터페이스에는 예외가 발생할 경우 close()메소드를 호출하기로 정의되어있기 때문에
import java.io.FileOutputStream; import java.io.IOException; public class Main { public static void main(String[] args) { try (FileOutputStream out = new FileOutputStream("test.txt")) { // test.txt file 에 Hello Sparta 를 출력 out.write("Hello Sparta".getBytes()); out.flush(); // catch문 작성 이전엔 FileOutputStream, write, flush에 빨간줄 // 다루지 않은 예외가 FileOutputStream을 만들 때 FileNotFoundException이라는게 만들어 질 수 있고 // write, flush 할 때에는 IOException이 발생할 수 있다고 미리 경고하는 것 // catch문 쓰니까 사라짐 // FileOutputStream은 크게 보면 IOException에 해당하기 때문에 catch문에서 다 걸림 } catch (IOException e) { System.out.println("IOException 발생 : "+ e.getMessage()); e.printStackTrace(); } } } // test 파일 생성되고 , 그 안에 Hello Sparta 적혀있음
- 에러가 발생하지 않더라도 에러 핸들링에 대한 코드가 필요할 수 있음
- try 뒤에 괄호가 있어서 그 안에 새로운 변수 할당
- 괄호안에 올 수 있는 것은 AutoClosable 인터페이스 구현한 클래스만 올 수 있음
위 코드를 try catch문을 사용했다면
- 코드 길어지고
- FileOutputStream 을 열고 닫을때 생기는 Exception 까지 그 상위에서 catch를 하거나 throws로 감싸줘야함
import java.io.FileOutputStream; import java.io.IOException; public class Main { public static void main(String[] args) throws IOException { FileOutputStream out = new FileOutputStream("test.txt"); try { // test.txt file 에 Hello Sparta 를 출력 out.write("Hello Sparta".getBytes()); out.flush(); } catch (IOException e) { e.printStackTrace(); } out.close(); } }
void method() throws IndexOutOfBoundsException, IllegalArgumentException { //메소드의 내용 }
divide() 함수는 매개변수(parameter)에 들어오는 값에 따라서
ArithmeticException과 ArrayIndexOutOfBoundsException이 발생1. throws 키워드를 통해서 divide() 함수에서 발생할 수 있는 exception의 종류가 무엇인지 알게 해주세요. 2. Main 함수에서 try-catch 문을 이용해서, 다음 동작을 구현하세요. a. ArithmeticException이 발생할 때는 잘못된 계산임을 알리는 문구 출력 b. ArrayIndexOutOfBoundsException이 발생할 때는 현재 배열의 index범위를 알려주는 문구 출력
- throws로 발생할 수 있는 에러 명세
class ArrayCalculation { int[] arr = {0, 1, 2, 3, 4}; public int divide(int denominatorIndex, int numeratorIndex) throws ArithmeticException, ArrayIndexOutOfBoundsException { // 이런 에러들이 발생할 수 있다고 명세 // 명세를 하면 이 함수를 사용하는 쪽에선 이런 에러에서 핸들링해야겠다고 생각할 수 있음 return arr[denominatorIndex] / arr[numeratorIndex]; } } public class Main { public static void main(String[] args) { ArrayCalculation arrayCalculation = new ArrayCalculation(); System.out.println("2 / 1 = " + arrayCalculation.divide(2, 1)); try { System.out.println( "1 / 0 = " + arrayCalculation.divide(1, 0)); } catch (ArithmeticException arithmeticException) { System.out.println("잘못된 계산입니다. " + arithmeticException.getMessage()); } try { System.out.println("Try to divide using out of index element = " + arrayCalculation.divide(5, 0)); } catch (ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException) { System.out.println( "잘못된 index 범위로 나누었습니다. 타당 index 범위는 0부터" + (arrayCalculation.arr.length - 1) + "까지 입니다."); } } }
2 / 1 = 2 잘못된 계산입니다. / by zero 잘못된 index 범위로 나누었습니다. 타당 index 범위는 0부터4까지 입니다. by zero : 0으로 나눴다고 알려주는 것
문제 발생시 Exception 핸들링 코드 작성해서 더 견고한 코드 만들 수 있음