본문 바로가기

Programming/Java

[Java] 김영한의 자바 중급 1편 #10 - 예외처리 실습

반응형

1. 예외 처리 도입1 - 시작

 

위의 프로그램은 반환값을 사용해서 예외를 처리했다. 이런 경우 다음의 문제가 있다.

  • 정상 흐름과 예의 흐름이 섞여 있기 때문에 코드를 한눈에 이해하기 어려움
  • 예외 흐름이 더 많은 코드 분량을 차지한다.

 

1.1. 이 문제를 점진적으로 해결해보기

 

 

 

1.2. 정상 프로그램

 

 

1.3. 예외

 

 

error1(연결 실패), error2(데이터 전송 실패) 둘 다 모든 곳에서 발생한 예외를 잡지 않았기 때문에 결과적으로 main() 밖으로 예외가 던져진다.

main() 밖으로 예외가 던져지면 예외 메시지와 예외를 추적할 수 있는 스택 트레이스를 출력하고 프래그램이 종료된다.

 

1.4. 남은 문제

  • 예외 처리를 도입했지만 아직 예외가 복구되지 않는다. 따라서 예외가 발생하면 프로그램이 종료된다.
  • 사용 후에는 반드시 disconnect()를 호출해서 연결을 해제해야 한다.

 

2. 예외 처리 도입2 - 예외 복구

목적 : 예외를 잡아서 예외 흐름을 정상 흐름으로 복구

 

2.1. 코드

NetworkServiceV2_2를 아래와 같이 만들었다

 

package exception.ex2;

public class NetworkServiceV2_2 {

    public void sendMessage(String data) {
        String address = "<https://example.com>";

        NetworkClientV2 client = new NetworkClientV2(address);
        client.initError(data);

        try {
            client.connect();
        } catch (NetworkClientExceptionV2 e) {
            System.out.println("[오류] 코드 : " + e.getErrorCode() + ", 메시지 : " + e.getMessage());
            return;
        }

        try {
            client.send(data);
        } catch (NetworkClientExceptionV2 e) {
            System.out.println("[오류] 코드 : " + e.getErrorCode() + ", 메시지 : " + e.getMessage());
            return;
        }

        client.disconnect();
    }
}

 

  • connect()와 send() 메서드를 호출할 때 try ~ catch 구문을 사용해서 NetworkClientExceptionV2 예외를 잡는다.
  • 예외를 잡아서 처리했기 때문에 이후에는 정상 흐름으로 복귀한다. 여기서는 리턴을 사용해서 sendMessage() 메서드를 정상적으로 빠져나간다.

 

MainV2 코드를 아래와같이 변경한다.

public static void main(String[] args) throws NetworkClientExceptionV2 {
	//NetworkServiceV2_1 networkService = new NetworkServiceV2_1();
	NetworkServiceV2_2 networkService = new NetworkServiceV2_2();
	...
}

 

 

2.2. 해결된 문제와 남은 문제

해결된 문제

  • 예외를 잡아서 처리했으므로 예외가 복구 되고, 프로그램도 계속 수행할 수 있다.

남은 문제

  • 예외 처리를 했지만 정상 흐름과 예외 흐름이 섞여서 코드를 읽기 어렵다.
  • 사용 후에는 반드시 disconnect()를 호출해서 연결을 해제해야 한다.

 

3. 예외 처리 도입3 - 정상, 예외 흐름 분리

목적 : 예외 처리의 try ~ catch 기능을 제대로 사용해서 정상 흐름과 예외 흐름이 섞여 있는 문제를 해결해본다.

 

3.1. 코드

package exception.ex2;

public class NetworkServiceV2_3 {

    public void sendMessage(String data) {
        String address = "<https://example.com>";

        NetworkClientV2 client = new NetworkClientV2(address);
        client.initError(data);

        // 하나의 try 안에 정상 흐름을 모두 담고
        // 예외 부분은 catch 블럭에서 해결한다.
        try {
            client.connect();
            client.send(data);
            client.disconnect();
        } catch (NetworkClientExceptionV2 e) {
            System.out.println("[오류] 코드 : " + e.getErrorCode() + ", 메시지 : " + e.getMessage());
        };
    }
}

 

3.2. 실행

 

 

3.3. 해결된 문제와 남은 문제

해결된 문제

  • try 블럭에 정상 흐름을 모아서 처리하고, 예외 흐름은 catch 블럭에 별도로 모아서 처리할 수 있게 되었다.
  • 코드를 더 쉽게 읽을 수 있게 되었다.

