ToBe끝판왕

[ JAVA ] 예외 처리 (1) 본문

■ 프로그래밍 SKILLS/JAVA

[ JAVA ] 예외 처리 (1)

업그레이드중 2024. 8. 21. 19:50
반응형





 

 

 

예외처리( Exception Handling )

 

 

•  예외처리를 알기 위한 예시 코드 만들기

-  흐름  :  Main  -->  NetworkService  -->  NetworkClient

-  NetworkClient  :  외부 서버와 연결, 데이터 전송, 연결 종료 기능 제공

-  NetworkService  :  NetworkClient를 사용해서 데이터 전송

-  Main  :  사용자의 입력을 받음

 

 

 

package exception.ex0;

public class NetworkClientV0 {

    private final String address;

    public NetworkClientV0(String address) {
        this.address = address;
    }

    public String connect() {
        // 연결 성공
        System.out.println(address + " 서버 연결 성공");
        return "success";
    }

    public String send(String data) {
        // 전송 성공
        System.out.println(address + " 서버에 데이터 전송: " + data);
        return "success";
    }

    public void disconnect() {
        System.out.println(address + " 서버 연결 해제");
    }
}
// connect() 호출하여 서버와 연결
// send(data) 로 연결된 서버에 메시지 전송
// disconnect() 로 서버와의 연결 해제


package exception.ex0;

public class NetworkServiceV0 {

    public void sendMessage(String data) {
        String address = "http://www.example.com";
        NetworkClientV0 client = new NetworkClientV0(address);

        client.connect();
        client.send(data);
        client.disconnect();
    }
}
// 전송할 문자를 Scanner를 통해 입력
// networkService.sendMessage() 메소드를 통해서 메시지 전달
// "exit"를 입력하면 프로그램 정상 종료


package exception.ex0;

import java.util.Scanner;

public class MainV0 {

    public static void main(String[] args) {

        NetworkServiceV0 networkService = new NetworkServiceV0();

        Scanner scanner = new Scanner(System.in);
        while (true) {
            System.out.print("전송할 문자: ");
            String input = scanner.nextLine();
            if( input.equals("exit") ) {
                break;
            }
            networkService.sendMessage(input);
            System.out.println();
        }
        System.out.println("프로그램을 정상 종료합니다");
    }
}

 

 

 

•  오류상황으로 인해 예외처리는 필요하다.

-  "error1" 단어가 있으면 연결 실패 ( "connnectError")

-  "error2" 단어가 있으면 전송 실패("sendError")

 

-  연결에 실패하면 데이터를 전송하지 않아야 하는데, 전송하기 때문에 해결해야 할 필요성

-  오류가 발생했을 때, 어떤 오류가 남았는지 내역을 남기면 이후 디버깅에 도움이 될 것이다.

 

package exception.ex1;

public class NetworkClientV1 {

    private final String address;
    public boolean connectError;
    public boolean sendError;

    public NetworkClientV1(String address) {
        this.address = address;
    }

	// connectError 필드값의 true가 되면 connectError 오류코드 반환
    public String connect() {
        if(connectError) {
            System.out.println(address + " 서버 연결 실패");
            return "connectError";
        }

        // 연결 성공
        System.out.println(address + " 서버 연결 성공");
        return "success";
    }

	// sendError 필드값의 true가 되면 sendError 오류코드 반환
    public String send(String data) {
        if(sendError) {
            System.out.println(address + " 서버에 데이터 전송 실패");
            return "sendError";
        }

        // 전송 성공
        System.out.println(address + " 서버에 데이터 전송: " + data);
        return "success";
    }

    public void disconnect() {
        System.out.println(address + " 서버 연결 해제");
    }

	// 해당 메서드로 connectError 와 sendError 필드의 값을 true로 설정 가능
    public void initError(String data) {
        if( data.contains("error1")) {
            connectError = true;
        }
        if( data.contains("error2")) {
            sendError = true;
        }
    }
}
package exception.ex1;

public class NetworkServiceV1_1 {

    public void sendMessage(String data) {
        String address = "http://www.example.com";
        NetworkClientV1 client = new NetworkClientV1(address);
        client.initError(data);     // 추가

        client.connect();
        client.send(data);
        client.disconnect();
    }
}
package exception.ex1;

