[JAVA] JDK 11에서 JDK 21로 변경하기 (LTS버전)
Overview
SpringBoot 버전을 2.x에서 3.x로 변경하면서 JDK도 최신버전인 21로 변경하게되었습니다.
JDK LTS 버전 | End Of Support Life |
21 | 2031년 9월 |
17 | 2029년 9월 |
11 | |
8 | 2030년 12월 |
1. JDK 설치
2. Maven Java version 변경
<properties>
<java.version>21</java.version>
</properties>
3. IntelliJ Project Settings
[Ctrl+Shift+Alt] Project Strucature > Project Settings < Project, Modules
만약 build 실패 중 아래와 같은 에러가 발생한다면, Settings > Build, Execution, Deployment > Build Tools > Maven 에서 Maven home path를 Bundled (Maven 3)로 설정해주시면됩니다.
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.13.0:compile (default-compile) on project: The plugin org.apache.maven.plugins:maven-compiler-plugin:3.13.0 requires Maven version 3.6.3 -> [Help 1]
4. Java EE 에서 Jakarta EE로 마이그레이션
인텔리제이에서는 Java EE에서 Jakarta EE로 패키지 변경을 도와주는 마이그레이션 기능이 존재합니다.
Refactor > Migrate Packages and Classes > Java EE to Jakarta EE
5. JDK 문법 변경
5.1. JDK 12
5.1.1. Switch문 확장
// 이전 버전
switch (day) {
case MONDAY:
case FRIDAY:
case SUNDAY:
System.out.println(6);
break;
case TUESDAY:
System.out.println(7);
break;
case THURSDAY:
case SATURDAY:
System.out.println(8);
break;
case WEDNESDAY:
System.out.println(9);
break;
}
// JDK 12 ~
switch (day) {
case MONDAY, FRIDAY, SUNDAY -> System.out.println(6);
case TUESDAY -> System.out.println(7);
case THURSDAY, SATURDAY -> System.out.println(8);
case WEDNESDAY -> System.out.println(9);
}
문법적으로 Switch문이 확장됐을 뿐, 이전버전도 사용이 가능합니다.
5.1.2. Compact Number Formatting
NumberFormat format = NumberFormat.getCompactNumberInstance(Locale.US, Style.SHORT);
String formatted = format.format(1000);
System.out.println(formatted); // 출력: 1K
5.2. JDK 13
5.2.1. Text Blocks (Multi-line String literals) 추가 (Preview)
String multiLine = """
This
is a
multi-line
string
""";
System.out.println(multiLine);
5.2.2. Switch문 향상 (Preview)
Switch문이 값을 반환할 수 있도록 yield 키워드가 추가되었습니다.
var a = switch (day) {
case MONDAY, FRIDAY, SUNDAY:
yield 6;
case TUESDAY:
yield 7;
case THURSDAY, SATURDAY:
yield 8;
case WEDNESDAY:
yield 9;
};
5.3. JDK 14
5.3.1. Instanceof 패턴 매칭 추가 (Preview)
// 이전 버전
if (obj instanceof String) {
String s = (String) obj;
System.out.println(s.contains("moonsiri"));
}
// JDK 14 ~
if (obj instanceof String s) {
System.out.println(s.contains("moonsiri"));
}
5.3.2. record 타입 지원 (Preview)
Record 클래스는 기본적으로 생성자, 접근자, equals(), hashCode(), toString()과 같은 메서드를 제공합니다.
final class Point {
public final int x;
public final int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
}
// 레코드 사용 시
record Point(int x, int y) { }
5.3.3. NullPointerExceptions 개선
정확히 어떤 변수가 null인지 자세히 나타냅니다.
Intellij 기준 VM Options에 -XX:+ShowCodeDetailsInExceptionMessages을 추가해주면 됩니다.
author.age = 35;
---
Exception in thread *"main"* java.lang.NullPointerException:
Cannot assign field *"age"* because *"author"* is null
5.3.4. 12, 13에서 Preview로 제공되었던 스위치 표현식이 표준화(Standard) 됨
5.4. JDK 15
5.4.1. Sealed 클래스 및 인터페이스 추가 (Preview)
특정한 하위 클래스 및 구현 클래스를 제한하고 제어하는데 사용합니다.
public sealed interface Shape permits Circle, Rectangle, Triangle {
// interface body
}
public final class Circle implements Shape {
// class body
}
자식 클래스는 sealed, final, non-sealed 세 종류로 나뉩니다.
- sealed : 자식도 마찬가지로 상속받을 서브 클래스를 명시할 수 있다.
- final : 더 이상 확장할 수 없다.
- non-sealed : 모든 서브 클래스들에 의해 확장될 수 있다.
5.4.2. Text Blocks에서 내용의 Trim 및 공백 제거
String trimmed = """
This is
a text block
""".trim();
System.out.println(trimmed);
5.5. JDK 16
OpenJDK의 버전 관리가 Mercurial에서 Git으로 변경되었습니다.
5.6. JDK 17 (LTS)
5.6.1. Sealed 클래스 개선
public abstract sealed class Shape permits Circle, Rectangle {
// Shape 클래스 내용
}
public final class Circle extends Shape {
// Circle 클래스 내용
}
public final class Rectangle extends Shape {
// Rectangle 클래스 내용
}
5.6.2. Pattern Matching for Switch (Preview)
// 이전버전
public String formatter(Object o) {
String formatted = "unknown";
if (o instanceof Integer i) {
formatted = String.format("int %d", i);
} else if (o instanceof Long l) {
formatted = String.format("long %d", l);
} else if (o instanceof Double d) {
formatted = String.format("double %f", d);
} else if (o instanceof String s) {
formatted = String.format("String %s", s);
}
return formatted;
}
// JDK 17 ~
public String formatterPatternSwitch(Object o) {
return switch (o) {
case Integer i -> String.format("int %d", i);
case Long l -> String.format("long %d", l);
case Double d -> String.format("double %f", d);
case String s -> String.format("String %s", s);
default -> o.toString();
};
}
5.7. JDK 18
자바 API의 기본 Charset이 UTF-8로 지정되었습니다.
Java API Doc에 @snippet 태그가 도입되었습니다.
try문의 finally 기능이 deprecate 되었습니다. (사용을 권장하지 않음. try-with-resources를 이용.)
5.8. JDK 19, JDK 20
5.8.1. Record Patterns (Preview)
record Point(int x, int y) {}
// 이전 버전
static void printSum(Object o) {
if (o instanceof Point p) {
int x = p.x();
int y = p.y();
System.out.println(x+y);
}
}
// JDK 19 ~
void printSum(Object o) {
if (o instanceof Point(int x, int y)) {
System.out.println(x+y);
}
}
5.8.2. Virtual Threads (Preview)
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
IntStream.range(0, 10_000).forEach(i -> {
executor.submit(() -> {
Thread.sleep(Duration.ofSeconds(1));
return i;
});
});
} // executor.close() is called implicitly, and waits
5.9. JDK 21 (LTS)
5.9.1. Virtaul Threads가 표준화 되었습니다.
5.9.2. 순차 컬렉션 (Sequenced Collections)
interface SequencedCollection<E> extends Collection<E> {
// new method
SequencedCollection<E> reversed();
// methods promoted from Deque
void addFirst(E);
void addLast(E);
E getFirst();
E getLast();
E removeFirst();
E removeLast();
}
5.9.3. Unnamed Patterns and Variables (Preview)
// 이전 버전
int total = 0;
for (Order order : orders) {
// 사실상 사용되지 않는 order
if (total < LIMIT) {
total++
}
}
// JDK 21 ~
int total = 0;
for (Order _ : orders) {
if (total < LIMIT) {
total++
}
}
5.9.4. Unnamed Classes and Instance Main Methods (Preview)
// 이전 버전
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
// JDK 21 ~
void main() {
System.out.println("Hello, World!");
}
[Reference]