8장 예외처리

slee2·2021년 9월 9일
0

Java의 정석

목록 보기
16/28
post-thumbnail

프로그램 오류

  • 컴파일 에러(compile-time error) : 컴파일 할 때 발생하는 에러
  • 런타임 에러(runtime error) : 실행 할 때 발생하는 에러
  • 논리적 에러(logical error) : 작성 의도와 다르게 동작(종료가 안됨)

    자바의 런타임 에러

    • 에러 : 심각한 오류
    • 예외 : 미약한 오류

예외처리의 정의와 목적

에러는 어쩔 수없지만, 예외는 비정상 종료를 막고 정상적인 실행상태를 유지하게 하자.

예외 클래스의 계층 구조

크게 신경쓰지 말라해서 넘어가기로함

Exception 클래스들
-사용자의 실수와 같은 외적인 요인에 의해 발생하는 예외

RuntimeException 클래스들
-프로그래머의 실수로 발생하는 예외

예외 처리하기

try-catch문

try {	// 중괄호 생략불가
	// 예외가 발생할 가능성이 있는 문장들을 넣는다.
} catch (Exception1 e1) {
	// Exception1이 발생했을때
} catch (Exception2 e2) {
	// Exception2이 발생했을때
} catch (ExceptionN eN) {
	// ExceptionN이 발생했을때
}
class	Ex {
	public static void	main(String args[]) {
   		System.out.println(1);
   		try {
  		System.out.println(0/0);
		System.out.println(2);
 		} catch (ArithmeticException ae) {
  			System.out.println(3);
		} catch (Exception e) {
  			System.println("Exception");
   		}
   		System.out.println(4);
   	}
}
결과
1
3
4

Exception이 선언된 catch블럭은 모든 예외 처리(마지막 catch 블럭)

printStackTrace()와 getMessage()

printStackTrace()

  • 예외발생 당시의 호출스택(Call Stack)에 있었던 메서드의 정보와 예외 메시지를 화면에 출력한다.

getMessage()

  • 발생한 예외클래스의 인스턴스에 저장된 메시지를 얻을 수 있다.
try {
	System.out.println(3);
   	System.out.println(0/0)	// 예외발생!!
  	System.out.println(4)	// 실행되지 않는다.
} catch (ArithmeticException ae) {
	ae.printStackTrace();
   	System.out.println("예외메시지 : " + ae.getMessage());
}

----- 결과 -----
3
java.lang.ArithmeticException: /by zero at Ex.main(Ex.java:8)
예외메시지 : /by zero

멀티 catch블럭

  • 내용이 같은 catch블럭을 하나로 합친 것(JDK1.7부터)
------- 위의 내용을 -------
try {
	...
} catch (ExceptionA e) {
	e.printStackTrace();
} catch (ExceptionB e2) {
	e2.printStackTrace();
}

