= Java =
{{tag> java programming jvm language }}
= Java 9부터 변경점 =
== 9 ==
* Java Platform **Module** System(JPMS) -> 라이브러리 만들때 제외하고는 사용이 드물다
* 확장된 try-with-resources -> try 밖 지역변수도 사용 가능
* @SafeVarargs를 private 메소드에서도 사용 가능
* 익명 Inner Class에도 diamon syntax(Generic 타입 명시 생략) 가능
* Interface안에 private 메소드 사용 가능
* '_' 하나만으로 변수,함수 이름 사용 불가능
* Collection에서 정적(불변) 팩토리 메소드 'of' 추가
* Optional에서 ifPresentOrElse, or, stream 메소드 추가
* Stream
* takewhile(predicate)[(참인 경우 뒤에 버림)], dropWhile(predicate)[(참인 경우 앞에 버림)]
* ofNullable(t)
* iterate가 for문 인자와 비슷하게 개선 (limit 메서드 대체) -> iterate(0, i -> i < 10, i -> i + 1);
* CompletableFuture에 타임아웃(orTimeout(long)), 지연(CompletableFuture.delayedExecutor()) 기능 추가
* Process API에서 native 프로세스를 제어할 수 있는 ProcessHandle 인터페이스 추가
* StackWalker -> Stack을 훑는 기능. Debug할 때 좋을 듯.
* 내부 문자열 처리 방식 개선으로 메모리 절약. 기존에는 UTF-16 char 배열이었지만 문자에 따라 1byte 혹은 2byte가 필요한지에 따라 다르게 저장 -> isLatin()
* G1GC가 default GC. 이전 Parallel GC가 메모리를 물리적으로 나누었다면, G1GC는 메모리를 바둑판처럼 쪼갠 region이라는 논리적 개념으로 관리한다.
* OOM 발생시 사용할 수 있는 옵션 두 가지 추가
* ExitOnOutOfMemoryError
* CrashOnOutOfMemoryError
* Flow -> Java에서 공식적으로 Reactive Stream API 추가. 직접 구현을 해보면 Observer 패턴
== 10 ==
* 타입 추론이 가능한, 가변 변수 예약어 'var'
* Collection에서 깊은 복사 'copyOf' 팩토리 메소드 추가
* G1GC 성능 개선
== 11(LTS) ==
* var에 람다식 매개변수에 적용 가능
* String, Predicate 기능 추가
* Files 클래스에 파일 전체<->문자열 변환(readString/WriteString) 기능 추가
* 새로운 Http Client 모듈
* ZGC(experimetnal) -> 25에서 정식 GC로 승격
== 12 ~ 17(LTS) ==
=== 15 ===
==== Text Block ====
**여러 줄에 걸친 문자열**을 만들기 위한 새로운 문법
12에서 preview였다가 15에서 정식 기능으로 승격
// """ 다음으로 문자가 올 수 없고, 한줄로 작성할 수 없다!
// \를 사용하면 개행 제거
// 들여쓰기도 가능
String str = """
A
BC
DEF"""
=== Switch Expression 개선 ===
12에서 preview였다가 14에서 정식 기능으로 승격
private String calculateTestGrade1(int score) {
return switch (score) {
case 5:
yield "A";
case 4, 3:
yield "B";
case 2:
yield "C";
default:
yield "F";
};
}
private String calculateTestGrade2(int score) {
return switch (score) {
case 5 -> "A";
case 4, 3 -> "B";
case 2 -> {
System.out.println("C!");
yield "C";
}
default -> "F";
};
}
==== 'Instance of' Pattern Matching ====
14에서 preivew였다가 16에서 정식 기능으로 승격
public String say(Animal animal) throws IllegalAccessException {
if (animal instanceof Dog dog) {
return dog.bark();
} else if (animal instanceof Cat cat) {
return cat.purr();
}
throw new IllegalAccessException();
}
// 아래처럼 부정인 경우 Scope가 괄호 밖까지 확장 가능
public String sayIfDog(Animal animal) throws IllegalAccessException {
if (!(animal instanceof Dog dog)) {
throw new IllegalAccessException();
}
return dog.bark();
}
public interface Animal {
}
public static class Dog implements Animal {
public String bark() {
return "Dog barking...";
}
}
public static class Cat implements Animal {
public String purr() {
return "Cat purring...";
}
}
==== Record Class ====
데이터 전달을 위한 클래스 (DTO) -> Lombok 기능을 대체
14에서 preivew였다가 16에서 정식 기능으로 승격
public record PersonDtoV1 (
String name,
int age
) {
// Compact Constructor. 매개변수를 전혀 받지 않는다. this를 사용하지 않는다. (매개변수가 있다고 가정)
/*public PersonDtoV1 {
}*/
}
==== Sealed Class/Interface ====
하위 클래스를 지정된 클래스로만 상속을 제한(봉인)
자바 15에서 preview였다가 17에서 정식 기능으로 승격
// 한 파일에 있다면 permits 생략 가능
public sealed interface Animal permits Dog, Cat {
}
// final : 재상속 불가능
// sealed : 한 번더 sealed class로 동작
// non-seald : 상속 가능하지만 하위 타입 추적 불가능
public final static class Dog implements Animal {
public String bark() {
return "Dog barking...";
}
}
public final static class Cat implements Animal {
public String purr() {
return "Cat purring...";
}
}
== 18 ~ 21(LTS) ==
=== record pattern ===
19 Preview -> 21 정식
record class를 instanceof pattern matching과 함께 사용할 때 내부 필드에 바로 접근할 수 있는 기능 (구조 분해)
record Point(double x, double y) {}
record Line(Point p1, Point p2) {}
public static void findDistanceIfPoint2(Object object) {
if (object instanceof Point(double x, double y)) {
double distance = Math.hypot(x, y);
System.out.printf("원점으로부터의 거리 : %3.f\n", distance);
}
if(object instanceof Line(Point(var x1, var y1), Point(var x2, var y2))) {
double distance = Math.hypot(x1 - x2, y1 - y2);
System.out.printf("두 점 사이의 거리 : %3.f\n", distance);
}
}
=== switch pattern matching ===
17 preivew -> 21 정식
switch 선택자 안에 reference type도 들어갈 수 있는 기능
public String say(Animal animal) {
return switch (animal) {
case Dog d -> d.bark();
case Cat c -> c.purr();
default -> throw new IllegalStateException("Unexpected value: animal");
};
}
interface Animal {}
public static class Dog implements Animal {
public String bark() {
return "Dog bark";
}
}
public static class Cat implements Animal {
public String purr() {
return "Cat purr";
}
}
만약 sealed class로 상속을 제한하면 Dog와 Cat 두 가지 밖에 없으므로 switch 문의 default를 제거할 수 있다. 그러면 객체를 Enum처럼 사용할 수 있다.
public String say(Animal animal) {
return switch (animal) {
case Dog d -> d.bark();
case Cat c -> c.purr();
// default가 필요없다!
};
}
sealed interface Animal {}
public static final class Dog implements Animal {
public String bark() {
return "Dog bark";
}
}
public static final class Cat implements Animal {
public String purr() {
return "Cat purr";
}
}
한 번 더 검사할 수 있는 when 절도 생김
public String say(Animal animal) {
return switch (animal) {
case Dog d when d.isQuiet() -> "";
case Dog d -> d.bark();
case Cat c -> c.purr();
};
}
sealed interface Animal {}
public static final class Dog implements Animal {
public String bark() {
return "Dog bark";
}
public boolean isQuiet() {
return (new Random().nextBoolean());
}
}
public static final class Cat implements Animal {
public String purr() {
return "Cat purr";
}
}
null인 경우 NPE가 발생하지 않고 제어할 수 있다.
public String say(Animal animal) {
return switch (animal) {
case Dog d when d.isQuiet() -> Boolean.toString(d.isQuiet());
case Dog d -> d.bark();
case Cat c -> c.purr();
case null -> "";
};
}
=== Virtual Thread ===
"가상 Thread n개 - 플랫폼 Thread 1개 - OS Thread 1개" Mapping 관계
여러 요청을 동시에 처리해 전체 처리량을 늘리는 기능.
그래서 단일 요청에서 플랫폼 Thread보다 느릴 수 있다.
Pooling 방식을 권장하지 않는다. 그때 그때 필요할 때 만들어 사용하라!
/*Thread t = Thread.ofVirtual()
.start(() -> System.out.println("Hello World!"));
t.join();*/
try (ExecutorService executorService = Executors.newVirtualThreadPerTaskExecutor()) {
Future> future = executorService.submit(() -> System.out.println("Hello, Virtual Thread"));
future.get();
} catch (ExecutionException e) {
throw new RuntimeException(e);
}