[Java] 예외 처리

SeongWon Oh·2021년 8월 21일
0

Java

목록 보기
33/39
post-thumbnail

예외 처리의 두가지 목적

  1. 예외처리는 시스템이 비정상 종료가 되는 것을 피하고 시스템이 월할하게 실행되도록 한다.
  2. 오류가 발생한 경우 log를 남겨서 추후 개발자가 log파일 분성을 통해 그 원인을 파악하고 버그를 수정하기 위해서 남긴다.

※ 위의 두개의 목적을 이루기 위해 예외처리는 필수적으로 해줘야한다.
로그는 기업마다 로그를 남기는 format이 따로 있다.


프로그램의 오류의 종류

  • Compile Error
    • 프로그램 코드 작성 중 발생하는 문법적인 오류이다.
    • Eclipse와 같은 개봘환경을 사용하면 대부분의 컴파일 오류는 찾을 수 있다.

  • Runtime Error
    • 실행 중인 프로그램이 의도하지 않은 동작을 하거나 프로그램이 중지되는 오류이다.
    • 실행 오류는 비정상 종료가 되는 경우 시스템의 심각한 장애를 발생할 수 있다.

예외 클래스

  • Throwable class : 모든 예외처리 클래스의 조상이 되는 클래스로 Throwable 타입과 이 클래스를 상속받은 서브 타입만이 JVM이나 throw키워드에 의해 던져질 수 있다.

  • Error class : 동적 메모리가 없는 경우, 스택 메모리의 오버플로우 등 가상 머신에서 발생하는 프로그래머가 처리할 수 없는 오류이다.

  • Exception class : 읽으려는 파일이 존재하지 않거나 네트워크나 DB연결이 안되는 경우 등의 프로그램에서 제어할 수 있는 오류이며 모든 예외에 대한 catch가 가능하다.

자바는 안전성이 중요한 언어로 대부분의 프로그램에서 발생하는 오류에 대해서 문법적으로 예외 처리를 해줘야한다.


Exception Class

  • 모든 예외 클래스의 최상위 class는 Exception class이며 다음과 같이 Exception class에는 수많은 예외상황을 처리하기 위한 class들이 존재한다.

  • 대표적인 예외

    • Arithmetic Exception :정수를 0 으로 나눈 경우 발생
    • NullPointerException : 초기화 되지 않은 Object를 사용하는 경우
    • ArrayIndexOutOfBoundsException :배열의 크기를 넘어선 위치를 참조하려는 경우
    • FileNotFoundException :참조하는 파일이 지정된 위치에 존재하지 않는 경우
    • ClassNotFoundException : 클래스가 로드되지 않은 경우
    • InterruptedException :Thread.sleep(), join(). Object의 wait()로 non-runnable 상태인 thread를 Runnable하게 만들 수 있도록 사용할 수 있음

예외 처리하기

try-catch문

  • try 블록에 예외가 발생할 가능성이 있는 코드를 작성하고 try블록에서 예외가 발생하면 catch 블록이 수행된다.
	try {
		예외가 발생할 수 있는 코드를 입력
	}catch(처리할 예외 타입 e) {
		try블록 안에서 예외가 발생했을 때 예외를 처리하는 부분	
	}

👨🏻‍💻 Example Code

public class ArrayIndexExceptionTest {
	public static void main(String[] args) {
		int[] arr = {1,2,3,4,5};
		
		try { // Error가 발생할 수 있는 코드를 입력
			for(int i=0; i<=5; i++) {
				System.out.println(arr[i]);
			}
		}catch (ArrayIndexOutOfBoundsException e) {
			// ArrayIndexOutOfBoundsException :배열의 크기를 넘어선 위치를 참조하려는 경우 발생
			// 해당 exception이 발생하면 e라는 변수로 넘어온다~
			System.out.println(e.toString());
			// Result: java.lang.ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 5
		}
	}
}

