printStackTrace()getMessage()

 

예외가 발생하면 예외객체가 생성되고, 예외객체에 예외에 대한 정보가 들어있다.

예외에 있는 메소드를 통해서 그 정보를 알아볼 수 있다.

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

getMessage() : 발생한 예외클래스의 인스턴스에 저장된 메시지를 얻을 수 있다.

 

ex)

public class Ex8_5 {

	public static void main(String[] args) {
		System.out.println(1);
		System.out.println(2);
		
		try {
			System.out.println(3);
			System.out.println(0/0);
			System.out.println(4);
			
		} catch (ArithmeticException ae) {
			ae.printStackTrace();
			System.out.println("예외메세지 : " + ae.getMessage());
		}
		
		System.out.println(6);
	}

}

 

멀티 catch블럭

- 내용이 같은 catch블럭을 하나로 합친 것

try {
	...
} catch (ExceptionA e) {
	e.printStackTrace();
} catch (ExceptionB e2) {
	e2.printStackTrace();
}

내용 동일하므로 중복 제거함

try {
	...
} catch (ExceptionA | ExceptionB e) {
	e.printStackTrace();
}

부모-자손 관계인 Exception들은 멀티 catch블럭으로 사용 불가.

멀티 catch블럭으로는 공통멤버만 사용 가능하다.

 

 

예외 발생시키기

1. 연산자 new를 이용해서 발생시키려는 예외 클래스의 객체를 만든 다음

Exception e = new Exception(“고의로 발생시켰음”);

 

2. 키워드 throw를 이용해서 예외를 발생시킨다.

throw e;

ex)

public class Ex8_6 {

	public static void main(String[] args) {
		try {
			Exception e = new Exception("고의로 발생시켰음.");
			throw e;	// 예외를 발생시킴
			// throw new Exception("고의로 발생시켰음."); 위의 두 줄을 한 줄로 줄여쓸 수 있다.
			
		} catch (Exception e) {
			System.out.println("에러 메세지 : " + e.getMessage());
			e.printStackTrace();
		}
		System.out.println("프로그램이 정상 종료되었음.");
	}

}

 

 

checked 예외, unchecked 예외

- checked 예외 : 컴파일러가 예외 처리 여부를 체크(예외 처리 필수) / Exception과 그 자손이 checked 예외에 해당

- unchecked 예외 : 컴파일러가 예외 처리 여부를 체크 안함(예외 처리 선택) / RuntimeException과 자손이 unchecked 예외에 해당

 

 

ex) checked 예외

public class Ex8_7 {

	public static void main(String[] args) {
		throw new Exception(); // Exception을 고의로 발생시킨다.

	}

}

결과 (컴파일 에러)

 

Exception in thread "main" java.lang.Error: Unresolved compilation problem:

Unhandled exception type Exception

 

at Ex8_7.main(Ex8_7.java:5)

 

 

ex) unchecked 예외

public class Ex8_8 {

	public static void main(String[] args) {
		throw new RuntimeException(); // 컴파일 OK

	}

}

결과 (컴파일은 됨)

 

Exception in thread "main" java.lang.RuntimeException

at Ex8_8.main(Ex8_8.java:5)

 

메소드에 예외 선언하기

- 예외를 처리하는 방법 : try-catch예외 선언하기(예외 떠넘기기=알리기)

은폐(덮기) - catch블럭을 쓰는 것

 

- 메소드에 예외 선언하기란?

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

 

void method() throws Exception1, Exception2, ... ExceptionN { // (Exception1, Exception2, ... ExceptionN이 발생 가능함을 알림)

// 메소드의 내용

}	// method()에서 Exception과 그 자손 예외 발생 가능
void method throws Exception { // 모든 종류의 예외가 발생 가능함을 알림

// 메소드의 내용

}

 

(오버라이딩의 조건 1. 선언부가 같아야 함 2. 접근 제어자를 조상 클래스의 메소드보다 좁은 범위로 변경할 수 없다. 3. 예외는 조상 클래스의 메소드보다 많이 선언할 수 없다)

 

 

ex)

 