남은 문제

  • 사용 후에는 반드시 disconnect() 호출해서 연결을 해제해야 한다.

 

4. 예외 처리 도입4 - 리소스 반환 문제

4.1. 코드

package exception.ex2;

public class NetworkServiceV2_4 {

    public void sendMessage(String data) {
        String address = "<https://example.com>";

        NetworkClientV2 client = new NetworkClientV2(address);
        client.initError(data);

        try {
            client.connect();
            client.send(data);

        } catch (NetworkClientExceptionV2 e) {
            System.out.println("[오류] 코드: " + e.getErrorCode() + ", 메시지: " + e.getMessage());
        }

        // 정상 흐름의 마지막에 client.disconnect()를 호출했음
        // 이렇게 하면 예외가 모두 처리되었기 때문에 disconnect()가 항상 호출될 것 같다.
        // 하지만,, NetworkClientException이 아닌 다른 예외가 발생해서 예외가 밖으로 던져지면 무시
        client.disconnect();
    }
}

 

4.2. 문제

catch에서 잡을 수 없는 예외가 발생한다면 disconnect()는 호출되지 않을 것이다.

 

사용 후에 반드시 disconnect()를 호출해서 연결 해제를 보장하는 것은 쉽지 않다.

 

왜냐하면 정상적인 상황, 예외 상황 그리고 어디선가 모르는 예외를 밖으로 던지는 상황까지 모두 고려해야 한다.

 

하지만 앞서 보았듯이 지금과 같은 구조로는 항상 disconnect()와 같은 코드를 호출하는 것이 매우 오렵고 실수로 놓칠 가능성이 높다.

 

5. 예외 처리 도입5 - finally

자바는 어떤 경우라도 반드시 호출되는 finally 기능을 제공한다.

try {
	// 정상 흐름
} catch {
	// 예외 흐름
} finally {
	// 반드시 호출해야 하는 마무리 흐름
}
  • 정상 흐름 → finally
  • 예외 catch → finally
  • 예외 throw → finally → finally 코드 블럭이 끝나고 나서 이후에 예외가 밖으로 던져진다.

 

finally 블럭은 반드시 호출된다. 따라서 주로 try에서 사용한 자원을 해제할 때 주로 사용된다.

 

5.1. 코드

package exception.ex2;

public class NetworkServiceV2_5 {

    public void sendMessage(String data) {
        String address = "<https://example.com>";

        NetworkClientV2 client = new NetworkClientV2(address);
        client.initError(data);

        try {
            client.connect();
            client.send(data);
        } catch (NetworkClientExceptionV2 e) {
            System.out.println("[오류] 코드 : " + e.getErrorCode() + ", 메시지 : " + e.getMessage());
        } finally {
            client.disconnect();
        }
    }
}

 

5.2. 실행 결과

 

5.3. 정리

자바 예외 처리는 try ~ catch ~ finally 구조를 사용해서 처리할 수 있다.

  • 정상 흐름과 예외 흐름을 분리하여 코드를 읽기 쉽게 만들어준다.
  • 사용한 자원을 항상 반환할 수 있도록 보장해준다.

 

6. 예외 계층1 - 시작

예외를 단순히 오류 코드로 분류하는 것이 아니라 예외를 계층화하여 다양하게 만들면 더 세밀하게 예외를 처리할 수 있다.

  • NetworkClientExceptionV3 : NetworkClient에서 발생하는 모든 예외는 해당 예외의 자식이다.
  • ConnectExceptionV3 : 연결 실패시 발생하는 예외이며 내부에 연결을 시도한 address를 보관한다.
  • SendExceptionV3 : 전송 실패시 발생하는 예외이다. 내부에 전송을 시도한 데이터인 sendData를 보관한다.

예외 계층화 시 장점

  • 자바에서 예외는 객체이다. 따라서 부모 예외를 잡거나 던지면 자식 예외도 함께 잡거나 던질 수 있다. (NetworkClientExceptionV3 예외를 잡으면 그 하위인 ConnectExceptionV3, SendExceptionV3 예외도 함께 잡을 수 있다.)
  • 특정 예외를 잡아서 처리하고 싶으면 ConnectExceptionV3, SendExceptionV3와 같은 하위 예외를 잡아서 처리하면 된다.

 

6.3. 코드