try-catch-finally문

  • finally블럭은 파일이나 네트워크를 닫는 등의 리소스 해제를 구현하는 곳이다.

  • finally는 try블록이 수행되는 경우 무조건 수행되게 되며 catch문에서 return이 되더라도 finally문은 수행된다.

  • 여러개의 예외 블럭이 있는 경우 각각의 블럭에서 리소스를 해제하지 않고 finally블록에서 해제하도록 구현한다.

	try {
		예외가 발생할 수 있는 코드를 입력
	}catch(처리할 예외 타입 e) {
		try블록 안에서 예외가 발생했을 때 예외를 처리하는 부분	
	}finally {
    		리소스를 해제하는 코드를 구현
    }

👨🏻‍💻 Example Code

Finally를 사용하지 않는 경우 아래의 코드와 같이 블럭별로 try-catch를 해야한다.

		try {
			fis = new FileInputStream("a.txt");
			
			try {
				fis.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			
			
			try {
				fis.close();
			} catch (IOException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
		}

위의 코드를 finally문을 사용하면 catch문들 아래에서 file의 close에 대한 예외상황을 더 간결하게 처리할 수 있다.

	try {
			fis = new FileInputStream("a.txt");
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally { // try구문이 불리면 finally는 무조건 불린다.
			if(fis != null) {
				try {
					fis.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			System.out.println("finally");			
		}

try-with-resource문

  • try{}내부에서 리소스를 사용하는 경우 close()를 하지 않아도 try{}블록에서 열린 리소스는 정상적인 경우와 예외가 발생한 경우 모두 자동으로 파일이나 네트워크가 해제된다.

  • java7부터 제공된 구문이다.

		try (FileInputStream fis = new FileInputStream("a.txt")){
			// try내부 괄호내에서 위와 같이 파일 선언을 하면 자동으로 close가 된다.
			System.out.println("read");
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} 
  • FileInputStream과 같이 해당되는 리소스 클래스가 AutoClosable 인터페이스가 구현되어 있어야 사용 가능하다. 그렇지 않은 경우 직접 인터페이스를 구현해야 한다.

  • java9부터는 리소스를 외부에서 선언하고 try(obj)와 같이 괄호 안에 변수만 써서 사용할 수 있다.

👨🏻‍💻 Example Code

AutoCloseableObj.java

public class AutoCloseableObj implements AutoCloseable {
	
	// AutoCloasble을 implement하면 close를 overriding해야한다.
	@Override
	public void close() throws Exception {
		// TODO Auto-generated method stub
		System.out.println("closing...");
	}
	
}

AutoCloseableObjTest.java

public class AutoCloseTest {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		AutoCloseableObj obj = new AutoCloseableObj();
		
		try(obj) {
			throw new Exception();
		}catch(Exception e) {
			System.out.println("Exception");
		}
		System.out.println("end");
	}

}

위의 코드를 실행할 경우
closing...
Exception
end
다음과 같은 결과가 나온다. 결과에서 end가 나온 것을 통해 Finally없이 ojb가 auto close가 되었다는 것을 알 수 있다.


예외 미루기

  • 예외 처리는 예외가 발생하는 문장에서 try-catch 블록으로 처리하는 방법과 이를 사용하는 부분에서 처리하는 방법 두 가지가 있다.
  • 예외 처리 미루기는 throws를 이용하여 예외가 발생할 수 있는 부분을 사용하는 문장에서 예외를 처리할 수 있게 한다.

👨🏻‍💻 Example Code

import java.io.FileInputStream;
import java.io.FileNotFoundException;

public class ThrowException {
	// Class 클래스를 사용
	public Class loadClass(String fileName, String className) throws ClassNotFoundException, FileNotFoundException {
		FileInputStream fis = new FileInputStream(fileName);
		
		// throws를 통해 코드를 실제로 사용하는 곳에서 예외 처리를 하도록 미루었다.
		Class c = Class.forName(className);
		return c;
	}
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		ThrowException test = new ThrowException();
		
		try {
			test.loadClass("a.txt", "abc");
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			System.out.println(e);
			} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			System.out.println(e);
		}
		System.out.println("end");
	}

}



Reference

profile
블로그 이전했습니다. -> https://seongwon.dev/

0개의 댓글