
예외 처리에서 시작해 데이터베이스까지, 한 시즌을 다 돌았습니다.
11편을 마치면서 자바로 혼자 돌아가는 프로그램을 넘어 파일을 남기고, 동시에 일을 시키고, 다른 프로그램과 이야기하고, 데이터베이스까지 다루게 됐습니다. 이번 편은 새 개념 없이 JAVA3 시즌 전체를 점검합니다. 개념을 퀴즈로 확인한 뒤, 직접 코드를 고쳐 실행하는 실습 문제를 풉니다.
한눈에 보는 JAVA3 시즌
| 편 | 핵심 | 대표 함정 |
|---|---|---|
| 1. 예외 처리 | try·catch로 죽지 않게 | finally를 안 쓰고 자원 방치 |
| 2. 다중 catch·던지기 | 예외마다 다르게 대응 | 넓은 예외를 먼저 잡기 |
| 3. 제네릭 | 담을 타입을 나중에 지정 | 타입 없이 쓰고 형변환 |
| 4. 컬렉션 | List·Set·Map | Set에 중복 넣고 기대하기 |
| 5. 래퍼·날짜 | 기본형을 객체로 | ==로 객체 값 비교 |
| 6. 파일 입출력 | 껐다 켜도 남기기 | flush·close 누락 |
| 7. 스레드 | 여러 일을 동시에 | 공유 값 동시 수정 |
| 8. 소켓 | 두 프로그램 연결 | 서버를 나중에 켜기 |
| 9. 채팅 | 소켓 + 스레드 | 한 스레드로 만들기 |
| 10. JDBC | DB에 말 걸기 | 문자열로 SQL 조립 |
| 11. 트랜잭션 | 전부 성공 또는 전부 취소 | 자동 커밋을 안 끄기 |