Exception 코드 : exception 패키지 내에 담아둠

 

 

NetworkClient 코드

package exception.ex3;

import exception.ex3.exception.ConnectExceptionV3;
import exception.ex3.exception.SendExceptionV3;

public class NetworkClientV3 {
    private final String address;
    public boolean connectError;
    public boolean sendError;

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

    // 예외 그 자체로 어떤 오류가 발생했는지 알 수 있다.
    public void connect() throws ConnectExceptionV3 {
        if (connectError) {
            throw new ConnectExceptionV3(address, address + " 서버 연결 실패");
        }

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

    public void send(String data) throws SendExceptionV3 {
        if (sendError) {
            throw new SendExceptionV3(data, address + " 서버에 데이터 전송 실패 : " + data);
        }

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

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

    public void initError(String data) {
        if (data.contains("error1")) {
            connectError = true;
        }
        if (data.contains("error2")) {
            sendError = true;
        }
    }
}

 

NetworkService 코드

package exception.ex3;

import exception.ex3.exception.ConnectExceptionV3;
import exception.ex3.exception.SendExceptionV3;

public class NetworkServiceV3_1 {

    public void sendMessage(String data) {
        String address = "<https://example.com>";

        NetworkClientV3 client = new NetworkClientV3(address);
        client.initError(data);

        try {
            client.connect();
            client.send(data);

        // 연결 예외를 잡는다.
        } catch (ConnectExceptionV3 e) {
            System.out.println("[연결 오류] 주소 : " + e.getAddress() + ", 메시지 : " + e.getMessage());

        // 전송 예외를 잡는다.
        } catch (SendExceptionV3 e) {
            System.out.println("[전송 오류] 전송 데이터 : " + e.getSendData() + ", 메시지 : " + e.getMessage());
        } finally {
            client.disconnect();
        }
    }
}

 

 

Main 코드

 

 

 

7. 예외 계층2 - 활용

  • NetworkClientV3에서 수 많은 예외를 발생시킨다고 가정한다.
    • 이런 경우 모든 예외를 하나하나 다 잡아서 처리하는 것은 상당히 번거로울 수 있다.
  • 연결 오류는 중요하다고 가정한다. ConnectExceptionV3가 발생하면 다음과 같이 명확한 메시지를 남기도록 한다.
    • [연결 오류] 주소: …
  • NetworkClientV3를 사용하면서 발생하는 나머지 예외(NetworkClientExceptionV3의 자식)은 단순하게 다음과 같이 출력하도록 한다.
    • [네트워크 오류] 메시지: …
  • 그 외에 예외가 발생하면 다음과 같이 출력한다.
    • [알 수 없는 오류] 메시지: …

 

7.1. 코드

NetworkServiceV3_2 코드

package exception.ex3;

import exception.ex3.exception.ConnectExceptionV3;
import exception.ex3.exception.NetworkClientExceptionV3;

 class NetworkServiceV3_2 {
    public void sendMessage(String data) {

        String address = "<https://example.com>";

        NetworkClientV3 client = new NetworkClientV3(address);

        client.initError(data);

        try {
            client.connect();
            client.send(data);

        } catch (ConnectExceptionV3 e) {
            System.out.println("[연결 오류] 주소: " + e.getAddress() + ", 메시지: " + e.getMessage());

        } catch (NetworkClientExceptionV3 e) {
            System.out.println("[네트워크 오류] 메시지: " + e.getMessage());

        } catch (Exception e) {
            System.out.println("[알 수 없는 오류] 메시지: " + e.getMessage());

        } finally {
            client.disconnect();
        }
    }
}

 

 

Main 코드 및 실행 결과

 

 

 

7. 예외 계층2 - 활용

  • NetworkClientV3에서 수 많은 예외를 발생시킨다고 가정한다.
    • 이런 경우 모든 예외를 하나하나 다 잡아서 처리하는 것은 상당히 번거로울 수 있다.
  • 연결 오류는 중요하다고 가정한다. ConnectExceptionV3가 발생하면 다음과 같이 명확한 메시지를 남기도록 한다.
    • [연결 오류] 주소: …
  • NetworkClientV3를 사용하면서 발생하는 나머지 예외(NetworkClientExceptionV3의 자식)은 단순하게 다음과 같이 출력하도록 한다.
    • [네트워크 오류] 메시지: …
  • 그 외에 예외가 발생하면 다음과 같이 출력한다.
    • [알 수 없는 오류] 메시지: …

 

7.1. 코드

NetworkServiceV3_2 코드

package exception.ex3;

import exception.ex3.exception.ConnectExceptionV3;
import exception.ex3.exception.NetworkClientExceptionV3;

 class NetworkServiceV3_2 {
    public void sendMessage(String data) {

        String address = "<https://example.com>";

        NetworkClientV3 client = new NetworkClientV3(address);

        client.initError(data);

        try {
            client.connect();
            client.send(data);

        } catch (ConnectExceptionV3 e) {
            System.out.println("[연결 오류] 주소: " + e.getAddress() + ", 메시지: " + e.getMessage());

        } catch (NetworkClientExceptionV3 e) {
            System.out.println("[네트워크 오류] 메시지: " + e.getMessage());

        } catch (Exception e) {
            System.out.println("[알 수 없는 오류] 메시지: " + e.getMessage());

        } finally {
            client.disconnect();
        }
    }
}

 

 

Main 코드 및 실행 결과

 

7.2. 정리

예외를 계층화하고 다양하게 만들면 더 세밀한 동작들을 깔끔하게 처리할 수 있다.

 

특정 분류의 공통 예외들도 한번에 catch로 잡아서 처리할 수 있다.

 

 

 

8. 실무에서의 예외 처리 방안1 - 설명

처리할 수 없는 예외 : 상대 네트워크 서버에 문제가 발생해서 통신이 불가능하거나, 데이터베이스 서버에 문제가 발생해서 접속이 안되면, 애플리케이션 연결 오류, 데이터베이스 접속 실패와 같은 예외가 발생한다.

이런 경우 고객에게는 ‘현재 시스템에 오류가 있다’라는 오류 메시지를 보여주고, 내부 개발자가 문제 상황을 빠르게 인지할 수 있도록 오류에 대한 로그를 남겨두어야 한다.

 

체크 예외의 부담 : 체크 예외는 개발자가 실수로 놓칠 수 있는 예외들을 컴파일러가 체크해주기 때문에 오래전부터 많이 사용해왔다.

하지만 점점 처리할 수 없는 예외가 많아지고, 프로그램이 점점 복잡해지면서 체크 예외를 사용하는 것이 부담스러워졌다.

 

8.1. 체크 예외 시나리오

체크 예외를 발생 시 어떤 문제가 발생하는지 시나리오로 설명

 

 

  • 실무에서는 수 많은 라이브러리를 사용하고, 또 다양한 외부 시스템과 연동한다.
  • 사용하는 각각의 클래스들이 자신만의 예외를 모두 체크 예외로 만들어서 전달한다고 가정하자.

 

 

이 경우 Service 는 호출하는 곳에서 던지는 체크 예외들을 처리해야 한다.

만약 처리할 수 없다면 밖으로 던져야 한다.

 

8.1.1. 모든 체크 예외를 잡아서 처리하는 예시

try {
} catch (NetworkException) {...}
} catch (DatabaseException) {...}
} catch (XxxException) {...}

 