public class Ex8_9 {
	static void method1() throws Exception {
		method2();
	}
	
	static void method2() throws Exception {
		throw new Exception();
	}
	
	public static void main(String[] args) throws Exception { // 예외를 결국 처리하지 못하고 JVM에 떠넘기게됨
		method1();

	}

}

 

 

ex) try-catch문을 메소드를 호출한 쪽에서 작성하는 경우

import java.io.File;

public class Ex8_10 {
	static File createFile(String fileName) throws Exception {
		if (fileName==null || fileName.equals(""))
			throw new Exception("파일이름이 유효하지 않습니다.");	// 예외 떠넘기기
		File f = new File(fileName);	// File클래스의 객체를 만든다.
		// File객체의 createNewFile메소드를 이용해서 실제 파일을 생성한다.
		f.createNewFile();
		return f;
	}
	
	public static void main(String[] args) {
		try {
			File f = createFile("test2.txt");
			System.out.println( f.getName()+"파일이 성공적으로 생성되었습니다.");
		} catch (Exception e) {	// 예외 처리하기
			System.out.println(e.getMessage()+" 다시 입력해 주시기 바랍니다.");
		}
		

	}

}

 

 

ex) try-catch문을 메소드 정의한 쪽에서 작성하는 경우

import java.io.File;
import java.io.IOException;

public class Ex8_10_2 {
	static File createFile(String fileName) {
		try {
			if (fileName==null || fileName.equals(""))
				throw new Exception("파일이름이 유효하지 않습니다.");
		} catch (Exception e) {
			fileName = "제목없음.txt";
		}
		
		File f = new File(fileName);	// File클래스의 객체를 만든다.
		// File객체의 createNewFile메소드를 이용해서 실제 파일을 생성한다.
		try {
			f.createNewFile();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return f;
	}
	
	public static void main(String[] args) {
			File f = createFile("");
			System.out.println( f.getName()+"파일이 성공적으로 생성되었습니다.");
		
	}

}

createNewFile메소드가 예외를 발생시킬 수 있기 때문에 try-catch블럭으로 감쌌다 

 

 

finally 블록

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

try {
	// 예외가 발생할 가능성이 있는 문장들을 넣는다.
} catch (Exception1 e1) {

} finally {
	// 예외의 발생여부에 관계없이 항상 수행되어야 하는 문장들을 넣는다.
	// finally블럭은 try-catch문의 맨 마지막에 위치해야 한다.
}

참고 try 블록 안에 return문이 있어서 try블럭을 벗어날 때도 finally블럭이 실행된다.

 

사용자 정의 예외 만들기

- 우리가 직접 예외 클래스를 정의할 수 있다.

- 조상은 Exception(사용자가 발생시키는 예외)RuntimeException(프로그래머의 실수로 발생시키는 예외) 중에서 선택한다.

 
class MyException extends Exception {
	MyException(String msg) { // 문자열을 매개변수로 받는 생성자
		super(msg); // 조상인 Exception클래스의 생성자를 호출한다.
	}
}

 

예외 되던지기(Exception re-throwing)

- 예외를 처리한 후에 다시 예외를 발생시키는 것

- 호출한 메소드와 호출된 메소드 양쪽 모두에서 예외처리하는 것

-> 분담처리(?)

 

ex)

public class Ex8_12 {
	static void method1() throws Exception {
		try {
			throw new Exception();
		} catch (Exception e) {
			System.out.println("method1 메소드에서 예외가 처리되었습니다.");
			throw e;	// 다시 예외를 발생시킨다.
		}
	}
	public static void main(String[] args) {
		try {
			method1();
		} catch (Exception e) {
			System.out.println("main메소드에서 예외가 처리되었습니다.");
		}

	}

}

 

연결된 예외(chained exception)

- 한 예외가 다른 예외를 발생시킬 수 있다.

- 예외 A가 예외 B를 발생시키면, AB의 원인 예외(cause exception)

- 세부적인 예외를 포괄적인 예외로 감쌀 때 사용하거나 checked 예외를 unchecked 예외로 변경할 때 사용한다.

 

