OOP(5) : 예외 처리 / try-catch, throw, finally

부트캠프(END)/Java|2022. 6. 7. 16:19

객체 지향 프로그래밍(OOP: Object-Oriented Programming)

1. 데이터 보호

패키지 / 접근제어자 / 캡슐화

2. 재사용

변경해서 사용(상속 : is-a) / 그대로 사용(포함 : has-a)

3. 다형성

오버라이딩 / 오버로딩 

4. 형변환

5. 추상 클래스 / 인터페이스 

+5 내부 클래스

6. 예외처리 ← 오늘은 여기! 


예외처리

프로그램을 실행할 때 발생할 수 있는 에러에 미리 대비하는 코드이다.

비정상적인 종료를 방지하고 정상상태를 유지하기 위해 사용한다.

*** 예외처리를 한다고 에러를 잡아주는 게 아니다. 에러를 건너뛰는 것이다. ***

 

에러 = 프로그래머의 실수 or 사용자의 입력

 

예외처리해 주어야 하는 유형은 크게 다음과 같다. (당연히 더있음)

파일 입출력, 읽기 → IOException

데이터베이스 연결 → SQLException

네트워크 → MalformedURLException

크롤링 등을 포함한 위 3가지는 컴파일 시에 예외처리 여부를 확인한다. 

 

java파일(원시 소스)은 프로그래머만 인식하고 class파일(바이트 코드)은 컴퓨터가 인식한다.

자바 컴파일러가 자바 소스코드를 바이트코드로 만들고, 인터프리터가 바이트코드를 해석하고 실행한다.

이 때 컴파일 단계에서 발생하는 에러 컴파일 에러라고 하고, 해석 단계에서 발생하는 에러 런타임 에러라고 한다.

컴파일 에러는 반드시 예외처리를 해야 하고, 런타임 에러는 필요한 경우에만 에외처리를 해도 된다.

 

에러 : 심각한 에러(소스상에서 변경할 수 없는 에러)

→ 예: 메모리가 부족하여 강제 종료됨

예외 : 가벼운 에러(소스상에서 수정이 가능한 에러)

→ 예: 사이트 연결(주소가 다르다), 파일 읽기 시 경로가 다르다, 서버 연결 시 IP가 다르다 등

 

 

예외처리를 위한 클래스 구조

예외처리에도 순서가 있고 그 순서를 잘 지켜야 한다.

더 상위의 예외를 먼저 처리한 후에 그 하위의 예외를 처리하면 에러가 난다.

이미 더 넓은 범위에서 커버친 부분인데 또 처리하는 셈이니까...

 

https://stackify.com/types-of-exceptions-java/
https://rollbar.com/blog/java-exceptionininitializererror-runtime-error/

자주 등장하는 예외

CheckException (반드시 예외처리가 필요함)

- ***IOException : 파일 입/출력
- ***SQLException :DB 연결시
- MalformedURLException : 네트워크 연결시
- ClassNotFoundException : 메모리 할당 시, new가 없을 때
- InterrupedException : 스레드와 관련됨. 충돌 방지

⇢ 이 모든걸 뭉뚱그려서 그냥 Exception 으로 처리하면 편하다.

UnCheckException (필요시에만 예외처리, 생략 가능)

- ArrayIndexOutOfBoundsException : 배열 범위를 벗어났을 때
- NumberFormatException : 정수 변환이 안 된 경우
- ArithmeticException : 0으로 나눈 경우
- ClassCastException : class형 변환을 잘못한 경우
- NullPointerException : 주소 값이 없는 경우

 

 

예외처리 방법

1. 예외 복구 : try~catch문

try해보고 예외가 발생하면 그 예외를 catch해놓고 나머지를 수행한다는 느낌.

catch문은 여러 번 사용이 가능하다. 여러 가지 예외를 하나하나 지정해서 catch문을 작성할 수 있다.

try에서 에러가 없는 경우에는 catch블록 내에 있는 코드는 수행하지 않고 finally로 빠져나간다.

finally 는 데이터베이스, 네트워크, 파일 읽기, 크롤링시 프로그램을 종료하는 데에 주로 사용된다.

try {
    //정상으로 수행하는 문장
} catch (Exception ex) {
    /*에러 처리/복구하는 문장*/ } finally { //생략가능, 필요시에만 사용
    //반드시 수행하는 문장 : 오라클/서버/파일 등을 닫는 등..
}
package day24;

public class Ex2 {

    public static void main(String[] args) {
        try {
            //        	int[] arr = {1};
            //        	arr[1] = 20; //ArrayIndexOutOfBoundsException

            //            System.out.println(10 / 0); //ArithmeticException

            //            String a = " 10";
            //            System.out.println(Integer.parseInt(a)); //NumberFormatException

            Class.forName("day24.Ex11"); //ClassNotFoundException

        } catch (ArrayIndexOutOfBoundsException ex) {
            System.out.println("배열 범위를 초과함.");
        } catch (ArithmeticException ex) {
            System.out.println("0으로 나눌 수 없음.");
        } catch (NumberFormatException ex) {
            System.out.println("정수형 변환이 안 되었음.");
        } catch (ClassCastException ex) {
            System.out.println("클래스 형변환 문제 발생함.");
        } catch (NullPointerException ex) {
            System.out.println("클래스 객체의 값이 없음.");
        } catch (Exception ex) {
            //예외처리중에 가장 큰 클래스. 맨 위로 올라가면 에러난다.
            //이미 Exception이 모두 잡을 수 있기 때문에..
            System.out.println("(뭔진몰라도 아무튼)예외 에러 발생함.");
        } catch (Throwable ex) {
            //얘가 Exception보다 더 크다.
            //예외처리+에러까지 잡아주는 ...
            System.out.println("던져~던져!");
        }
        System.out.println("PROGRAM CLOSED");
    }

}