그림 1. catch 순서·flush·닫는 순서·SQL 조립·자동 커밋 — 이 다섯이 단골입니다.
1단계 — 개념 빠른 점검
먼저 개념을 퀴즈로 확인합니다. 해설에 몇 편 내용인지 적어 두었으니, 막히는 부분은 그 편으로 돌아가 보세요. 정답은 눌러야 나옵니다.
미니 퀴즈
2단계 — 직접 풀어 보기
이제 눈으로 읽는 대신 직접 고쳐 실행해 봅니다. 편집기에서 코드를 바꿔 돌려 보고, 아래 '정답 보기'로 확인하세요.
문제 1. 실행 순서 예측하기 (예외)
돌리기 전에 무엇이 어떤 순서로 찍힐지 예측해 보세요.
public class Main {
public static void main(String[] args) {
try {
System.out.println("A");
int x = 10 / 0;
System.out.println("B");
} catch (ArithmeticException e) {
System.out.println("C");
} finally {
System.out.println("D");
}
System.out.println("E");
}
}📱 코드 실행(실습)은 태블릿·PC에서 이용할 수 있어요. 모바일에서는 위 코드를 눈으로 따라가며 확인하세요.
정답 보기
A / C / D / E 입니다. 10 / 0에서 예외가 나는 순간 B는 건너뛰고 곧바로 catch로 갑니다. finally는 예외 여부와 상관없이 실행되므로 D가 찍히고, catch에서 예외를 처리했으니 프로그램은 죽지 않고 E까지 갑니다.
문제 2. catch 순서 고치기
지금 코드는 컴파일되지 않습니다. catch 두 개의 순서를 바꿔 정상 실행되게 만드세요.
public class Main {
public static void main(String[] args) {
try {
String s = null;
System.out.println(s.length());
} catch (Exception e) {
System.out.println("넓은 예외");
} catch (NullPointerException e) {
System.out.println("널 포인터");
}
}
}📱 코드 실행(실습)은 태블릿·PC에서 이용할 수 있어요. 모바일에서는 위 코드를 눈으로 따라가며 확인하세요.
정답 보기
NullPointerException catch를 위로 올리면 됩니다. Exception은 모든 예외의 부모라 먼저 두면 뒤의 catch에 도달할 방법이 없어 "이미 잡힌 예외" 오류가 납니다. 좁은 것부터 넓은 것 순서가 원칙입니다. 고치면 널 포인터가 출력됩니다.
문제 3. 컬렉션 결과 예측하기
List와 Set에 같은 값을 넣었습니다. 크기가 어떻게 나올까요.
import java.util.*;
public class Main {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
Set<String> set = new HashSet<>();
String[] data = {"사과", "바나나", "사과"};
for (String d : data) {
list.add(d);
set.add(d);
}
System.out.println("List 크기: " + list.size());
System.out.println("Set 크기: " + set.size());
Map<String, Integer> price = new HashMap<>();
price.put("사과", 1000);
price.put("사과", 1500);
System.out.println("사과 값: " + price.get("사과"));
}
}📱 코드 실행(실습)은 태블릿·PC에서 이용할 수 있어요. 모바일에서는 위 코드를 눈으로 따라가며 확인하세요.
정답 보기
List 3 / Set 2 / 사과 값 1500 입니다. List는 중복을 그대로 담고, Set은 같은 값을 한 번만 저장합니다. Map은 같은 키로 다시 넣으면 덮어쓰기가 되어 마지막 값만 남습니다.
문제 4. 제네릭 채우기
Box 클래스가 타입에 상관없이 값을 담도록 빈칸을 채우세요. 지금은 컴파일 오류가 납니다.
class Box<T> {
private T item;
public void set(T item) { this.item = item; }
public T get() { return item; }
}
public class Main {
public static void main(String[] args) {
// 아래 빈칸에 타입을 넣어 완성하세요 (문자열을 담습니다)
Box<Object> b = new Box<>();
b.set("포켓코딩");
String s = (String) b.get(); // 제대로 고치면 이 형변환이 필요 없습니다
System.out.println(s);
}
}📱 코드 실행(실습)은 태블릿·PC에서 이용할 수 있어요. 모바일에서는 위 코드를 눈으로 따라가며 확인하세요.
정답 보기
Box<String> b = new Box<>(); 로 바꾸고, 마지막 줄을 String s = b.get(); 으로 고치면 됩니다. 타입을 지정해 두면 꺼낼 때 형변환이 필요 없고, 실수로 다른 타입을 넣으면 실행 전에 오류가 잡힙니다. 이것이 제네릭을 쓰는 이유입니다.
문제 5. 롤백 흉내 내기
실제 DB는 브라우저에서 돌릴 수 없으니, 전부 성공하거나 전부 되돌리는 흐름만 코드로 확인합니다. 실행해 보고 fail 값을 false로 바꿔 다시 돌려 보세요.
public class Main {
static int myMoney = 10000;
static int friendMoney = 0;
public static void main(String[] args) {
boolean fail = true; // false로 바꿔 다시 실행해 보세요
int backupMe = myMoney; // 시작 상태를 기억 (트랜잭션 시작)
int backupFriend = friendMoney;
try {
myMoney -= 10000; // 출금
if (fail) throw new RuntimeException("입금 중 오류");
friendMoney += 10000; // 입금
System.out.println("커밋 — 이체 완료");
} catch (Exception e) {
myMoney = backupMe; // 롤백
friendMoney = backupFriend;
System.out.println("롤백 — " + e.getMessage());
}
System.out.println("내 잔액: " + myMoney);
System.out.println("친구 잔액: " + friendMoney);
}
}📱 코드 실행(실습)은 태블릿·PC에서 이용할 수 있어요. 모바일에서는 위 코드를 눈으로 따라가며 확인하세요.
정답 보기
fail이 true면 출금까지 갔다가 예외가 나고, catch에서 시작 상태로 되돌려 잔액이 그대로 남습니다. false로 바꾸면 두 작업이 모두 끝나 10,000원이 이동합니다. 11편의 conn.rollback()이 하는 일이 바로 이것입니다. 다만 실제 DB에서는 이렇게 백업 변수를 직접 만들 필요 없이 setAutoCommit(false) 하나로 같은 보호를 받습니다.
이것만 기억하면 됩니다
JAVA3에서 자주 막히는 다섯 가지를 다시 짚습니다.
- catch 순서: 좁은 예외부터,
Exception은 맨 마지막(2편). - flush 누락: 버퍼에 고이면 상대는 아무것도 못 받습니다(6·8·9편).
- 닫는 순서: 만든 반대 순서로,
finally에서(6·10편). - SQL 조립: 문자열로 잇지 말고 물음표에 값으로 채우기(10편).
- 자동 커밋: 끄지 않으면 되돌릴 것이 남지 않습니다(11편).
12문제 중 9개 이상 맞고 실습 문제를 스스로 고쳤다면, 자바 심화 과정은 충분히 소화한 것입니다. 헷갈린 부분만 해당 편으로 돌아가 다시 보면 됩니다. 여기까지 오시느라 수고 많으셨습니다.
포켓코딩(JAVA3) 12편 · 예제 출처: 강사 개인 GitHub 저장소. JAVA3 시즌은 이 편으로 마무리합니다.