현재는 Oracle 사에서 Java를 인수하고 관리하고 있다.


자바의 버전 역사를 알아보자.
https://www.java.com/releases/
버전마다 타입이 다르다. 현재 사용 중인 타입들:
| 타입 | 설명 |
|---|---|
| Feature Release | Java SE 플랫폼 스펙이 바뀔 수 있는 버전. API 추가/deprecated/제거 가능. 6개월마다 나옴 |
| Patch Release | 치명적인 버그(보안 아님) 생겼을 때 비정기적으로 나오는 긴급 패치 |
| Security Alert (SA) | 보안 취약점 발견됐을 때 비정기적으로 나오는 긴급 보안 패치 |
| CPU Release | 모든 지원 버전에 동시에 보안 취약점 수정 + LTS 버전은 일반 유지보수도 포함 |
그리고 더 이상 안 쓰는 옛날 타입들:
| 타입 | 설명 |
|---|---|
| Major Release | JDK 9 이전에 쓰던 방식. 기능이 준비될 때까지 날짜를 미뤘음. JDK 10부터 날짜 기반으로 바뀌면서 Feature Release로 이름 변경 |
| Minor Release | 수정사항이 많거나 새 기능, 포트, OS 업그레이드 있을 때 |
| PSU Release | Patch Set Update. CPU랑 같은 날 나오는데 보안 수정 + 추가 기능 수정 포함 |
| Update Release | 버그 수정, 플랫폼/서드파티 업데이트 위주 |
| Security Release | 2008년 이전에 보안 취약점을 각 버전별로 따로 고치던 방식 |
| Emergency Release (ER) | 보안이든 아니든 비정기 긴급 릴리즈 |
| Performance Release | 성능 개선 집중 버전. 주로 HotSpot 업데이트 포함 |
2013년부터 Oracle CPU 스케줄에 맞춰서 릴리즈 날짜가 고정됐다.
즉 자바는 1년에 2번 새 버전이 나오는 구조이다.
문서에 나온 지원 기간 표를 보면:
LTS 버전들 (장기 지원)
| 버전 | 출시일 | 지원 종료 |
|---|---|---|
| Java 8 | 2014.03 | 2030.12 |
| Java 11 | 2018.09 | 2032.01 |
| Java 17 | 2021.09 | 2029.09 |
| Java 21 | 2023.09 | 2031.09 |
| Java 25 | 2025.09 | 2033.09 |
일반 버전들 (단기 지원)
Java 22 → 2024.03 출시, 2024.09 지원 종료 (6개월)
Java 23 → 2024.09 출시, 2025.03 지원 종료 (6개월)
Java 24 → 2025.03 출시, 2025.09 지원 종료 (6개월)
일반 버전은 딱 6개월만 지원하고 끝난다. 그래서 실무에서는 LTS만 쓴다.
Java 26 → 2026.03.17 출시 (이미 나옴)
Java 27 → 2026.09 예정
Java 28 → 2027.03 예정
Java 29 LTS → 2027.09 예정
LTS는 3버전마다 나오는 패턴 (17 → 21 → 25 → 29)
// module-info.java
module com.myapp {
requires java.sql; // 이 모듈 필요
exports com.myapp.api; // 이 패키지만 외부 공개
}
쉽게 말하면 패키지보다 더 큰 단위로 코드를 캡슐화하는 것. 내가 공개하고 싶은 패키지만 exports로 열어주고 나머지는 외부에서 접근 못 하게 막을 수 있음
// Java 8 이전 - 새 변수 선언해야 했음
Resource resource1 = new Resource("r1");
try (Resource r1 = resource1) { ... }
// Java 9 - 이미 있는 변수 그냥 쓰면 됨
Resource resource1 = new Resource("r1");
try (resource1) { ... }
interface MyInterface {
default void publicMethod() {
sharedLogic(); // private 메서드 공유 가능
}
private void sharedLogic() { // Java 9부터 가능
System.out.println("공통 로직");
}
}
int _ = 10; // Java 9부터 컴파일 에러
var (지역변수 타입 추론)
// 이전
HashMap<String, List<Integer>> map = new HashMap<>();
// Java 10부터
var map = new HashMap<String, List<Integer>>();
var list = new ArrayList<String>();
var number = 10;
타입을 컴파일러가 알아서 추론해준다. 지역변수에만 사용 가능
var를 람다 파라미터에도 사용 가능
// Java 11부터
var list = List.of(1, 2, 3);
list.forEach((var x) -> System.out.println(x));
// 이게 왜 유용하냐면 어노테이션 붙일 때
list.forEach((@NotNull var x) -> System.out.println(x));
Switch Expression (preview)
// 기존 switch - 이렇게 길었음
String result;
switch (day) {
case MONDAY:
result = "월요일";
break;
case TUESDAY:
result = "화요일";
break;
default:
result = "기타";
}
// Java 12 preview - 화살표 문법
String result = switch (day) {
case MONDAY -> "월요일";
case TUESDAY -> "화요일";
default -> "기타";
};
훨씬 짧아졌고 값을 바로 반환할 수 있게 됨
break로 값 반환하던 걸 yield 키워드로 바꿈String result = switch (day) {
case MONDAY -> "월요일";
default -> {
String s = day.toString();
yield s.toLowerCase(); // yield로 값 반환
}
};
// 이전 - 지저분함
String json = "{\n" +
" \"name\": \"홍길동\",\n" +
" \"age\": 30\n" +
"}";
// Java 13 preview - 깔끔함
String json = """
{
"name": "홍길동",
"age": 30
}
""";
여러 줄 문자열을 이스케이프 없이 그냥 쓸 수 있게 됨
Switch Expression 정식 출시
12, 13에서 preview였던 것이 정식 기능이 됨
instanceof Pattern Matching (preview)
// 이전 - 형변환을 두 번 해야 했음
if (obj instanceof String) {
String s = (String) obj; // 형변환 따로
System.out.println(s.length());
}
// Java 14 preview - 한 번에 처리
if (obj instanceof String s) {
System.out.println(s.length()); // s 바로 사용
}
// 이전 - DTO 클래스
public class Point {
private final int x;
private final int y;
public Point(int x, int y) { this.x = x; this.y = y; }
public int x() { return x; }
public int y() { return y; }
// equals, hashCode, toString 다 구현해야 함
}
// Java 14 preview - 한 줄로 끝
public record Point(int x, int y) {}
불변 데이터 객체를 간결하게 선언 가능하다. getter, equals, hashCode, toString 자동 생성
Text Blocks 정식 출시
13, 14에서 preview였던 것이 정식 기능이 됨
Sealed Classes (preview)
// 이 클래스를 상속할 수 있는 클래스를 딱 지정
public sealed class Shape
permits Circle, Rectangle, Triangle { }
public final class Circle extends Shape { }
public final class Rectangle extends Shape { }
// Triangle 외에 다른 클래스가 Shape 상속하면 컴파일 에러
상속 가능한 클래스를 제한할 수 있게 됨. 보안/설계 측면에서 유용
public record Point(int x, int y) {} // 이제 그냥 씀
if (obj instanceof String s) {
System.out.println(s.length()); // 정식 기능
}
public sealed class Shape permits Circle, Rectangle { }
// 정식 기능으로 확정
// instanceof + switch 합친 것
String result = switch (obj) {
case Integer i -> "정수: " + i;
case String s -> "문자열: " + s;
case null -> "null";
default -> "기타";
};
타입 체크 + 형변환 + switch를 한 번에 처리
언어 변경사항은 이게 전부. 나머지는 JVM, API 레벨 변경
when 절을 사용하는 방식으로 바뀜. switch 블록에 null 케이스 레이블이 없는데 null이 들어오면 NullPointerException 발생. 컴파일 타임엔 exhaustive하지만 런타임엔 아닌 경우 MatchException 발생.// when 절 추가된 모습
switch (obj) {
case Integer i when i > 0 -> "양수";
case Integer i -> "음수 또는 0";
}
record Point(int x, int y) {}
if (obj instanceof Point(int x, int y)) {
// x, y 바로 꺼내서 사용
}
Pattern Matching for switch 4차 preview
exhaustive switch에서 런타임에 일치하는 switch 레이블이 없으면 IncompatibleClassChangeError 대신 MatchException 발생하도록 변경. switch 레이블 문법도 단순화됨. 제네릭 Record 패턴의 타입 인자를 컴파일러가 추론 가능해짐.
Record Patterns 2차 preview
제네릭 Record 패턴의 타입 인자 추론 가능. Record 패턴을 enhanced for 문에서도 쓸 수 있게 됨. 명명된 Record 패턴은 제거됨.
// enhanced for에서 record 패턴 사용
for (Point(int x, int y) : points) {
System.out.println(x + ", " + y);
}
사실상 Java 21 LTS 준비 단계
Record Patterns 정식 출시
Java SE 19에서 preview 시작, 이번에 정식 기능이 됨. 단, enhanced for 문 헤더에서의 Record 패턴 지원은 제거됨.
Pattern Matching for switch 정식 출시
Java SE 17에서 preview 시작, 이번에 정식 기능이 됨. 괄호 패턴은 제거됨. switch 표현식과 문에서 한정된 enum 상수를 case 상수로 쓸 수 있게 됨.
// 완성된 모습
String result = switch (obj) {
case Integer i when i > 10 -> "큰 정수";
case Integer i -> "작은 정수";
case String s -> "문자열: " + s;
case null -> "null";
default -> "기타";
};
String name = "홍길동";
String msg = "안녕하세요, \{name}님";
// 안 쓰는 변수 _ 로 표시
if (obj instanceof Point(int x, _)) {
// y는 필요없을 때
}
// 클래스 선언 없이 main 바로 작성 (초보자 친화적)
void main() {
System.out.println("Hello World");
}
Unnamed Variables & Patterns 정식 출시
Java SE 21에서 preview, 이번에 정식 기능. Java SE 21과 내용 동일.
Statements Before super(...) preview 시작
생성자에서 명시적 생성자 호출 전에 인스턴스를 참조하지 않는 문장들을 추가할 수 있게 됨.
class Child extends Parent {
Child(int value) {
// Java 22 이전엔 여기에 아무것도 못 씀
int adjusted = Math.abs(value); // 이제 가능
super(adjusted);
}
}
String Templates 2차 preview
21에서 preview였던 것 계속 다듬는 중
Implicitly Declared Classes and Instance Main Methods 2차 preview
명시적 클래스 선언 없이 선언된 클래스를 "암묵적으로 선언된 클래스"라고 부르게 됨. main 메서드 선택 절차도 단순화됨.
// 기존엔 int같은 기본형을 패턴에 못 씀
// Java 23부터 가능
switch (value) {
case int i when i > 0 -> "양수";
case int i -> "음수";
case double d -> "실수";
}
// 이전 - 하나하나 import
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
// Java 23 - 모듈 통째로 import
import module java.base;
String Templates 결국 폐기
JDK 21에서 preview, JDK 22에서 재preview됐지만 현재 형태로는 적합하지 않다는 결론. 더 나은 설계에 대한 합의가 없어서 기능 자체를 철회. JDK 23에 포함되지 않음.
Flexible Constructor Bodies 2차 preview
생성자 유연성 계속 다듬는 중
Primitive Types in Patterns 2차 preview
Java SE 23과 동일하게 유지, 변경 없음.
Module Import Declarations 2차 preview
타입 import-on-demand 선언이 모듈 import 선언보다 우선순위가 높아짐. java.se 모듈이 java.base를 transitively require하게 돼서 java.se 모듈 import 시 Java SE API 전체를 import하게 됨.
Flexible Constructor Bodies 3차 preview
계속 다듬는 중
Module Import Declarations 정식 출시
Java SE 23에서 preview 시작, 이번에 변경 없이 정식 기능이 됨.
Compact Source Files and Instance Main Methods 정식 출시
Java SE 21에서 preview 시작, 이번에 정식 기능이 됨. IO 클래스가 java.io 패키지 대신 java.lang 패키지로 이동해서 모든 소스 파일에서 암묵적으로 import됨. IO 클래스의 static 메서드는 더 이상 compact 소스 파일에 암묵적으로 import되지 않아서 IO.println("Hello") 처럼 명시적으로 호출해야 함.
Flexible Constructor Bodies 정식 출시
Java SE 22에서 preview 시작, 이번에 정식 기능이 됨. 변경 없음.
Primitive Types in Patterns 3차 preview
계속 다듬는 중
아직 다듬는 중
Java 8은 현대 자바의 시작점이라 불릴 만큼 변화가 컸다.
// 이전
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println("실행");
}
};
// Java 8
Runnable r = () -> System.out.println("실행");
// 이전
List<String> result = new ArrayList<>();
for (String s : list) {
if (s.startsWith("A")) {
result.add(s.toUpperCase());
}
}
// Java 8
List<String> result = list.stream()
.filter(s -> s.startsWith("A"))
.map(String::toUpperCase)
.collect(Collectors.toList());
// null 처리를 명시적으로
Optional<String> name = Optional.ofNullable(getName());
name.ifPresent(n -> System.out.println(n));
String result = name.orElse("이름 없음");
// 이전 Date, Calendar는 쓰기 불편하고 버그 많았음
// Java 8부터
LocalDate today = LocalDate.now();
LocalDateTime now = LocalDateTime.now();
Duration duration = Duration.between(start, end);
interface MyInterface {
default void hello() {
System.out.println("기본 구현");
}
}
Function<String, Integer> len = s -> s.length();
Predicate<String> isEmpty = s -> s.isEmpty();
Consumer<String> print = s -> System.out.println(s);
Supplier<String> hello = () -> "Hello";
Java 8 (2014) LTS ⭐ → Lambda, Stream, Optional
현대 자바의 시작점
Java 9 (2017) → 모듈 시스템 (대형 변화)
Java 10 (2018) → var 추가
Java 11 (2018) LTS → var 람다에도 적용
Java 12 (2019) → switch 표현식 preview 시작
Java 13 (2019) → Text Block preview 시작
Java 14 (2020) → Record, instanceof 패턴매칭 preview 시작
Java 15 (2020) → Sealed Class preview 시작
Java 16 (2021) → Record, instanceof 패턴매칭 정식
Java 17 (2021) LTS ⭐→ Sealed Class 정식
switch 패턴매칭 preview 시작
Java 18 (2022) → switch 패턴매칭 계속 다듬기
Java 19 (2022) → Virtual Threads preview, Record Patterns preview
Java 20 (2023) → 21 준비 단계
Java 21 (2023) LTS ⭐→ Virtual Threads, Record Patterns,
switch 패턴매칭 전부 정식
Java 22 (2024) → super() 전 statements preview
Java 23 (2024) → 기본형 패턴매칭 preview, String Templates 폐기
Java 24 (2025) → 소소한 개선
Java 25 (2025) LTS ⭐→ 최신 LTS, 모듈 import 정식
Java 26 (2026) → 현재 최신 버전 (일반)