8.1.2. 모든 체크 예외를 던지는 예시

class Service {
	void sendMessage(String data) throws NetworkException, DatabaseException, ...{
	...
	}
}
  • 모든 체크 예외를 하나씩 다 밖으로 던져야 한다.
  • 라이브러리가 늘어날수록 다루어야 하는 예외도 많아진다.

여기서 중간에 Facade라는 클래스가 있다고 가정해보자.

 

 

  • 이 경우 Facade 클래스에서도 이런 예외들을 복구할 수 없다. Facade 클래스도 예외를 밖으로 던져야 한다.
  • 결국 중간에 모든 클래스에서 예외를 계속 밖으로 던지는 지저분한 코드가 만들어진다.
  • throws로 발견한 모든 예외를 다 밖으로 던지는 것이다.
class Facade {
	void send() throws NetworkException, DatabaseException, ...
}

class Service {
	void sendMessage(String data) throws NetworkException, DatabaseException, ...
}

 

8.1.3. throws Exception

예외 처리 지옥에 빠지게 되는 개발자는 결국 Exception을 던지게 되는 최악의 수를 던지게 될 수도 있음

class Facade {
	void send() throws Exception
}

class Service {
	void sendMessage(String data) throws Exception
}

throws Exception의 문제

Exception은 최상위 타입이므로 모든 체크 예외를 다 밖으로 던지는 문제가 발생한다.