Throwable initCause(Throwable cause) 지정한 예외를 원인 예외로 등록

Throwable getCause() 원인 예외를 반환

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] 여러 예외를 하나로 묶어서 다루기 위해서

 

ex) 설치공간 부족 에러를 발생시켜서 InstallException으로 묶어서 처리하는 경우

public class Ex8_13 {
	
	public static void main (String[] args) {
		try {
			Ex8_13.install();
		} catch(InstallException e) {
			e.printStackTrace();
		} catch(Exception e) {
			e.printStackTrace();		
		}
	}
	
	static void install() throws InstallException {
		try {
			startInstall();		// 프로그램 설치에 필요한 준비를 한다.
			copyFiles();		// 파일들을 복사한다. 
		} catch (SpaceException2 e)	{
			InstallException ie = new InstallException("설치 중 예외발생");
			ie.initCause(e);
			throw ie;
		} catch (MemoryException2 me) {
			InstallException ie = new InstallException("설치 중 예외발생");
			ie.initCause(me);
			throw ie;
		} finally {
			deleteTempFiles();		// 프로그램 설치에 사용된 임시파일들을 삭제한다.
		} // try의 끝
	}

	static void startInstall() throws SpaceException2, MemoryException2 { 
		if(!enoughSpace()) { 		// 충분한 설치 공간이 없으면...
			throw new SpaceException2("설치할 공간이 부족합니다.");
		}

		if (!enoughMemory()) {	// 충분한 메모리가 없으면...
			throw new MemoryException2("메모리가 부족합니다.");
//			throw new RuntimeException(new MemoryException("메모리가 부족합니다."));
		}
	} // startInstall메서드의 끝

   static void copyFiles()       { /* 파일들을 복사하는 코드를 적는다.   */ }
   static void deleteTempFiles() { /* 임시파일들을 삭제하는 코드를 적는다.*/ }
   
   static boolean enoughSpace() {
		// 설치하는데 필요한 공간이 있는지 확인하는 코드를 적는다.
		return false;
   }
   static boolean enoughMemory() {
		// 설치하는데 필요한 메모리공간이 있는지 확인하는 코드를 적는다.
		return true;
   }

}

class InstallException extends Exception {
	InstallException(String msg) {
	   super(msg);	
   }
} 

class SpaceException2 extends Exception {
	SpaceException2(String msg) {
	   super(msg);	
   }
} 

class MemoryException2 extends Exception {
	MemoryException2(String msg) {
	   super(msg);	
   }

}

<메인 메소드의 흐름 요약>

static 메소드인 install 메소드를 호출함->install 메소드 안에서 startInstall 메소드를 호출함->if문에서 enoughSpace 메소드로 SpaceException2를 발생시킴-> InstallException 객체를 만들고 initCause 메소드를 이용해 SpaceException2를 원인 예외로 만든 후 ie를 발생시키고 finally 블럭을 수행함-> 메인메소드의 catch 블럭에서 InstallException을 받아서

printStackTrace메소드로 원인을 출력하게 됨.

 

 

[이유2] checked예외를 unchecked예외로 변경하려 할 때

static void startInstall() throws SpaceException {
	if(!enoughSpace())	// 충분한 설치 공간이 없으면...
		throw new SpaceException(“설치할 공간이 부족합니다.”);

	if(!enoughMemory())	// 충분한 메모리가 없으면...
		throw new RuntimeException(new MemoryException(“메모리가 부족합니다.”));
	}

-> MemoryException을 원인 예외로 등록하고 RuntimeException으로 나타나게 하여 불필요하게 checked예외를 사용하지 않을 수 있도록 바꿔주었음.

java가 만들어졌을 당시의 환경과 지금의 환경이 많이 다르기 때문에 checked Exceptionunchecked Exception 안에 집어넣어서 쓰는게 편할 경우가 있기 때문에 이렇게 하는 경우가 있다.

 

 


출처 - 유튜브 남궁성의 정석코딩 [자바의 정석 - 기초편] 

 

 

 

 

집중하자

정신차리자

할 때 제대로 하자

 

+ Recent posts