import java.util.Scanner;

public class MainV1 {

    public static void main(String[] args) {

        //NetworkServiceV1_1 networkService = new NetworkServiceV1_1();
        //NetworkServiceV1_2 networkService = new NetworkServiceV1_2();
        NetworkServiceV1_3 networkService = new NetworkServiceV1_3();

        Scanner scanner = new Scanner(System.in);
        while (true) {
            System.out.print("전송할 문자: ");
            String input = scanner.nextLine();
            if( input.equals("exit") ) {
                break;
            }
            networkService.sendMessage(input);
            System.out.println();
        }
        System.out.println("프로그램을 정상 종료합니다");
    }
}
// 실행 결과

전송할 문자: hello
http://www.example.com 서버 연결 성공
http://www.example.com 서버에 데이터 전송: hello
http://www.example.com 서버 연결 해제

전송할 문자: error1
http://www.example.com 서버 연결 실패
[네트워크 오류 발생] 오류 코드: connectError
http://www.example.com 서버 연결 해제

전송할 문자: error2
http://www.example.com 서버 연결 성공
http://www.example.com 서버에 데이터 전송 실패
[네트워크 오류 발생] 오류 코드: sendError
http://www.example.com 서버 연결 해제

전송할 문자: exit
프로그램을 정상 종료합니다

 

 


 

 

Java 의 예외처리

 

•   자바 예외처리는 아래와 같은 키워드를 사용한다.

-  try , catch , finally , throw , throws

 

 

※  Error

•   메모리 부족이나 심각한 시스템 오류와 같이 애플리케이션에서 복구가 불가능한 시스템 예외

•   개발자는 이 예외를 잡을 필요 X

 

•   Exception ( 체크 예외 )

-  애플리케이션 로직에서 사용할 수 있는 최상위 예외이다.

-  Exception과 하위 예외는 모두 컴파일러가 체크하는 예외이다.

 

•   RuntimeException( 언체크 예외 )

-  컴파일러가 체크하지 않는 예외

-  런타임 예외라고 부른다.

 

•   예외 규칙

-  예외가 발생하면 처리하거나 처리할 수 없다면 밖으로 던져야 한다.

-  예외를 처리 못하고 계속 던지게 된다면, 예외 로그를 출력하며 프로그램이 종료된다.

 

 

 

•   체크 예외 예시

-  체크예외는 잡아서 직접 처리하거나 또는 밖으로 던지거나 둘중 하나를 개발자가 직접 꼭 명시해야 한다.

-  체크 예외는 예외를 잡아서 처리할 수 없을 때, 예외를 밖으로 던지는 throws 예외 를 필수로 선언해야 한다

package exception.basic.checked;

/**
 * Exception을 상속받는 예외는 체크 예외가 된다.
 */
public class MyCheckedException extends Exception{

    public MyCheckedException(String message) {
        super(message);
    }
}
// 예외도 객체이기 때문에 new로 생성하고 예외 발생
// throws 키워드는 예외를 밖으로 던질때 사용

package exception.basic.checked;

public class Client {

    public void call() throws MyCheckedException{

        // 문제 상황
        throw new MyCheckedException("ex");
    }
}
package exception.basic.checked;

public class Service {

    Client client = new Client();

    /**
     * 예외를 잡아서 처리하는 코드
     */
    public void callCatch() {

        try{
            client.call();
        } catch (MyCheckedException e) {
            // 예외 처리 로직
            System.out.println("예외 처리, message = " + e.getMessage());
        }
        System.out.println("정상 흐름");

    }

    /**
     *  체크 예외를 밖으로 던지는 코드
     *  체크 예외는 예외를 잡지 않고 밖으로 던지려면 throws 예외를 메서드에 필수로 선언해야 한다.
     */
    public void catchThrow() throws MyCheckedException{
        client.call();

    }
}

 

 

•   위 소스를 바탕으로 예외를 처리하는 코드 예시

package exception.basic.checked;

public class CheckedCatchMain {

    public static void main(String[] args) {

        Service service = new Service();
        
        // callCatch() 메서드로 예외를 처리했기 때문에 main() 메서드까지 예외가 올라가지 않는다.
        service.callCatch();
        
        System.out.println("정상 종료");
    }
}

 

// 실행 결과

