Java 예외 처리 - 네트워크 예제 리팩토링 4
이전 작성 글 "예외 처리 - 네트워크 리팩토리 3" 이어서 살펴보자.
이전의 작성 글에서는 NetworkService 에서 네트워크 로직이 있으며 외부 자원을 연결 시 반드시 disconnect() 호출하여 외부 자원을 끊는 코드가 필요했다.
NetworkService.class 로직을 살펴보자.
NetworkService.class
public class NetworkService {
public void sendMessage(String data) throws NetworkClientException {
String address = "http://kiioio.com";
NetworkClient client = new NetworkClient(address);
client.initError(data); // 오류 코드로 반환.
try {
client.connect();
client.send(data);
client.disconnect();
} catch (NetworkClientException e) {
System.out.println("[Error] Code: " + e.getErrorCode() + ", Message: " + e.getMessage());
}
}
private static boolean isError(String connectResult) {
return !connectResult.equals("success");
}
}
- try ~ catch 문 예외 처리가 되어있음
- connect(), send(data) 예외 상황 발생 시 disconnect() 호출하지 못하는 문제가 남아 있음
남은 문제를 해결을 위해 client.disconnect(); (try ~ catch) 문에서 아래에 선언을 하였다.
try {
client.connect();
client.send(data);
} catch (NetworkClientException e) {
System.out.println("[Error] Code: " + e.getErrorCode() + ", Message: " + e.getMessage());
}
client.disconnect();
그렇지만 여기서 아직 치명적인 문제가 남아있다.
문제점 찾아내기
상단의 코드에서 예외 처리 발생 시 disconnect() 호출하는 모습을 볼 수 있었다.
Send Message data: error1
[Error] Code: connectError, Message: Connect Open Failed
http://kiioio.com Connect Closed Success
Send Message data: error2
http://kiioio.com Connect Open Success
[Error] Code: sendError, Message: Send Failed
http://kiioio.com Connect Closed Success
Connect Closed Success 문구로 끊어졌다. 언뜻 보기에는 훌륭하게 잘 동작하는 코드이다.
만약 협업으로 NetworkService 관리하는 개발자가 한명 더 생겼을 때를 가정한다.
예외 처리를 위한 Exception 객체 생성을 하여 동작하고 있다. 새로운 개발자가 만약 RuntimeException 객체로 Client 구현 코드로 새로 만들었다면 어떻게 되는지 살펴보자.
NetworkClient.class
public class NetworkClient {
private final String address;
public boolean connectError;
public boolean sendError;
public NetworkClient(String address) {
this.address = address;
}
public void connect() throws NetworkClientException {
// exception error
if (connectError) {
throw new NetworkClientException("connectError", "Connect Open Failed");
}
// Connect Success
System.out.println(address + " Connect Open Success");
}
public void send(String message) throws NetworkClientException {
if (sendError) {
throw new NetworkClientException("sendError", "Send Failed");
}
// 전송 성공
System.out.println(address + " Send Message data: " + message);
}
public void disconnect() {
System.out.println(address + " Connect Closed Success");
}
public void initError(String data) {
if (data.contains("error1")) {
connectError = true;
}
if (data.contains("error2")) {
sendError = true;
}
}
}
이 코드에서 새로운 개발자가 send() 메소드를 RuntimeException 객체로 사용한다면?
send(...) 메소드 수정
public void send(String message) throws NetworkClientException {
if (sendError) {
// throw new NetworkClientException("sendError", "Send Failed");
throw new RuntimeException("Send Failed");
}
// 전송 성공
System.out.println(address + " Send Message data: " + message);
}
이제 예외처리로 인한 호출을 시도해보자.
Main 출력 결과
Send Message data: error2
http://kiioio.com Connect Open Success
Exception in thread "main" java.lang.RuntimeException: Send Failed
at NetworkClient.send(NetworkClient.java:23)
at NetworkService.sendMessage(NetworkService.java:10)
at Main.main(Main.java:15)
"Connect Closed Success" 문구로 외부 자원 연결이 끊어졌다는 문구가 표시되지 않고 예외 처리가 되었다!
이 코드를 계속 사용하면 결국 원인을 찾을 수 없고 네트워크 과부하로 큰 장애로 이어진다.
이 문제 해결 방법은 try ~ catch 문에서 finally 키워드를 사용하는 방법이 있다.
finally 추가하여 개선하기
try ~ catch문의 finally 키워드를 붙일 수 있는데, 이 것은 어떤 경우의 예외라도 마지막으로 호출시켜주는 기능을 제공한다.
NetworkService 클래스에서 finally 추가한 send 메소드는 다음과 같다.
NetworkService.class
public class NetworkService {
public void sendMessage(String data) throws NetworkClientException {
String address = "http://kiioio.com";
NetworkClient client = new NetworkClient(address);
client.initError(data); // 오류 코드로 반환.
try {
client.connect();
client.send(data);
} catch (NetworkClientException e) {
System.out.println("[Error] Code: " + e.getErrorCode() + ", Message: " + e.getMessage());
} finally {
client.disconnect();
}
}
private static boolean isError(String connectResult) {
return !connectResult.equals("success");
}
}
이제 Main 엔트리 포인트를 실행하면 올바르게 표시 되는 것을 살필 수 있다.
Send Message data: error1
[Error] Code: connectError, Message: Connect Open Failed
http://kiioio.com Connect Closed Success
Send Message data: error2
http://kiioio.com Connect Open Success
http://kiioio.com Connect Closed Success
Exception in thread "main" java.lang.RuntimeException: Send Failed
at NetworkClient.send(NetworkClient.java:23)
at NetworkService.sendMessage(NetworkService.java:10)
at Main.main(Main.java:15)
개선사항 체크
- 사용 후 반드시 disconnect() 호출하여 연결을 해제해주어야 한다. -> 해결
- 예외 처리 했으나 정상, 예외 흐름이 두 개가 생겨 가독성이 저하되었다 -> 해결