package exception.ex2;
public class NetworkClientExceptionV2 extends Exception {
private String errorCode;
public NetworkClientExceptionV2(String errorCode, String message) {
super(message);
this.errorCode = errorCode;
}
public String getErrorCode() {
return errorCode;
}
}
package exception.ex2;
public class NetworkClientV2 {
private final String address;
public boolean connectError;
public boolean sendError;
public NetworkClientV2(String address) {
this.address = address;
}
public void connect() throws NetworkClientExceptionV2 {
if (connectError) {
throw new NetworkClientExceptionV2("connectError", address +
" 서버 연결 실패");
}
//연결 성공
System.out.println(address + " 서버 연결 성공");
}
public void send(String data) throws NetworkClientExceptionV2 {
if (sendError) {
throw new NetworkClientExceptionV2("sendError", 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;
}
}
}
throw
를 통해 던진다.package exception.ex2;
public class NetworkServiceV2_1 {
public void sendMessage(String data) throws NetworkClientExceptionV2 {
String address = "http://example.com";
NetworkClientV2 client = new NetworkClientV2(address);
client.initError(data);
client.connect();
client.send(data);
client.disconnect();
}
}
throws
를 통해 밖으로 던진다.package exception.ex2;
import java.util.Scanner;
public class MainV2 {
public static void main(String[] args) throws NetworkClientExceptionV2 {
NetworkServiceV2_1 networkService = new NetworkServiceV2_1();
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("프로그램을 정상 종료합니다.");
}
}
throws
를 통해 밖으로 던진다.disconnect()
호출이 안되는 문제가 남아있다.package exception.ex2;
public class NetworkServiceV2_4 {
public void sendMessage(String data) {
String address = "http://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());
}
//NetworkClientException이 아닌 다른 예외가 발생해서 예외가 밖으로 던져지면 무시
client.disconnect();
}
}
client.disconnect()
를 호출하여 예외가 처리되면 항상 client.disconnect()
가 호출된다.NetworkClientExceptionV2
가 아닌 다른 오류가 생기면 client.disconnect()
가 호출되지 않는다.try {
//정상 흐름
} catch {
//예외 흐름
} finally {
//반드시 호출해야 하는 마무리 흐름
}
try~catch~finally
구조는 정상 흐름, 예외 흐름, 마무리 흐름을 제공한다.try
를 시작하기만 하면, finally
코드 블럭은 어떤 경우라도 반드시 호출된다.try,catch
안에서 잡을 수 없는 예외가 발생해도 finally
는 반드시 호출된다.finally
블럭은 반드시 호출되어 주로 try
에서 사용한 자원을 해제할 때 주로 사용한다.
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();
}
}
}
try~catch
안에서 처리할 수 없는 예외가 발생해도 finally
는 반드시 호출된다.NetworkClientExceptionV2
에서 RuntimeException
으로 오류가 변경되면 try~catch
로 잡지 못해 오류가 발생할텐데그럼에도 finally
블럭의 코드는 실행된다.catch
에서 잡을 수 없는 예외가 발생해서, 예외를 밖으로 던지는 경우에도 finally
를 먼저 호출하고서 예외를 밖으로 던진다.다음과 같이 catch
없이 try~finally
만 사용할 수 있다.
try {
client.connect();
client.send(data);
} finally {
client.disconnect();
}
예외를 오류 코드로 분류하는 것이 아니라, 예외를 계층화해서 다양하게 만들면 더 세밀하게 예외를 처리 할 수 있다.
package exception.ex3.exception;
public class NetworkClientExceptionV3 extends Exception {
public NetworkClientExceptionV3(String message) {
super(message);
}
}
package exception.ex3.exception;
public class ConnectExceptionV3 extends NetworkClientExceptionV3 {
private final String address;
public ConnectExceptionV3(String address, String message) {
super(message);
this.address = address;
}
public String getAddress() {
return address;
}
}
package exception.ex3.exception;
public class SendExceptionV3 extends NetworkClientExceptionV3 {
private final String sendData;
public SendExceptionV3(String sendData, String message) {
super(message);
this.sendData = sendData;
}
public String getSendData() {
return sendData;
}
}
NetworkClientExceptionV3
를 상속받아 2개의 자식 예외를 만들었다.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;
}
}
}
getAddress()
getSendData()
와 같이 예외 클래스가 가지는 고유의 기능을 활용할 수 있다.아래와 같이 |
를 사용해서 여러 예외를 한번에 잡을 수 있다.
try {
client.connect();
client.send(data);
} catch (ConnectExceptionV3 | SendExceptionV3 e) {
System.out.println("[연결 또는 전송 오류] 주소: , 메시지: " + e.getMessage());
} finally {
client.disconnect();
}
애플리케이션에서 외부 자원을 사용하는 경우 반드시 외부 자원을 해제해야한다.
따라서 finally
구문을 반드시 사용해야한다.
try
에서 외부 자원을 사용하고 try
가 끝나면 외부 자원을 반납하는 패턴이 반복되면서 Try with resource라는 편의 기능을 자바에서 도입했다.
AutoCloseable
인터페이스를 구현해야 한다.close()
: AutoCloseable
인터페이스가 제공하는 이 메서드는 try
가 끝나면 자동으로 호출된다. 종료 시점에 자원을 반납하는 방법을 여기에 정의하면 된다. 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 resource
구문은 try
안에 사용할 자원을 명시한다.