자바 스터디

[자바의 정석] CH8

changha. 2023. 6. 24. 23:38

프로그램 오류 종류

- 컴파일 에러 : 컴파일 할 때 발생하는 에러

- 런타임 에러 : 실행 중 발생하는 에러 

- 논리적 에러 : 작성 의도와 다르게 동작 

 

자바의 런타임 에러 

- 에러 : 프로그램 코드에 의해서 수습될 수 없는 심각한 오류 

- 예외 : 프로그램 코드에 의해서 수습될 수 있는 다소 미약한 오류 

 

예외 처리의 정의와 목적 

정의 : 프로그램 실행 시 발생할 수 있는 예외의 발생에 대비한 코드를 작성하는 것 

목적 : 프로그램의 비정상 종료를 막고, 정상적인 실행상태를 유지하는 것 

 

Throwable - 모든 오류의 조상 

Exception, Error - 런타임 에러

1. Exception클래스들 : 사용자의 실수와 같은 외적인 요인에 의해 발생하는 예외 

2. RuntimeException클래스들 : 프로그래머의 실수로 발생하는 예외 

 

예외 처리하기. try-catch문 

예외처리(exception handling)

정의 : 프로그램 실행 시 발생할 수 있는 예외의 발생에 대비한 코드를 작성하는 것

목적 : 프로그램의 비정상 종료를 막고, 정상적인 실행상태를 유지하는 것 

try{
	// 예외가 발생할 가능성이 있는 문장들을 넣는다.
}catch (Exception1 e1){
	// Exception1이 발생했을 경우, 이를 처리하기 위한 문장을 적는다.
}catch (Exception2 e2){
	// Exception2이 발생했을 경우, 이를 처리하기 위한 문장을 적는다.
}
...

 

try-catch문에서의 흐름 

1. 발생한 예외와 일치하는 catch블럭이 있는지 확인함.

2. 일치하는 catch블럭을 찾으면, 그 블럭을 수행하고 전체 try-catch문을 빠져나가서 그 다음 문장을 계속해서 수행 

    만약 일치하는 catch블럭 찾지 못하면, 예외는 처리되지 못함.

왼쪽: 예외 발생 안함, 오른쪽: 예외 발생 함

3. Exception이 선언된 catch블럭은 모든 예외 처리(마지막 catch블럭)

          - Exception catch블럭은 모든 예외를  처리하므로 제일 마지막 catch블럭에 넣어야 한다.

 

 

printStackTrace() 와 getMessage()

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());
}

System.out.println(6);


//결과 
//3
//java.lang.ArithmeticException ...
//예외메시지 : / by zero
//6

 멀티 catch블럭 

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

 

예외 발생시키기 

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

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

2. 키워드 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: 고의로 발생시켰음 ...
// 프로그램이 정상 종료되었음.

checked예외, unchecked예외 

checked예외 : 컴파일러가 예외 처리 여부를 체크(예외 처리 필수)

public static void main(String[] args){
    try{
    	throw new Exception(); // checked예외. 필수 예외처리 
    }
    catch(Exception e){}
}

unchecked예외 : 컴파일러가 예외 처리 여부를 체크 안함(예외 처리 선택)

pubilc static void main(String[] args){
	throw new RuntimeException(); // unchecked 예외. 예외처리 선택 
}

오류의 종류 흐름

 

메서드에 예외 선언하기 

- 예외를 처리하는 방법 : try-catch문, 예외 선언하기

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

 

void method() throws Exception1, Exception2, ... {

}

void method() throws Exeption {

}

주의할 점

오버라이딩의 조건 세가지

1. 선언부가 일치해야 함 

2. 접근제어자가 좁아지면 안됨

3. 조상보다 많은 예외 선언 안됨

3번 규칙에서 단순히 예외의 개수 뿐만 아니라 개수가 더 적어도 더 많은 예외를 처리할 수 있기 때문에 불가능한 경우가 있음 