https://tutorial.eyehunts.com/java/try-catch-finally-java-blocks-exception-handling-examples/

언제나 try-catch문이 가장 바깥쪽에서 감싸줄 필요는 없다.

예외가 발생할 법한 부분만 감싸줘도 충분하다.

public class MainClass {

	public static void main(String[] args) {
		try {
			for(int i=1; i<=10; i++) {
				int j = (int)(Math.random()*3);
				System.out.println("i="+i+",i/j="+i/j);
			}
		}catch(Exception ex) {
			//에러가 발생하기만 하면 for문 자체가 멈춘다.
			System.out.println("Error");
		}
		
		for(int i=1; i<=10; i++) {
			try {
				int j = (int)(Math.random()*3);
				System.out.println("i="+i+",i/j="+i/j);
			}catch(Exception ex) {
			//에러가 발생해도 for문은 정해진 횟수만큼 돌아간다.
				System.out.println("Error");
			}
		}
	}
}

 

2. 예외 발생시키기 : throw (throws와 다름)

throw를 사용해서 고의로 예외를 발생시킬 수 있다.

프로그램의 안정성을 테스트하기 위해 주로 사용하고, 임의로 발생한다.

//연산자 new를 이용해서 발생시키려는 예외 클래스의 객체를 만듬 
Exception e = new Exception("thorw example"); 
//String을 넣어주면 getMessage()를 통해 해당 메시지를 얻을 수 있다.
//throw로 예외를 발생시킴 
throw e;
public static void main(String[] args) {
    try {
        Exception e = new Exception("throw Exception");
        throw e;
        //throw new Exception("throw Exception"); 이렇게 짧게도 쓸 수 있음.
    } catch (Exception e) {
        System.out.println("Error:" + e.getMessage());
    }
}

 

3. 예외 회피 : throws

throws를 이용하면 예외 처리를 위한 예외를 메서드에 선언할 수 있다.

try-catch문과 달리 메서드의 선언부에 키워드 throws와 함께 발생할 수 있는 예외를 적어 준다.

또한 try-catch와 달리 예외의 클래스 구조와 관계없이 순서 무관하게 작성이 가능하다.

(상위 Exception을 하위 Exception 보다 먼저 명시한다던가)

void method() throws Exception1, Exception2,...ExceptionN{
	//메서드 내용
    }

임의의 사용자가 이 메서드를 사용하기 위해 어떤 예외들이 처리되어야 하는지 쉽게 알 수 있다.

예외를 메서드에 명시하는 것은 해당 예외를 처리하는 것이 아니라,

예외가 발생할 가능성이 있는 메서드를 호출한 메서드에게 예외를 전달하여 예외처리를 떠맡기는 것이다.

 

 

예외 임의 발생

자바에서 모든 에러에 대한 처리를 할 수는 없기 때문에,

사용자 정의 예외 처리도 가능하다. → class MyException extends Exception

자세한 내용은 https://www.geeksforgeeks.org/user-defined-custom-exception-in-java/ 참조

 

 

+멀티블록

OR을 써서 여러 개의 예외를 같이 잡을 수 있다.

package day24;

public class Ex3 {

	public static void main(String[] args) {
		try {
//			System.out.println(10/0);
			int[] a = {1};
			a[1] = 0;
			//멀티블록. 하나로 여러 개의 에러를 잡는것임. OR로 연결가능함.
		}catch(ArrayIndexOutOfBoundsException | ArithmeticException ex) {
			System.out.println("Error!!");
		}
	}

}

 

getMessage()와 printStackTrace()

getMessage()를 통해 어떤 에러가 발생했는지 정보를 출력하거나,

printStackTrace()로 어느 위치에서 에러가 발생했는지 확인이 가능하다.

보통 catch문에 써 준다.

package day24;
/*
 * 에러메시지 처리방법
 * = getMessage() -> 실제 에러내용만 출력
 * = printStackTrace() -> 에러 위치 확인***
 */
import java.util.*;
public class Ex3_1 {

	public static void main(String[] args) {
		try {
			Scanner scan = new Scanner(System.in);
			System.out.print("first int:");
			int num1 = scan.nextInt();
			System.out.print("second int:");
			int num2 = scan.nextInt();
			
			int[] arr = new int[2];
			arr[0] = num1;
			arr[1] = num2;
			
			int result = num1/num2;
			System.out.println(result);
		}catch(Exception ex) {
			System.out.println(ex.getMessage());
			ex.printStackTrace(); 
		}
	}

}

 

'부트캠프(END) > Java' 카테고리의 다른 글

java.lang package  (0) 2022.06.08
OOP(4) : 내부 클래스  (0) 2022.06.03
OOP(3) : 형변환, 추상 클래스, 인터페이스  (0) 2022.06.02

댓글()