Text Blocks (Preview)
Java 13에서 가장 기다려진 기능은 텍스트 블록(JEP 355)입니다. 여러 줄 문자열을 작성할 때 \n과 + 연결 지옥에서 벗어날 수 있습니다.
이메일 템플릿을 떠올리면 됩니다. 기존에는 편지 한 줄마다 풀칠해서 붙이는 느낌이었다면, 텍스트 블록은 편지지 한 장에 자연스럽게 쓰는 느낌입니다.
기본 사용법
public class TextBlockBasic {
public static void main(String[] args) {
// === 기존 방식: 이스케이프와 연결 연산자의 지옥 ===
String jsonOld = "{\n" +
" \"name\": \"홍길동\",\n" +
" \"age\": 30,\n" +
" \"city\": \"서울\"\n" +
"}";
// === 텍스트 블록: 보이는 그대로 저장 ===
String jsonNew = """
{
"name": "홍길동",
"age": 30,
"city": "서울"
}
""";
System.out.println("기존 방식:");
System.out.println(jsonOld);
System.out.println();
System.out.println("텍스트 블록:");
System.out.println(jsonNew);
System.out.println("두 문자열 동일? " + jsonOld.equals(jsonNew.strip()));
// 출력:
// 기존 방식:
// {
// "name": "홍길동",
// "age": 30,
// "city": "서울"
// }
//
// 텍스트 블록:
// {
// "name": "홍길동",
// "age": 30,
// "city": "서울"
// }
//
// 두 문자열 동일? true
}
}
텍스트 블록은 """(따옴표 세 개)로 시작하고 끝납니다. 시작 """ 뒤에는 반드시 줄바꿈이 와야 합니다. 들여쓰기는 닫는 """의 위치를 기준으로 자동 정렬됩니다.
들여쓰기 제어
텍스트 블록의 들여쓰기는 **공통 선행 공백(common leading whitespace)**이 자동 제거되는 규칙을 따릅니다. 닫는 """의 위치가 기준선입니다.
public class TextBlockIndent {
public static void main(String[] args) {
// 닫는 """를 왼쪽으로 옮기면 들여쓰기가 유지됨
String html = """
<html>
<body>
<p>들여쓰기 없음</p>
</body>
</html>
""";
// 닫는 """를 오른쪽으로 옮기면 상대적 들여쓰기 적용
String htmlIndented = """
<html>
<body>
<p>4칸 들여쓰기</p>
</body>
</html>
""";
System.out.println("들여쓰기 없음:");
System.out.println(html);
System.out.println("들여쓰기 적용:");
System.out.println(htmlIndented);
// 출력:
// 들여쓰기 없음:
// <html>
// <body>
// <p>들여쓰기 없음</p>
// </body>
// </html>
//
// 들여쓰기 적용:
// <html>
// <body>
// <p>4칸 들여쓰기</p>
// </body>
// </html>
}
}
Switch Expressions 개선 — yield 키워드
Java 12에서 프리뷰로 도입된 Switch Expressions가 Java 13에서 한 단계 개선되었습니다(JEP 354). 핵심 변경은 yield 키워드의 도입입니다.
화살표(→) 문법은 단일 표현식을 반환하기에 적합하지만, 블록 내에서 복잡한 로직 후 값을 반환할 때는 yield를 사용합니다.
public class SwitchYieldDemo {
public static void main(String[] args) {
String day = "WEDNESDAY";
// === 화살표 문법: 단순 값 반환 ===
int letters = switch (day) {
case "MONDAY", "FRIDAY", "SUNDAY" -> 6;
case "TUESDAY" -> 7;
case "WEDNESDAY", "THURSDAY", "SATURDAY" -> {
// 블록이 필요한 경우 yield로 값 반환
System.out.println(day + " 처리 중...");
yield day.length();
}
default -> throw new IllegalArgumentException("알 수 없는 요일: " + day);
};
System.out.println(day + " → " + letters + "글자");
// === 콜론(:) 문법에서도 yield 사용 가능 ===
String season = switch (day) {
case "MONDAY":
case "TUESDAY":
yield "평일 초반";
case "WEDNESDAY":
yield "주 중간";
case "THURSDAY":
case "FRIDAY":
yield "평일 후반";
default:
yield "주말";
};
System.out.println(day + " → " + season);
// 출력:
// WEDNESDAY 처리 중...
// WEDNESDAY → 9글자
// WEDNESDAY → 주 중간
}
}
yield는 switch 표현식 전용 키워드입니다. break가 값을 반환하던 Java 12의 방식(break value;)을 대체합니다. 이 변경으로 break는 루프 제어, yield는 switch 값 반환이라는 명확한 역할 분리가 이루어졌습니다.
ZGC 메모리 반환 (JEP 351)
ZGC(Z Garbage Collector)는 Java 11에서 실험적으로 도입된 저지연 GC입니다. Java 13에서는 미사용 힙 메모리를 OS에 반환하는 기능이 추가되었습니다.
이전에는 ZGC가 한 번 확보한 메모리를 계속 들고 있었습니다. 트래픽 급증 후 메모리가 원래 수준으로 돌아오지 않아 컨테이너 환경에서 비효율적이었습니다.
# ZGC 활성화 및 메모리 반환 설정
java -XX:+UnlockExperimentalVMOptions \
-XX:+UseZGC \
-XX:ZUncommitDelay=300 \
-jar your-app.jar
# ZUncommitDelay: 미사용 메모리 반환까지 대기 시간 (초, 기본 300)
| 환경 | 기대 효과 |
|---|---|
| 쿠버네티스 Pod | 트래픽 감소 시 메모리 반환 → 클러스터 자원 절약 |
| 공유 서버 | 유휴 애플리케이션의 메모리 회수 |
| 개발 환경 | 여러 JVM 프로세스의 메모리 사용량 감소 |
Socket API 재구현 (JEP 353)
java.net.Socket과 java.net.ServerSocket의 내부 구현이 NioSocketImpl로 교체되었습니다. 기존 구현(PlainSocketImpl)은 JDK 1.0 시절부터 이어져 온 레거시 코드였습니다.
외부 API는 동일하므로 기존 코드 변경은 필요 없습니다. 내부적으로 NIO 기반으로 전환되어 유지보수성이 향상되고, 이후 Virtual Thread(Java 21)와의 통합 기반이 마련되었습니다.
Dynamic CDS Archives (JEP 350)
**CDS(Class Data Sharing)**는 JVM 시작 시간을 줄이는 기술입니다. 클래스 메타데이터를 공유 아카이브에 미리 저장해두고, 다음 실행 시 재활용합니다.
Java 13에서는 애플리케이션 종료 시점에 자동으로 CDS 아카이브를 생성할 수 있게 되었습니다. 이전에는 별도의 trial run이 필요했습니다.
# 1단계: 애플리케이션 실행하면서 CDS 아카이브 자동 생성
java -XX:ArchiveClassesAtExit=app-cds.jsa -jar your-app.jar
# 2단계: 다음 실행부터 아카이브 활용 → 시작 시간 단축
java -XX:SharedArchiveFile=app-cds.jsa -jar your-app.jar
마이크로서비스 환경에서 수십 개 인스턴스가 동시에 시작하는 경우, CDS로 시작 시간을 20~30% 단축할 수 있습니다.
실전 팁
| 기능 | 활용 포인트 |
|---|---|
| Text Blocks | JSON, HTML, SQL 등 여러 줄 문자열에 즉시 적용 |
| yield | switch 블록 내 복잡한 로직이 있을 때 사용 |
| ZGC 메모리 반환 | 컨테이너 환경에서 메모리 효율 개선 |
| Dynamic CDS | 마이크로서비스 시작 시간 최적화 |
| NioSocketImpl | 코드 변경 없이 자동 적용 (Java 13+ 사용 시) |
Java 13은 “큰 변화”보다는 기존 기능의 성숙에 초점을 맞춘 릴리스입니다. Text Blocks는 이후 Java 15에서 정식 확정되고, Switch Expressions의 yield 키워드는 Java 14에서 정식으로 굳어집니다. 이 시기의 프리뷰 기능들이 모두 Java 14~15에서 정식이 되므로, Java 13은 “전환기의 다리” 역할을 한 버전입니다.