- 컴파일 에러(compile-time error) : 컴파일 할 때 발생하는 에러
- 런타임 에러(runtime error) : 실행 할 때 발생하는 에러
- 논리적 에러(logical error) : 작성 의도와 다르게 동작(종료가 안됨)
자바의 런타임 에러
- 에러 : 심각한 오류
- 예외 : 미약한 오류
에러는 어쩔 수없지만, 예외는 비정상 종료를 막고 정상적인 실행상태를 유지하게 하자.
크게 신경쓰지 말라해서 넘어가기로함
Exception 클래스들
-사용자의 실수와 같은외적인 요인
에 의해 발생하는 예외
RuntimeException 클래스들
-프로그래머의 실수
로 발생하는 예외
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()
- 예외발생 당시의 호출스택(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블럭을 하나로 합친 것(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 ""
파일이름이 유효하지 않습니다. 다시 입력해 주시기 바랍니다.
예외 발생여부와 관계없이 수행되어야 하는 코드를 넣는다.
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 예외
컴파일러가 예외 처리 여부를 체크 안함(예외 처리 선택)
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("메모리가 부족스"); } --- Exception을 RuntimeException으로 바꾸려면 --- static void startInstall() throws SpaceException { if(!enoughtSpace()) throw new SpaceException("설치할 공간이 부족스"); if(!enoughtMemory()) throw new RuntimeException(new MemoryException("메모리가 부족스")); }