티스토리 뷰
728x90
서문
자바의 정석 기초편 챕터 8편을 기재합니다.
목적은 공부한 내용을 기록하는 것에 있기 때문에 완전한 문장이 아닐 수도 있습니다.
또한 모든 내용을 적은 것은 아닙니다.
- 참고 자료
자바의 정석 ( ch.8 )
프로그램 오류
컴파일 에러(Compile-Time Error) : 컴파일 할 때 발생하는 에러 ( 수정 전까지 프로그램 실행 자체가 불가)
- 컴파일러
- 구문체크
- 번역
- 최적화 (간단한 계산이나 컴파일, 실행시점에 동일한 처리들)
- 컴파일러
런타임 에러(Runtime Error) : 실행 할 때 발생하는 에러(프로그램이 종료됨)
- index out of bound, NullPoint 등등
논리적 에러(Logical Error) : 작성의도와 다르게 동작하는 에러(프로그램 종료는 되지 않음)
- 재고량이 음수가 나오면 안되는데 음수가 나와버리는 경우
Java의 런타임에러
- 에러(Error) : 프로그램 코드에 의해서 수습될 수 없는 심각한 오류,
- 예외(Exception) : 프로그램 코드에 의해서 수습될 수 있는 다소 미약한 오류, 처리 가능(프로그램 종료를 막을 수 있음)
예외처리의 정의와 목적
- 정의 : 프로그램 실행 시 발생할 수 있는 예외의 발생에 대비한 코드를 작성하는 것
- 목적 : 프로그램이 비정상적으로 종료되는 것을 방지하고 정상적인 실행상태를 유지하는 것
- Exception은 다시 RuntimeException과 그 외의 그룹으로 나눌 수 있음
- IOException : 입출력 에러
- ClassNotFoundException : 클래스를 찾을 수 없을 때
- ArithmeticException : 산술 에러, 5/0
- ClassCastException : 형변환 에러
- NullPointException: nullpoint 에러
- IndexOutOfBoundsException : index 범위를 벗어나는 에러
- ...
class ExceptionTest{
public static void main(String[] args){
system.out.println("에러!!"); // complie error
System.out.println(args[0]); // Runtime error, args가 없는데 사용하려고 해서
}
}
예외처리하기 try-catch문
try블럭 내에서 예외가 발생할 경우
- 발생한 예외와 일치하는 catch블럭이 있는지 확인
- 일치하는 catch블럭을 찾으면 그 catch문 내의 문장을 실행하고 전체 try-catch문을 빠져나가서 그 다음 문장을 계속해서 수행한다. 만일 일치하는 catch블럭을 찾지 못했을 때 예외는 처리되지 못한다.
- try블럭 내에서 예외가 발생하지 않는 경우
- catch블럭을 거치지 않고 전체 try-catch문을 빠져나가서 수행을 계속함
1. try-catch문의 기본적 구조
try{
// 예외가 발생할 가능성이 있는 문장을 넣음
} catch (Exception e1){
// Exception e1가 발생했을 경우 처리할 문장
} catch (Exception e2){
// Exception e2가 발생했을 경우 처리할 문장
} catch (Exception eN){
// Exception eN가 발생했을 경우 처리할 문장
}
-----------------------------------------
2. try-catch문의 예시 1
class Ex{
public static void main(String[] args){
System.out.println(1);
try{
System.out.println(2);
System.out.println(3);
} catch (Exception e){
System.out.println(4); // 예외
} // try-catch문 종료
System.out.println(5);
}
}
예외가 발생하지 않은 경우
> 1
> 2
> 3
> 5
예외가 발생한 경우
> 1
> 2
> 3
> 4
> 5
-----------------------------------------
3. try-catch문의 예시 2
class Ex2{
public static void main(String[] args){
System.out.println(1);
try{
System.out.println(0/0); // 예외발생
System.out.println(2);
} catch (Exception e){
System.out.println(3);
}
System.out.println(4);
}
}
> 1
> 3
> 4
-----------------------------------------
4. try-catch문의 예시 3
class Ex3{
public static void main(String[] args){
System.out.println(1);
System.out.println(2);
try{
System.out.println(3);
System.out.println(0/0); // error
System.out.println(4);
} catch(ArithmeticException e){
if (e instanceof ArithmeticException){
System.out.println("true");
}
System.out.println("ArithmeticException");
} catch(Exception e){ // 모든 Exception의 부모격이기 때문에 가장 마지막에 Exception을 사용함
System.out.println("Exception");
}
System.out.println(6);
}
}
> 1
> 2
> 3
> true
> ArithmeticException
> 6
printStackTrace()와 getMessage()
- printStackTrace() : 예외발생 당시의 호출스택(Call Stack)에 있었던 메서드의 정보와 예외 메시지를 화면에 출력
- getMessage() : 발생한 예외클래스의 인스턴스에 저장된 메시지를 얻음
1. printStackTrace()와 getMessage() 기본적 예시
try{
...
System.out.println(0/0);
...
} catch(ArithmeticException ae){ // ae는 참조변수, 해당하는 에러에 예외정보가 담겨 있는데 만약 catch()괄호 안에 일치하는 에러가 있을 때 참조하여 printStackTrace와 getMessage를 사용할 수 있음
ae.printStackTrace();
System.out.println(aa.getMessage());
} catch(Exception e){
...
}
> java.lang.ArithmeticException: / by zero
at MyClass.main(MyClass.java:5)
> / by zero
---------------------------------------------
2. 멀티 try-catch 문 예시
- 멀티 try-catch문은 내용이 같은 catch블럭을 하나로 만들어 주는 것
try {
...
} catch(ExceptionA ae){
ae.printStackTrace();
} catch(ExceptionB be){
be.printStackTrace();
}
try{
...
} catch (ExceptionA | ExceptionB e){
e.printStackTrace();
}
--------------------------
// 부모자식관계의 경우 부모만 잡아도 ok
try{
...
// } catch (ParentException pe | ChildException ce)
} catch (ParentException pe){
pe.printStackTrace();
}
--------------------------
// 멀티 케치문을 사용할 때 특정 에러의 메서드를 사용하려면 instanceof로 확인하여 형변환해서 사용
try{
...
} catch (ExceptionA | ExceptionB e){
e.methodA(); // error, ExceptionA, ExceptionB 둘 중 하나에 의해 에러가 잡힌 것이기 때문에 특정 에러의 메서드 호출 불가
if (e instanceof ExceptionA){
ExceptionA e1 = (ExceptionA) e;
e.methodA(); // 이건 가능
} else {
...
}
}
예외 발생시키기
연산자 new를 이용하여 발생시키려는 예외 클래스의 객체를 생성
- Exception e = new Exception("예외발생");
키워드 throw를 이용해서 예외를 발생시킴
- throw e;
1. 예외 발생시키기 예시
class Ex{
public static void main(String[] args){
try{
Exception e = new Exception("고의로 예외 발생시킴");
throw e; // 예외를 발생시킴, 예외를 던짐
}catch(Exception e){ // 예외를 잡음, 잡아서 처리
System.out.println("에러 메시지 : " + e.getMessage());
e.printStaceTrace();
}
System.out.println("프로그램이 종료되었습니다.!!");
}
}
> 에러 메시지 : 고의로 예외 발생시킴
> 프로그램이 종료되었습니다.!!
> java.lang.Exception: 고의로 예외 발생시킴
at MyClass.main(MyClass.java:5)
checked예외, uncheckede예외
checked예외 : 컴파일러가 예외 처리 여부를 체크(예외 처리 필수)
- Exception과 그 자손
unchecked예외 : 컴파일러가 예외 처리 여부를 체크안함(예외 처리 선택)
- RuntimeException과 그 자손
이유:
- 만약 RuntimeException을 필수로 처리해주어야 한다면, 거의 모든 구문에 try-catch문을 사용해야 하기 때문에
1. checked 예외 발생 예시 ( 필수적 )
// 예외를 발생시켰는데 try-catch문으로 처리해주지 않으면 컴파일 에러
class Ex{
public static void main(String[] args){
throw new Exception("고의로 예외발생");
}
}
> MyClass.java:4: error: unreported exception Exception; must be caught or declared to be thrown
throw new Exception("고의로 예외발생");
^
1 error
-------------------------------------------
2. unchecked 예외 발생 예시 ( 선택적 )
class Ex2{
public static void main(String[] args){
throw new RuntimeException("고의로 예외발생");
}
}
> Exception in thread "main" java.lang.RuntimeException: 고의로 예외발생
at MyClass.main(MyClass.java:4)
메서드에 예외 선언하기
예외 처리하는 방법 : try-catch문(직접처리), 예외 선언하기(예외 떠넘기기)
메서드가 호출 시 발생가능한 예외를 호출하는 쪽에 알리는 것
오버라이딩 조건
- 선언부일치
- 접근제어자가 조상보다 좁으면 x
- 조상보다 예외선언이 많으면 x (Exception은 모든 예외의 조상이기 때문에 가장 큰 범위이자 많은 선언이라고 할 수 있음)
throw로 던져진 Exception은 누군가는 처리해야 함
1. 메서드에 예외 선언하기 예시
void method() throws Exception1, Exception2, ... , ExceptionN{// 필수 처리 예외를 우선으로 적음, 선택예외는 안적는 걸 권장
// 메서드 내용
}
void method2() throws Exception{// 모든 종류의 예외 발생 가능
}
static void startInstall() throws SpaceException, MemoryException{
// 호출한 메서드에 Exception을 알려주기
if (!enoughSpace()){
throw new SpaceException("설치할 공간이 부족합니다.");
} else if (!enoughMemory()){
throw new MemoryException("충분한 메모리가 없습니다.");
}
}
----------------------------------------------
2. 메서드에 예외 선언하기 예시 2
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("예외발생 - method2()");
}
}
> Exception in thread "main" java.lang.Exception
at MyClass.method2(MyClass.java:11)
at MyClass.method1(MyClass.java:7)
at MyClass.main(MyClass.java:3)
------------------------------------------------
3. 메서드에 예외 선언하기 예시 3
import java.io.*;
class Ex3{
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 (fileName == null || fileName.equals("")){
throw new Exception("파일이름이 유효하지 않습니다.");
}
File f = new File(fileName);
f.createNewFile();
return f;
}
}
> cmd args : testFileName
> testFileName파일이 성공적으로 생성되었습니다.
> cmd args :
> Index 0 out of bounds for length 0 다시 입력해주시기 바랍니다.
finally 블럭
- 예외 발생 여부와 상관없이 수행되어야 하는 코드를 넣는 블럭
1. finally 구문의 기본 구조
try{
// 예외가 발생할 가능성이 있는 코드
}catch(Exception e){
// 예외가 발생했을 때 처리할 코드
}finally{
// 예외 발생 여부와 상관없이 마지막에 실행되는 코드
}
참고 : try 블럭 안에 return문이 있어서 try블럭을 벗어나는 경우에도 finally 블럭은 실행된다.
-----------------------------------------
2. finally 구문의 예시
try{
startInstall();
copyFile();
deleteTempFiles(); // 예외가 발생하지 않아도 실행
} catch(Exception e){
e.printStackTrace();
deleteTempFiles(); // 예외가 발생해도 실행
}
try{
startInstall();
copyFile();
} catch (Exception e){
e.printStackTrace();
} finally {
deleteTempFiles(); // 예외 발생 여부와 상관없이 실행되어야 하는 코드는 finally구문으로 처리
}
사용자 정의 예외 만들기
- 사용자가 직접 예외를 만들 수 있음
- 조상은 Exception과 RuntimeException중에서 선택
- 만약 Exception으로 처리하면 필수 예외처리를 함
- 만약 RuntimeException으로 처리하면 선택 예외처리를 함
1. 사용자 정의 예외 만들기 예시 1
class MyExceptionClass extends Exception{
MyException(String msg){ // 매개변수로 message를 받는다.
super(msg); // 조상인 Exception클래스의 생성자를 호출
}
}
-------------------------------------
2. 사용자 정의 예외 만들기 예시 2
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;
}
}
예외 되던지기 (Exception re-throwing)
- 예외를 처리한 후에 다시 예외를 발생시키는 것
- 호출한 메서드와 호출된 메서드 양쪽 모두에서 예외처리를 하는 것
- 분담처리를 하기 위해서 사용, 상황에 맞게
1. 예외 되던지기 예시, 예외를 method1에서 받고 처리한 후 다시 던져서 main에서 또 처리
class Ex1{
public static void main(String[] args){
try{
method1();
} catch(Exception e){
System.out.println("main메서드에서 예외를 처리했습니다.");
}
}
static void method1() throws Exception{
try{
throw new Exception();
} catch(Exception e){
System.out.println("method1메서드에서 예외가 처리되었습니다.");
throw e;
}
}
}
> method1메서드에서 예외가 처리되었습니다.
> main메서드에서 예외를 처리했습니다.
연결된 예외(chained exception)
한 예외가 다른 예외를 발생시키는 것
예외 A가 예외 B를 발생시키면, 예외 A는 원인예외(cause exception)이라고 함
이유:
- 여러 예외를 하나로 묶어서 다룰 때
- checked예외를 unchecked 예외로 변경할 떄
- Exception을 RuntimeException으로
1. 연결된 예외 기본 구조
Throwable initCause(Throwable cause) 지정한 예외를 원인 예외로 등록
Throwable getCause() 원인 예외를 반환
public class Throwable implements Serializable{
...
private Throwable cause = this; // 객체 자신을 원인 예외로 등록
...
public synchronized Throwable initCause(Throwable cause){
...
this.cause = cause; // 다른 예외를 등록할 수 있음
return this;
}
...
}
-----------------------------------------------
2. 연결된 예외 예시 1
void install() throws InstallException{
try{
startInstall();
copyFiles();
} catch (SpaceException se){
InstallException ie = new InstallException("설치중 예외발생"); // 예외 생성
ie.initCause(se); // InstallException의 원인은 SpaceException이기 때문에 InstallException의 원인 예외로 SpaceException을 등록
throw ie;
} catch (MemoryException me){
...
}
}
----------------------------------------------
3. 여러 예외를 하나로 묶어서 다루기 위한 예시
try{
install();
} catch(SpaceException se){
se.printStackTrace();
} catch(MemoryException me){
me.printStackTrace();
} catch(Exception e){
e.printStackTrace();
}
try{
install();
} catch(InstallException ie){
ie.printStackTrace();
} catch(Exception e){
e.printStackTrace();
}
--------------------------------------------
4. checked 예외를 unchecked 예외로 변경할 때
static void startInstall() throws SpaceException, MemoryException{ // 필수 예외 처리 선언 -> RuntimeException으로 바꾸면 선택 예외 처리 가능
if (!enoughSpace()){
throw new SpaceException("설치할 공간이 부족합니다.");
}
if (!enoughMemory()){
throw new MemoryException("메모리가 부족합니다.");
}
}
static void startInstall() throws MemoryException{ // 필수 예외 처리 선언 -> RuntimeException으로 바꾸면 선택 예외 처리 가능
if (!enoughSpace()){
throw new RuntimeException(SpaceException("설치할 공간이 부족합니다."));
}
if (!enoughMemory()){
throw new MemoryException("메모리가 부족합니다.");
}
}
- 자바의 정석 8 챕터에서는 오류와 예외의 자세한 이론을 배웠습니다.
댓글