1) 컴파일 에러 :
- 컴파일 시 발생 에러 (소스코드 오타, 잘못된 구문, 자료형 체크)
- 아직 RUN 안됐을 때 발생
2) 런타임 에러 :
- 컴파일 잘 되었다고 프로그램 실행 시에도 에러 발생하지 x 아니다 / 프로그램 실행 도중에 발생하는 것!
- RUN 된 후 발생
자바는 실행 시 발생가능한 프로그램 오류를 예외
와 에러
로 구분
1) 에러 : 발생하면 복구 불가능한 심각 오류
2) 예외 : 발생해도 수습 가능한 덜 심각한 것
에러 발생 시 프로그램의 비정상적 종료 막을 길 존재 x
예외는 프로그래머가 미리 적절 코드 입력 -> 비정상적 종료 방지 가능
예외처리 : 프로그램 실행 시 발생 가능한 예기치 못한 예외 발생 대비 코드 작성
정상적 실행상태 유지 가능하게 하는 것
원래 예외가 발생하면 비정상적으로 프로그램이 종료되고 만다.
따라서 해당 예외 발생 -> catch해서 적절한 대응, 즉 처리를 해줘야 한다.
하나의 try 블럭 다음에 여러 종류의 예외 처리 가능하도록 하나 이상의 catch 블럭 오는 것 가능,
class ExceptionEx1 {
public static void main(String[] args)
{
try {
try { } catch (Exception e) { }
} catch (Exception e) {
try { } catch (Exception e) { } // 에러. 변수 e가 중복 선언되었다.
} // try-catch의 끝
try {
} catch (Exception e) {
} // try-catch의 끝
} // main메서드의 끝
}
class ExceptionEx4 {
public static void main(String args[]) {
System.out.println(1);
System.out.println(2);
try {
System.out.println(3);
System.out.println(4);
} catch (Exception e) {
System.out.println(5); // 실행 X
} //try catch 끝
System.out.println(6);
} // main메서드의 끝
}
try 블럭에서 예외가 발생하지 않는 경우엔 catch 블럭 거치지 않고, try catch 문 빠져나가서 수행 계속 진행
class ExceptionEx5 {
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) {
System.out.println(5);
} // try-catch의 끝
System.out.println(6);
} // main메서드의 끝
}
try 0/0 에서 exception이 발생하면 try 의 남은 것들 수행하지 않고 바로 catch문으로 가서 ,지금 일어난 exception에 해당하는 , 혹은 지금 일어난 exception이 포함될 수 있는 exception이 있는지 검사 진행
FLOW
1) 예외 발생한다면 해당 예외 클래스의 인스턴스가 만들어진다
(EX : ArithmeticException 발생 시, 얘의 인스턴스가 생성)
2) 예외 발생 문장이 try 블럭에 포함된다면 이 예외 처리 가능한 catch 블럭 있는지 찾게 됨
3) 찾으면서 catch 블럭 안에 있는참조변수의 종류
&생성된 예외클래스 인스턴스
를 instance of 연산자를 이용해서 검사 진행
이때 모든 예외클래스는 Exception 클래스의 자손
catch() 블럭에서 Exception 클래스 타입의 참조변수 선언 시 , 어떤 예외가 다 발생해도 catch가 잡아준다 (모든 인스턴스는 instanceof(Exception) 이 true가 되므로)
catch 에서 예외 발생 시 참조변수를 통해 인스턴스에 접근 가능
catch (AtirhmeticException ae){
ae.printStackTrace(); #ae를 통해 AtirhmeticException 인스턴스 접근 가능
}
printStackTrace
: 예외 발생 당시 호출 스택에 있던 메서드 정보와 예외 메시지 화면에 출력 가능getMessage
: 발생 예외클래스의 인스턴스에 저장된 메시지 읽기 가능
(+) 멀티 catch 블럭 (교재 423)
try{
}catch(예외1 e1){
예외1 처리 로직
}catch(예외2 e2){
예외2 처리 로직
}catch(예외3 e3){
예외3 처리 로직
}
출처: https://dololak.tistory.com/61 [코끼리를 냉장고에 넣는 방법:티스토리]
=> 멀티 캐치 블럭을 사용한다면
try{
}catch(예외1 | 예외2 | 예외3 e){
공통 예외로직 ex)e.printStackTrace();
}
출처: https://dololak.tistory.com/61 [코끼리를 냉장고에 넣는 방법:티스토리]
로 간소화 시키기 가능
- 연산자 new를 이용해 발생시키려는 예외 클래스 객체 만들기
Exception e = new Exception("고의 발생")
- throw 이용해 예외 발생시키기
throw e
class ExceptionEx10 {
public static void main(String[] args) {
throw new Exception(); // Exception 고의 발생
}
}
checked
예외라고 불림 class ExceptionEx11 {
public static void main(String[] args) {
throw new RuntimeException(); // RuntimeException 고의 발생
}
}
unchecked
예외 라고 불림 static void method1() throws Exception1, Exception2, Exception3 {
//메서드 내용
}
메서드 내에서 발생할 가능성이 있는 예외를 메서드 선언부에 예외 선언하면
: 메서드 사용하려는 사람이 이 메서드 사용 위해선 어떤 예외 처리 필요한지 알기 가능
자바에서는 메서드 작성 시 메서드 내에서 발생 가능한 예외를 메서드 선언부에 명시해서 이 메서드 사용하는 쪽에서는 이에 대한 처리 강요함
=> 이전에 메서드에 예외 선언 하지 않을 때는, 경험 많은 프로그래머가 아니고서는 어떤 상황에 어떤 종류의 예외 발생 가능한지 예측 힘듦 & 대비 어려웠음
메서드에 선언되는 예외는 주로 unchecked 가 아닌, 반드시 처리해주어야만 하는 예외들뿐이다.
public class ExceptionTest14 {
static void method1() throws Exception {
// method1을 호출한 메소드로 예외 처리 넘김
method2(); // 2)
}
static void method2() throws Exception {
// method2를 호출한 메소드로 예외 처리 넘김
throw new Exception(); // Exception 발생 // 1)
}
public static void main(String[] args) throws Exception {
method1(); //3)
}
}
- 예외를 전달받은 메서드가 자신을 호출한 메서드에게 예외 전달 가능, 이런 식으로 계속 호출 스택에 있는 메서드들 따라다가 최후 main 에서도 처리 안되면 프로그램 종료
예외가 발생한 메서드에서 예외처리 하지 않고 자신 호출한 메서드에게 예외를 토스할 수 있음, 그러나 이것으로 예외처리 된 것이 아니라 반드시 어느 한 지점에서는 예외를 처리해주는 과정이 피필요한 것이지.
class ExceptionEx13 {
public static void main(String[] args) {
method1();
// 같은 클래스내의 static멤버이므로 객체생성없이 직접 호출가능.
} // main메서드의 끝
static void method1() {
try {
throw new Exception();
} catch (Exception e) {
System.out.println("method1메서드에서 예외가 처리되었습니다.");
e.printStackTrace();
}
} // method1의 끝
}
try {
// Exception이 발생할 가능성이
있는 문장들을 넣는다.
} catch (Exception1 e1) {
// Exception1 이 발생했을 경우,
이를 처리하기 위한 문장을 넣는다.
} catch (Exception2 e2) {
// Exception2 이 발생했을 경우,
이를 처리하기 위한 문장을 넣는다.
}
.....................
catch (ExceptionN eN) {
// ExceptionN 이 발생했을 경우,
이를 처리하기 위한 문장을 넣는다.
}
finally {
무조건 수행되는 부분
}
class FinallyTest3 {
public static void main(String args[]) {
// method1()은 static메서드이므로 인스턴스 생성없이 직접 호출이 가능하다.
FinallyTest3.method1();
System.out.println("method1()의 수행을 마치고 main메서드로 돌아왔습니다.");
} // main메서드의 끝
static void method1() {
try {
System.out.println("method1()이 호출되었습니다.");
return; // 현재 실행 중인 메서드를 종료한다.
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println("method1()의 finally블럭이 실행되었습니다.");
}
} // method1메서드의 끝
}
class NewExceptionTest {
public static void main(String args[]) {
try {
startInstall(); // 프로그램 설치에 필요한 준비를 한다.
copyFiles(); // 파일들을 복사한다.
} catch (SpaceException e) {
System.out.println("에러 메시지 : " + e.getMessage());
e.printStackTrace();
System.out.println("공간을 확보한 후에 다시 설치하시기 바랍니다.");
} catch (MemoryException me) {
System.out.println("에러 메시지 : " + me.getMessage());
me.printStackTrace();
System.gc(); // Garbage Collection을 수행하여 메모리를 늘려준다.
System.out.println("다시 설치를 시도하세요.");
} finally {
deleteTempFiles(); // 프로그램 설치에 사용된 임시파일들을 삭제한다.
} // try의 끝
} // main의 끝
static void startInstall() throws SpaceException, MemoryException {
if(!enoughSpace()) // 충분한 설치 공간이 없으면...
throw new SpaceException("설치할 공간이 부족합니다.");
if (!enoughMemory()) // 충분한 메모리가 없으면...
throw new MemoryException("메모리가 부족합니다.");
} // startInstall메서드의 끝
static void copyFiles() { /* 파일들을 복사하는 코드를 적는다. */ }
static void deleteTempFiles() { /* 임시파일들을 삭제하는 코드를 적는다.*/}
static boolean enoughSpace() {
// 설치하는데 필요한 공간이 있는지 확인하는 코드를 적는다.
return false;
}
static boolean enoughMemory() {
// 설치하는데 필요한 메모리공간이 있는지 확인하는 코드를 적는다.
return true;
}
} // ExceptionTest클래스의 끝
class SpaceException extends Exception {
SpaceException(String msg) {
super(msg);
}
}
class MemoryException extends Exception {
MemoryException(String msg) {
super(msg);
}
}
Throwable initCause (Throwable cause) : 지정 예외를 원인 예외로 등록
Throwable getCause() : 원인 예외를 반환
(ex)
static void install() throws InstallException {
try {
startInstall(); // 프로그램 설치에 필요한 준비를 한다.
copyFiles(); // 파일들을 복사한다.
} catch (SpaceException e) {
InstallException ie = new InstallException("설치중 예외발생");
ie.initCause(e);
throw ie;
} catch (MemoryException me) {
InstallException ie = new InstallException("설치중 예외발생");
ie.initCause(me);
throw ie;
} finally {
deleteTempFiles(); // 프로그램 설치에 사용된 임시파일들을 삭제한다.
} // try의 끝
}
이렇게 두 예외를 Install예외의 조상으로 처리 하지 않았더라면, install() 메소드를 실행하면서 발생할 수 있는 예외는 두가지이므로
나중에 main에서 install 메소드 실행할 때 각각 예외에 대해서 다 처리해줘야 함,
반면 위와 같이 처리를 해줌으로써 main에서 install을 try 할 때 installexcpetion 하나에 대해서만 catch를 작성해주면 ok
public static void main(String args[]) {
try {
install();
} catch(InstallException e) {
e.printStackTrace();
} catch(Exception e) {
e.printStackTrace();
}
} // main의 끝
< total 코드>
class ChainedExceptionEx {
public static void main(String args[]) {
try {
install();
} catch(InstallException e) {
e.printStackTrace();
} catch(Exception e) {
e.printStackTrace();
}
} // main의 끝
static void install() throws InstallException {
try {
startInstall(); // 프로그램 설치에 필요한 준비를 한다.
copyFiles(); // 파일들을 복사한다.
} catch (SpaceException e) {
InstallException ie = new InstallException("설치중 예외발생");
ie.initCause(e);
throw ie;
} catch (MemoryException me) {
InstallException ie = new InstallException("설치중 예외발생");
ie.initCause(me);
throw ie;
} finally {
deleteTempFiles(); // 프로그램 설치에 사용된 임시파일들을 삭제한다.
} // try의 끝
}
static void startInstall() throws SpaceException, MemoryException {
if(!enoughSpace()) { // 충분한 설치 공간이 없으면...
throw new SpaceException("설치할 공간이 부족합니다.");
}
if (!enoughMemory()) { // 충분한 메모리가 없으면...
throw new MemoryException("메모리가 부족합니다.");
// throw new RuntimeException(new MemoryException("메모리가 부족합니다."));
}
} // startInstall메서드의 끝
static void copyFiles() { /* 파일들을 복사하는 코드를 적는다. */ }
static void deleteTempFiles() { /* 임시파일들을 삭제하는 코드를 적는다.*/}
static boolean enoughSpace() {
// 설치하는데 필요한 공간이 있는지 확인하는 코드를 적는다.
return false;
}
static boolean enoughMemory() {
// 설치하는데 필요한 메모리공간이 있는지 확인하는 코드를 적는다.
return true;
}
} // ExceptionTest클래스의 끝
class InstallException extends Exception {
InstallException(String msg) {
super(msg);
}
}
class SpaceException extends Exception {
SpaceException(String msg) {
super(msg);
}
}
class MemoryException extends Exception {
MemoryException(String msg) {
super(msg);
}
}
코드 및 내용 출처 : 자바의 정석 교재 및 깃허브