---- 멀티 catch블럭 사용 ----
try {
	...
} catch (ExceptionA | ExceptionB e) {
	e.methodA();	// 에러. 공통멤버만 사용가능
	e.printStackTrace();	// OK. 공통멤버

   	if(e instaceof ExceptionA) {
   		ExceptionA	e1 = (ExceptionA)e;
   		e1.methodA();	// OK.
   	} else {	// 근데 이렇게 쓸바에는 멀티안씀
  		...
}

메서드에 예외 선언하기

예외를 처리하는 방법

try-catch문, 예외 선언하기

메서드가 호출시 발생가능한 예외를 호출하는 쪽에 알리는 것

void	method() throws Exception {
	//	메서드는 throws
}

class	Ex {
	public static void main(String[] args) throws Exception {
   		method1();
   	}
    
   	static void method1() throws Exception {
   		method2();
   	}
    
   	static void method2() throws Exception {
   		throw new Exception();
   	}
}
--- 결과 ---
Exception in thread "main" java.lang.Exception
	at Ex.method2(Ex.java:11)
   	at Ex.method1(Ex.java:7)
   	at Ex.main(Ex.java:3)

예제

import java.io.*;

class	Ex {
	public static void main(String[] args) {
   		try {
   			File	f = createFile(args[0]);
   			System.out.println(f.getName()+"파일이 성공적으로 생성되었습니다.");
   		} catch (Exception e) {
			System.out.println(e.getMessage()+"다시 입력해 주시기 바랍니다.");
  		}
   	}
}

static File createFile(String fileName) throws Exception {
	if (fileNmae==Null || fileNmae.equals(""))
   		throw new Exception("파일 이름이 유효하지 않습니다.");
   	File	f = new File(fileName);
 	f.createNewFile();
   	return f;
}

---- 결과 ----
c:\jdk1.8\work\ch>java Ex test2.txt
test2.txt파일이 성공적으로 생성되었습니다.

c:\jdk1.8\work\ch>java Ex ""
파일이름이 유효하지 않습니다. 다시 입력해 주시기 바랍니다.

finally 블럭

예외 발생여부와 관계없이 수행되어야 하는 코드를 넣는다.

try {
	startInstall();
   	copyFiles();
   	deleteTempFiles();
} catch (Exception e) {
	e.printStackTrace();
   	deleteTempFiles();
}

---- add finally ----
try {
	startInstall();
   	copyFiles();
} catch (Exception e) {
	e.printStackTrace();
} finally {	// 예외의 발생여부에 관계없이 항상 수행되어야 하는 문장들을 넣는다.
   	deleteTempFiles();
}

예외 발생시키기

  • 연산자 new를 이용해서 발생시키려는 예외 클래스의 객체를 만든 다음
    Exception e = new Exception("고의로 발생시킴");
  • 키워드 throw를 이용해서 예외를 발생시킨다.
    throw e;
try {
	Exception	e = new Exception("고의로 발생시킴");
   	throw	e;
   //	throw new Exception("고의로 발생시킴");

} catch (Exception e) {
	System.out.println("에러 메시지 : " + e.getMessage());
   	e.printStackTrace();
}
System.out.println("프로그램이 정상 종료되었음");

--- 결과 ---
에러 메시지 : 고의로 발생시킴
java.lang.Exception: 고의로 발생시킴
	at Ex.main(Ex.java:4)
프로그램이 정상 종료되었음

checked 예외, unchecked 예외

checked 예외

컴파일러가 예외 처리 여부를 체크(예외 처리 필수)

unchecked 예외

컴파일러가 예외 처리 여부를 체크 안함(예외 처리 선택)

throw	new Exception();	// 컴파일 에러

throw	new RuntimeException();	// 런타임 에러

사용자 정의 예외 만들기

  • 우리가 직접 예외 클래스를 정의할 수 있다.
  • 조상은 Exception과 RuntimeException중에서 선택
class	MyException extends Exception {
	MyException(String msg) {	// 문자열을 매개변수로 받는 생성자
   		super(msg);	// 조상인 Exception클래스의 생성자를 호출한다.
   	}
}

Exception은 필수처리 예외라서 try-catch를 꼭 써야하지만, RuntimeException은 선택이기 때문에 꼭 필요한 경우가 아니라면 선택처리가 가능한 RuntimeException을 조상으로 하는게 좋다.

예제

class	MyException extends Exception {
	private final int ERR_CODE;

	MyException(String msg, int errCode) {
   		super(msg);
   		ERR_CODE = errCode;
   	}
   	MyException(String msg) {
   		this(msg, 100);
   	}
   	public int getErrCode() {
   		return ERR_CODE;
   	}
}

예외 되던지기

  • 예외를 처리한 후에 다시 예외를 발생시킨 것
  • 호출한 메서드와 호출된 메서드 양쪽 모두에서 예외처리하는 것
try {
} catch (Exception e) {
	System.out.println("처리");
   	throw	e;
}

예외를 안쪽 메서드가 처리를 하고 되던지면 메인에서도 처리를 하면서 서로 티키타카

연결된 예외

  • 한 예외가 다른 예외를 발생시킬 수 있다.
  • 예외 A가 예외 B를 발생시키면, A는 B의 원인 예외
Trowable initCause(Throwable cause)	지정한 예외를 원인 예외로 등록
Trowable getCause()			원인 예외를 반환
예제1
public class Throwable implements Serializable {
	...
   	private Throwable cause = this;	// 객체 자신을 원인 예외로 등록
   	...
   	public sysnchronized Throwable initCause(Throwable cause) {
   		this.cause = cause;	// cause를 원인 예외로 등록
       		return this;
   	}
}
예제2
void	install() throws InstallException {
	try {
   		startInstall();	// SpaceException 발생
   		copyFiles();
   	} catch (SpaceException e) {
   		InstallException ie = new InstallException("설치중 예외발생");	// 예외 생성
  		ie.initCause(e);	// InstallException의 원인 예외를 SpaceException으로 지정
  		throw ie;		// InstallException을 발생시킨다.
   	} catch (MemoryException me) {
  		...
}

와 이거 어렵네 ㅋㅋ;

쓰는 이유

이유1 - 여러 예외를 하나로 묶어서 다루기 위해서
try {
	install();
} catch (SpaceException e) {
	e.printStackTrace();
} catch (MemoryException e) {
	e.printStackTrace();
} catch (Exception e) {
	e.printStackTrace();
}
----- 연결된 예외 -----
try {
	install();
} catch (InstallException e) {
	e.printStackTrace();
} catch (Exception e) {
	e.printStackTrace();
}
이유2 - checked예외를 unchecked예외로 변경하려 할 때
static void startInstall() throws SpaceException, MemoryException {
	if(!enoughtSpace())
   		throw new SpaceException("설치할 공간이 부족스");
 
   	if(!enoughtMemory())
  		throw new MemoryException("메모리가 부족스");
}

--- ExceptionRuntimeException으로 바꾸려면 ---

static void startInstall() throws SpaceException {
	if(!enoughtSpace())
   		throw new SpaceException("설치할 공간이 부족스");
 
   	if(!enoughtMemory())
  		throw new RuntimeException(new MemoryException("메모리가 부족스"));
}

0개의 댓글