⦁ 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를 발생시키면, A는 B의 원인 예외(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 Exception을 unchecked Exception 안에 집어넣어서 쓰는게 편할 경우가 있기 때문에 이렇게 하는 경우가 있다.
출처 - 유튜브 남궁성의 정석코딩 [자바의 정석 - 기초편]
집중하자
정신차리자
할 때 제대로 하자
'Java > Java의 정석' 카테고리의 다른 글
220316 Java - Chapter 10. 날짜와 시간 & 형식화 (0) | 2022.03.17 |
---|---|
220315 Java - Chapter 9. java.lang패키지와 유용한 클래스 (0) | 2022.03.15 |
220312 Java - Chapter 8. 예외 처리 (0) | 2022.03.13 |
220310 Java - Chapter 7. 객체지향개념 II Part.3 (0) | 2022.03.11 |
220309 Java - Chapter 7. 객체지향개념 II Part.2 (0) | 2022.03.10 |