JDK 11(LTS) — JDK 8에서 무엇이 달라졌나: 모듈 시스템·var·표준 HTTP 클라이언트
JDK 11은 2018-09-25 GA한 LTS(장기 지원) 버전으로, JDK 8 다음 LTS입니다. 워낙 많은 서비스가 오래 8에 머물렀기에, 11은 "다음으로 올릴 첫 목적지"였습니다. 8 → 11 사이에는 세 버전(9·10·11)이 지나가며 모듈 시스템이라는 큰 변화와 실무에 바로 쓰는 편의 기능이 여럿 들어왔습니다. 이 글은 8에서 넘어올 때 무엇이 달라지는지, 그리고 이관에서 걸리는 지점까지 정리합니다.
8 → 11의 핵심은 모듈 시스템(JPMS) 의 도입과 함께, var·표준 HTTP 클라이언트·소스 파일 바로 실행 같은 실무 편의 기능이 정식으로 들어온 것 — 그리고 Java EE/CORBA 제거·라이선스 변화로 이관에 손이 가는 것입니다.1. 모듈 시스템 (JPMS, JEP 261 · JDK 9)
JDK 9의 가장 큰 변화입니다. 그동안 클래스패스에 JAR을 늘어놓기만 하면 됐지만, 모듈 시스템(Project Jigsaw) 은 코드 묶음의 의존성과 공개 범위를 명시하게 합니다. module-info.java로 "무엇을 필요로 하고(requires) 무엇을 공개하는지(exports)"를 선언합니다.
// module-info.java
module com.example.app {
requires java.net.http; // 표준 HTTP 클라이언트 모듈
exports com.example.app.api; // 이 패키지만 외부에 공개
}
- JDK 내부도 모듈로 쪼개졌고(
java.base등), 내부 API(sun.*) 접근이 제한되기 시작했습니다. - 다만 애플리케이션이 반드시 모듈을 써야 하는 건 아닙니다 — 모듈 선언 없이 클래스패스로 두면 이름 없는 모듈로 동작해 기존처럼 쓸 수 있습니다.
sun.*나 딥 리플렉션에 기대면 경고·오류가 난다.
2. var — 지역 변수 타입 추론 (JEP 286 · JDK 10)
지역 변수의 타입을 컴파일러가 추론해 var로 줄입니다. 타입이 사라지는 게 아니라(정적 타입 그대로), 우변에서 명확히 드러날 때 좌변 반복을 줄이는 것입니다.
var list = new ArrayList<String>(); // ArrayList<String>로 추론
var url = URI.create("https://…"); // URI
for (var entry : map.entrySet()) { … } // Map.Entry<K,V>
JDK 11에서는 람다 파라미터에도 var 를 쓸 수 있습니다(JEP 323 — 애너테이션을 붙이려는 경우 등에 유용).
3. 표준 HTTP 클라이언트 (JEP 321 · JDK 11)
낡은 HttpURLConnection을 대체하는 현대적 HTTP 클라이언트가 표준(java.net.http)으로 들어왔습니다(JDK 9 인큐베이터 → 11 정식). HTTP/2·비동기·CompletableFuture를 기본 지원합니다.
HttpClient client = HttpClient.newHttpClient();
HttpRequest req = HttpRequest.newBuilder(URI.create("https://api.example.com"))
.header("Accept", "application/json")
.build();
HttpResponse<String> res = client.send(req, HttpResponse.BodyHandlers.ofString());
// 비동기: client.sendAsync(req, ...).thenApply(HttpResponse::body)
외부 HTTP 라이브러리 없이 표준만으로 처리할 수 있는 경우가 늘어, 의존성을 줄이는 선택지가 생깁니다.
4. 소스 파일 바로 실행 + 편의 API (JEP 330 등)
컴파일 없이 단일 소스 파일을 바로 실행할 수 있습니다 — 스크립트·예제·학습에 편합니다.
java Hello.java # javac 없이 바로 실행 (JEP 330)
문자열·파일 편의 메서드도 늘었습니다.
" hi ".strip(); // "hi" (유니코드 공백까지, trim보다 정확)
" ".isBlank(); // true
"a\nb\nc".lines(); // Stream<String>
"ab".repeat(3); // "ababab"
Files.writeString(path, "내용"); // 파일 읽기/쓰기 한 줄
String text = Files.readString(path);
var·HTTP 클라이언트·문자열/파일 API는 곧바로 이득입니다.
5. 런타임·제거·라이선스
언어 기능 외에 런타임과 "빠진 것"이 이관 판단에 크게 작용합니다.
- G1 GC가 기본(JDK 9). 8의 기본이던 Parallel GC 대신 G1이 기본이 됩니다 — 지연에 민감한 서비스면 특성 차이를 확인해야 합니다.
- 실험적 GC 추가(JDK 11). 저지연 ZGC(JEP 333)와, 아무 일도 안 하는 Epsilon(JEP 318, 성능 테스트용)이 실험 기능으로 들어왔습니다.
- TLS 1.3(JEP 332), Flight Recorder 오픈소스화(JEP 328). 운영 프로파일링 도구 JFR을 OpenJDK에서도 무료로 쓰게 됐습니다.
- 제거된 것 — 이관 시 최우선 확인. Java EE·CORBA 모듈 제거(JEP 320)로
javax.xml.bind(JAXB)·javax.jws·CORBA 등이 JDK에서 빠졌습니다. 8에서 이들을 쓰던 코드는 외부 의존성으로 따로 추가해야 컴파일됩니다. Nashorn 자바스크립트 엔진도 이때 deprecated(이후 15에서 제거)됐습니다. - 라이선스 변화(실무 중요). JDK 11부터 Oracle JDK는 프로덕션 사용이 유료로 바뀌었고, 무료로 쓰려면 OpenJDK 빌드(Temurin·Corretto·Zulu 등)를 씁니다. 8에서 올릴 때 팀의 배포판·지원 정책을 함께 정해야 합니다.
정리 — 8에서 11로
- 바로 쓰는 것:
var(JEP 286), 표준 HTTP 클라이언트(321), 소스 파일 바로 실행(330), 문자열·파일 편의 API. - 큰 변화: 모듈 시스템(JPMS, 261) — 애플리케이션은 선택이지만 JDK 내부 API 제한은 영향을 준다.
- 이관 난관: Java EE·CORBA 제거(320)로 의존성 추가 필요, G1 기본화, Oracle JDK 유료화 → OpenJDK 배포판 선택.
- LTS라 지원이 길고, 8에서 넘어갈 실익이 큽니다. 다음 LTS는 JDK 17, 그다음이 21·25입니다.
var·HTTP 클라이언트 같은 실무 편의, 그리고 8 시대를 정리하고 넘어가는 LTS 기준점이라는 데 있습니다.