ex) 부모 클래스 예외(IOException, SQLException) 자식 클래스 예외(Exception)인 경우, Exception은 모든 예외의 조상이므로 하나만 선언한다고 적은 개수가 아님 

 

public static void main(String[] args) throws Exception{
	method1(); // 같은 클래스내의 static멤버이므로 객체생성없이 직접 호출가능.
}

static void method1() throws Exception{
	method2();
}

static void method2() throws Exception{
	throw new Exception();
}

stack의 최상단을 프로그램 작동 순서대로 적으면

main -> method1 -> method2 -> method1 -> main -> 비정상 종료

비정상 종료되는 이유는 method2, method1, main 모두 Exception으로 예외를 선언만 하고 처리는 하지 않기 때문이다. 

finally 블럭 

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

try{

} catch(Exception1 e1) {

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

try-catch에서 코드가 중복 될 때 사용한다.

try{
	startInstall();
    copyFiles();
    deleteTempFiles(); // 프로그램 설치에 사용된 임시파일들을 삭제한다.
}catch(Exception e){
	e.printStackTrace();
    deleteTempFiles(); 
}

// 아래와 같이 변경 가능 
try{
	startInstall();
    copyFiles();
}catch(Exception e){
	e.printStackTrace();
} finally {
    deleteTempFiles(); 
}

return 이 되어도 finally 문장들은 수행된다.

//main 메서드 중 
FinallyTest3.method1();
System.out.println("method1()의 수행을 마치고 main메서드로 돌아왔습니다.");


static void method1() {
    try{
        System.out.println("method1()이 호출 되었습니다.");
        return;
    } catch (Exception e){
        e.printStackTrace();
    } finally {
        System.out.println("method1()의 finally블럭이 실행되었습니다.");
    }
}


// 실행 결과
// method1()이 호출 되었습니다.
// method1()의 finally블럭이 실행되었습니다.
// method1()의 수행을 마치고 main메서드로 돌아왔습니다.

 

 

사용자 정의 예외 만들기

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

- 조상은 Exception과 RuntimeException중에서 선택 

 

1. Exception과 RuntimeException중에서 조상을 선택 

2. String 매개변수가 있는 생성자를 만들어야 함 

 

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

- 예외 메시지의 용도는 catch블록의 예외 처리 코드에서 이용하기 위해서이다.

 

예제 

class elementException extends Exception {
    public elementException(String a) {
        super(a);
    }
}

public class Test {
    public static int multi() throws elementException {
        Scanner sc = new Scanner(System.in);
        int a = sc.nextInt();
        int b = sc.nextInt();

        if (a<0 || b<0) {
            throw new elementException("음수 값 입력 금지");
        }
        return a*b;
    }

    public static void main(String[] args) {
        try {
            System.out.printf("곱 : %d", multi());
            System.out.println("multi 함수 실행 완료");
        } catch (elementException e) {
            System.out.println(e.getMessage());
        }
        System.out.println("try catch 문 실행 완료");
    }
// 실행 결과 
// 2
// -2
// Exception in thread "main" elementException : 음수 값 입력 금지 
// ...

예외 되던지기

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

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

public 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; // 다시 예외를 발생시킴 
    }
}

 

연결된 예외

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

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

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

Throwable 은 Exception, Error 의 조상 

 

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

이유2. checked예외(Exception 자손, 필수처리)를 unchecked(RuntimeException자손, 선택처리) 예외로 변경하려 할 때 

Space,MemoryException 필수예외인 상황

 

MemoryException을 선택예외로 바꿈

try-catch를 안써도 될 상황인데 필수 예외인 경우, 선택예외로 위와 같이 바꿀 수 있다. 

'자바 스터디' 카테고리의 다른 글

[자바의 정석] ch11.9 ~ ch.11.11  (0) 2023.07.12
[자바의 정석] CH 9(Math ~ Objects)  (0) 2023.06.29
[자바의 정석] CH7  (0) 2023.06.15
[자바의 정석] CH-6  (0) 2023.05.04
[자바의 정석] CH-5 ~ CH-6  (0) 2023.04.27