결과적으로 체크 예외의 최상위 타입인 Exception을 던지게 되면 다른 체크 예외를 체크할 수 있는 기능이 무효화되고, 중요한 체크 예외를 다 놓치게 된다.

중간에 중요한 체크 예외가 발생해도 컴파일러는 Exception을 던지기 때문에 문법에 맞다고 판단해서 컴파일 오류가 발생하지 않는다.

따라서 꼭 필요한 경우가 아니면 Exception 자체를 밖으로 던지는 것은 좋지 않다.

 

 

8.1.4. 문제 정리

  • 처리할 수 없는 예외 : 예외를 잡아서 복구할 수 있는 예외보다 복구할 수 없는 예외가 더 많다.
  • 체크 예외의 부담 : 처리할 수 없는 예외는 밖으로 던져야 한다. 체크 예외이므로 throws에 던질 대상을 일일이 명시해야 한다.

 

8.2. 언체크(런타임) 예외 사용 시나리오

 

 

  • 이번에는 Service에서 호출하는 클래스들이 언체크(런타임) 예외를 전달한다고 가정해본다.
  • NetworkException, DatabaseException은 잡아도 복구할 수 없다. 언체크 예외이므로 이런 경우 무시하면 된다.

 

8.2.1. 언체크 예외를 던지는 예시

class Service {
	void sendMessage(String data) {
	...
	}
}

→ throws를 선언하지 않아도 된다.

 

9. 실무 예외 처리 방안2 - 구현

지금까지 실습한 내용들을 언체크 예외로 만들고, 해결할 수 없는 예외들을 공통으로 처리해본다.

 

  • NetworkClientExceptionV4 : 언체크 예외인 RuntimeException을 상속받는다.
    • NetworkClientExceptionV4와 자식은 모두 언체크 예외가 된다.

 

9.1. 코드

9.1.1. exception

 

NetworkClientException : RuntimeException을 상속

package exception.ex4.exception;

public class NetworkClientExceptionV4 extends RuntimeException {

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

 

SendException

package exception.ex4.exception;

public class SendExceptionV4 extends NetworkClientExceptionV4 {
    private final String sendData;

    public SendExceptionV4(String sendData, String message) {
        super(message);
        this.sendData = sendData;
    }

    public String getSendData() {
        return sendData;
    }
}

 

ConnectException

package exception.ex4.exception;

public class ConnectExceptionV4 extends NetworkClientExceptionV4 {
    private final String address;

    public ConnectExceptionV4(String address, String message) {
        super(message);
        this.address = address;
    }

    public String getAddress() {
        return address;
    }
}

 

 

9.1.2. Client, Service

 

Client

package exception.ex4;
import exception.ex4.exception.ConnectExceptionV4;
import exception.ex4.exception.SendExceptionV4;

public class NetworkClientV4 {
    private final String address;
    public boolean connectError;
    public boolean sendError;

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

    public void connect() {
        if (connectError) {
            throw new ConnectExceptionV4(address, address + " 서버 연결 실패");
        }
        System.out.println(address + " 서버 연결 성공");
    }

    public void send(String data) {
        if (sendError) {
            throw new SendExceptionV4(data, address + " 서버에 데이터 전송 실패: " + data);
        }
        System.out.println(address + " 서버에 데이터 전송: " + data);
    }

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

    public void initError(String data) {
        if (data.contains("error1")) {
            connectError = true;
        }

        if (data.contains("error2")) {
            sendError = true;
        }
    }
}

 

 

Service

package exception.ex4;

// 1. ConnectExceptioNV4, SendExceptionV4를 잡아도 해당 오류들을 복구할 수 없다.
// 따라서 예외를 밖으로 던진다.

// 2. 언체크 예외이므로 throws를 사용하지 않는다.

// 3. 해결할 수 없는 예외들은 다른 곳에서 공통으로 처리된다.
public class NetworkServiceV4 {
    public void sendMessage(String data) {
        String address = "<https://example.com>";

        NetworkClientV4 client = new NetworkClientV4(address);

        client.initError(data);
        try {
            client.connect();
            client.send(data);

        } finally {
            client.disconnect();
        }
    }
}

 

 

9.1.3. Main

package exception.ex4;

import exception.ex4.exception.SendExceptionV4;

import java.util.Scanner;

public class MainV4 {