예외 처리, message = ex
정상 흐름
정상 종료

 

 

 

※  예외를 잡아서 처리하는 try ~ catch


// try 블럭에서 발생하는 예외를 잡아서 catch 로 넘긴다.
// 만약 try에서 잡은 예외가 catch 대상에 없으면 예외를 잡을 수 없기 때문에 던져야 한다.

try {
 // 정상로직
 
} catch(Exception e) {
 // 예외 처리 로직

}

 

 

•   위 소스를 바탕으로 예외를 처리하지 않고 밖으로 던지는 코드 예시

-  예외를 밖으로 던져서 main() 메서드까지 올라간다.

-  예외가 main()에서도 잡히지 않고 던져져 예외정보와 스택 트레이스( Stack Trace)를 출력하고 프로그램이 종료된다.

package exception.basic.checked;

public class CheckedThrowMain {

    public static void main(String[] args) throws MyCheckedException {

        Service service = new Service();
        service.catchThrow();
        System.out.println("정상 종료");
    }
}

 

// 실행 결과

Exception in thread "main" exception.basic.checked.MyCheckedException: ex
	at exception.basic.checked.Client.call(Client.java:8)
	at exception.basic.checked.Service.catchThrow(Service.java:27)
	at exception.basic.checked.CheckedThrowMain.main(CheckedThrowMain.java:8)

 

 

 

•   언체크 예외 예시

-  언체크 예외는 체크 예외와 다르게 throws 예외 를 선언하지 않아도 된다.

-  말 그대로 컴파일러가 이런 부분을 체크하지 않기 때문에 언체크 예외이다.

package exception.basic.uncheked;

/**
 * RuntimeException을 상속받은 예외는 Uncheck 예외가 된다.
 */
public class MyUncheckedException extends RuntimeException{

    public MyUncheckedException(String message) {
        super(message);
    }
}

 

package exception.basic.uncheked;

public class Client {

    public void call() {
        throw new MyUncheckedException("ex");
    }
}

 

package exception.basic.uncheked;

import exception.basic.checked.MyCheckedException;

/**
 * Unchecked 예외는
 * 예외를 잡거나,  던지지 않아도 된다.
 * 예외를 잡지 않으면 자동으로 밖으로 던진다.
 */
public class Service {

    Client client = new Client();

    /**
     * 필요한 경우 예외를 잡아서 처리할 수 있다.
     */
    public void callCatch() {

        try {
            client.call();
        } catch (MyUncheckedException e) {
            // 예외처리 로직
            System.out.println("예외 처리, message = " + e.getMessage());
        }
        System.out.println("정상 로직");
    }

    /**
     * 예외를 잡지 않아도 된다. 자연스럽게 상위로 넘어 간다.
     */
    public void callThrow() {
        client.call();
    }
}

 

 

 

•   위 소스를 바탕으로 예외를 잡아서 처리하는 코드 예시

package exception.basic.uncheked;

public class UncheckedCatchMain {

    public static void main(String[] args) {

        Service service = new Service();
        service.callCatch();
        System.out.println("정상 종료");
    }
}
// 실행 결과

예외 처리, message = ex
정상 로직
정상 종료

 

 

•   위 소스를 바탕으로 예외를 던지는 코드 예시

package exception.basic.uncheked;

public class UncheckedThrowMain {

    public static void main(String[] args) {

        Service service = new Service();
        service.callThrow();
        System.out.println("정상 종료");
    }
}

// 실행 결과

Exception in thread "main" exception.basic.uncheked.MyUncheckedException: ex
	at exception.basic.uncheked.Client.call(Client.java:6)
	at exception.basic.uncheked.Service.callThrow(Service.java:32)
	at exception.basic.uncheked.UncheckedThrowMain.main(UncheckedThrowMain.java:8)

 

 

 

▶  체크 예외와 언체크 예외

•    정리 체크 예외와 언체크 예외의 차이는 예외를 처리할 수 없을 때 예외를 밖으로 던지는 부분에 있다.

     이 부분을 필수로 선언 해야 하는가 생략할 수 있는가의 차이다.

 

 

 

 

 

※ 해당 내용은 인프런 김영한 강사님의  "실전 자바 중급1" 인강의 참고자료와 예시들을 참고하였습니다

 

 

 

 

반응형
Comments