    public static void main(String[] args) {

        NetworkServiceV4 networkService = new NetworkServiceV4();

        Scanner scanner = new Scanner(System.in);
        while (true) {
            System.out.print("전송할 문자: ");
            String input = scanner.nextLine();

            if (input.equals("exit")) {
                break;
            }

            try {
                networkService.sendMessage(input);

                // 모든 예외를 잡아서 처리
            } catch (Exception e) {
                exceptionHandler(e);
            }
            System.out.println();
        }
        System.out.println("프로그램을 정상 종료합니다.");
    }

    // 공통 예외 처리
    private static void exceptionHandler(Exception e) {
        // 공통 처리
        System.out.println("사용자 메시지 : 죄송합니다. 알 수 없는 문제가 발생했습니다.");
        System.out.println("-- 개발자용 디버깅 메시지 --");
        // System.err에 스택 트레이스 출력
        e.printStackTrace();

        // 필요하면 예외 별로 별도의 추가 처리 가능
        if (e instanceof SendExceptionV4 sendEx) {
            System.out.println("[전송 오류] 전송 데이터: " + sendEx.getSendData());
        }
    }
}

 

 

공통 예외 처리

try {
	networkService.sendMessage(input);
} catch (Exception e) { // 모든 예외를 잡아서 처리
	exceptionHandler(e);
}
  • Exception을 잡아서 지금까지 해결하지 못한 모든 예외를 여기서 공통으로 처리한다.
  • 예외도 객체이므로 공통 처리 메서드인 exceptionHandler(e)에 예외 객체를 전달한다.

 

exceptionhandler()

  • 해결할 수 없는 예외가 발생하면 사용자에게는 시스템 내에 알 수 없는 문제가 발생했다고 알리는 것이 좋다.
  • 개발자는 빨리 문제를 찾고 디버깅 할 수 있도록 오류 메시지를 남겨두어야 한다.
  • 예외도 객체이므로 필요하면 instanceof와 같이 예외 객체의 타입을 확인해서 별도의 추가 처리를 할 수 있다.

 

10. try-with-resources

Java 7에서부터 Try with resources라는 편의 기능을 도입했다.

이름 그대로 try에서 자원을 함께 사용한다는 뜻이다. 여기서 자원은 try가 끝나면 반드시 종료해서 반납해야 하는 외부 자원을 뜻한다.

이 기능을 사용하려면 AutoCloseable 인터페이스를 구현해야 한다.

package java.lang;

public interface AutoCloseable {
	void close() throws Exception;
}

→ 이 인터페이스를 구현하면 Try with resources를 사용할 때 try가 끝나는 시점에 close()가 자동으로 호출된다.

그리고 다음과 같이 Try with resource 구문을 사용하면 된다.

try (Resource resource = new Resource()) {
	// resource를 사용하는 코드
}

 

 

10.1. 코드 예시

package exception.ex4;

public class NetworkServiceV5 {
	public void sendMessage(String data) {
	
	String address = "<https://example.com>";
	
	// Try with resource 구문
	try (NetworkClientV5 client = new NetworkClientV5(address)) {
		client.initError(data);
		client.connect();
		client.send(data);

 } catch (Exception e) {
		System.out.println("[예외 확인]: " + e.getMessage());
		throw e;
		}
	}
}
  • Try with resiource 구문은 try 괄호 안에 사용할 자원을 명시한다.
  • 이 자원은 try 블럭이 끝나면 자동으로 AutoCloseable.close()를 호출해서 자원을 해제한다.
  • 참고로 여기서 catch 블럭 없이 try 블럭만 있어도 close()는 호출된다.

 

10.2. Try with resource 장점

  • 리소스 누수 방지 : 모든 리소스가 제대로 닫히도록 보장한다. 실수로 finally 블록을 적지 않거나, finally 블럭 안에서 자원 해제 코드를 누락하는 문제들을 예방할 수 있다.
  • 코드 간결성 및 가독성 향상 : 명시적인 close() 호출이 필요 없어 코드가 더 간결하고 읽기 쉬워진다.
  • 스코프 범위 한정: 예를 들어 리소스로 사용되는 client 변수의 스코프가 try 블럭 안으로 한정된다. 따라서 코드 유지보수가 더 쉬워진다.
  • 조금 더 빠른 자원 해제: 기존에는 try catch finally로 catch 이후에 자원을 반납했다. Try with resources 구분은 try 블럭이 끝나면 즉시 close() 를 호출한다.

 

 

반응형