티스토리 뷰
1. JPMS
- https://forest-33.tistory.com/52
[JAVA] JPMS 자바 플랫폼 모듈 시스템이란
JPMS(Java Platform Module System)Java 9에서 도입된 모듈 시스템으로, Java 애플리케이션과 라이브러리를 모듈 단위로 구성하고 관리JPMS는 코드의 재사용성, 유지보수성, 보안성 등을 향상시키기 위해 설
forest-33.tistory.com
2. try-with-resource
- 이미 선언된 리소스를 try-with-resources 블록에서 다시 선언하지 않고 사용할 수 있음
- 다만 리소스는 AutoCloseable 인터페이스를 구현하고 있어야함.
public class TryWithResourcesJava7 {
public static void main(String[] args) {
try (BufferedReader br = new BufferedReader(new FileReader("path/to/file.txt"))) {
System.out.println(br.readLine());
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class TryWithResourcesJava9 {
public static void main(String[] args) {
BufferedReader br = new BufferedReader(new FileReader("path/to/file.txt"));
try (br) {
System.out.println(br.readLine());
} catch (IOException e) {
e.printStackTrace();
}
}
}
3. @SafeVarargs 어노테이션 private method 사용 가능
- SafeVarargs: 가변 인수 메소드가 타입 안전함을 컴파일러에게 알리는 어노테이션.
- final, static, private 메소드 및 생성자에만 적용
public class WarningExample {
@SafeVarargs
private final void printLists(List<String>... lists) {
for (List<String> list : lists) {
System.out.println(list);
}
}
public static void main(String[] args) {
WarningExample example = new WarningExample();
example.printLists(List.of("A", "B", "C"), List.of("D", "E", "F"));
}
}
4. 인터페이스 + private 메서드 사용
- 내부 구현의 캡슐화: private 메소드는 인터페이스 내부에서만 사용되며, 외부 클래스가 이 메소드를 호출할 수 없음
- 중복 코드 제거: 여러 디폴트 메소드가 공통적으로 사용하는 코드를 private 메소드로 정의하여 코드의 중복을 줄일 수 있음
public interface MyInterface {
// 디폴트 메소드
default void defaultMethod() {
System.out.println("Default method");
// 내부에서 private 메소드 호출
helperMethod();
}
// 또 다른 디폴트 메소드
default void anotherDefaultMethod() {
System.out.println("Another default method");
// 내부에서 private 메소드 호출
helperMethod();
}
// private 메소드
private void helperMethod() {
System.out.println("Helper method");
}
}
5. 간결해진 Collection
- List.of(...)
- Set.of(...)
- Map.of(...)
- Map.ofEntries(...)
- of 메서드로 생성된 컬렉션은 불변(immutable). 즉, 생성된 후에는 요소를 변경할 수 없음
public class Example {
public static void main(String[] args) {
List<String> list = List.of("Apple", "Banana", "Cherry");
System.out.println(list); // 출력: [Apple, Banana, Cherry]
Set<String> set = Set.of("Apple", "Banana", "Cherry");
System.out.println(set); // 출력: [Apple, Banana, Cherry]
Map<String, Integer> map = Map.of(
"Apple", 1,
"Banana", 2,
"Cherry", 3
);
System.out.println(map); // 출력: {Apple=1, Banana=2, Cherry=3}
Map<String, Integer> map = Map.ofEntries(
Map.entry("Apple", 1),
Map.entry("Banana", 2),
Map.entry("Cherry", 3)
);
System.out.println(map); // 출력: {Apple=1, Banana=2, Cherry=3}
}
}
6. Optional 기능 추가
- fPresentOrElse: Optional이 값을 포함할 때와 포함하지 않을 때 각각 다른 작업을 수행할 수 있게 해줌
- or: 현재 Optional이 비어 있으면 대체할 다른 Optional을 반환
- stream: 값을 가진 경우 그 값을 원소로 하는 스트림을 반환하고, 비어 있는 경우 빈 스트림을 반환
public class Example {
public static void main(String[] args) {
Optional<String> opt = Optional.of("Hello");
// 출력 : Value is: Hello
opt.ifPresentOrElse(
value -> System.out.println("Value is: " + value),
() -> System.out.println("Value is not present")
);
// 출력 : Default
Optional<String> opt1 = Optional.empty();
Optional<String> opt2 = Optional.of("Default");
Optional<String> result = opt1.or(() -> opt2);
// 출력: Hello
Optional<String> opt3 = Optional.of("Hello");
Stream<String> stream = opt3.stream();
// 출력 : 빈값
Optional<String> emptyOpt = Optional.empty();
Stream<String> emptyStream = emptyOpt.stream();
}
}
7. Stream 기능 추가
- takeWhile(Predicate<? super T> predicate): 조건이 참인 동안의 요소들을 스트림에 포함시키고, 조건이 거짓이 되면 종료
- dropWhile(Predicate<? super T> predicate): 조건이 참인 요소들을 처음부터 제외하고, 조건이 거짓이 되면 나머지 요소들을 스트림에 포함
- ofNullable(T t): null일 수 있는 값을 포함하는 스트림을 생성. null이면 빈 스트림을 반환하고, 값이 존재하면 단일 원소 스트림을 반환
public class Example {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 4, 6, 8, 10);
// 출력: [2, 4, 6, 8, 10]
List<Integer> result = numbers.stream()
.takeWhile(n -> n % 2 == 0)
.collect(Collectors.toList());
// 출력: [2, 4, 6, 8, 10]
List<Integer> numbers = Arrays.asList(1, 2, 4, 6, 8, 10);
List<Integer> result = numbers.stream()
.dropWhile(n -> n % 2 != 0)
.collect(Collectors.toList());
Stream<String> stream1 = Stream.ofNullable("Hello");
Stream<String> stream2 = Stream.ofNullable(null);
stream1.forEach(System.out::println); // 출력: Hello
stream2.forEach(System.out::println); // 출력 없음
}
}
- iterator 개선
public class Example {
public static void main(String[] args) {
// 기존
Stream.iterator(0, i -> i+2)
.limit(5)
.forEach(System.out::println);
// 변경
Stream.iterator(0, i -> i < 10 , i -> i+2)
.forEach(System.out::println);
}
}
8. CompletableFuture 타임 아웃 관련 추가
- 자바의 비동기 프로그래밍을 위한 강력한 도구로, 비동기 작업의 실행과 결과 처리를 관리할 수 있는 다양한 메서드를 제공
- onTimeout과 completeOnTimeout은 특정 시간 내에 작업이 완료되지 않았을 때 처리할 방법을 제공하는 메서드
onTimeout
- 주어진 시간안에 작업이 완료 되지 않으면 예외 발생
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(3000); // 긴 작업 시뮬레이션 3초 sleep
} catch (InterruptedException e) {
e.printStackTrace();
}
return "작업 완료";
});
CompletableFuture<String> result = future.orTimeout(1, TimeUnit.SECONDS)
.exceptionally(ex -> "타임아웃 발생");
result.thenAccept(System.out::println); // 출력: 타임아웃 발생
completeOnTimeout
- 주어진 시간 안에 작업이 완료되지 않으면 정해진 값 반환
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(3000); // 긴 작업 시뮬레이션
} catch (InterruptedException e) {
e.printStackTrace();
}
return "작업 완료";
});
CompletableFuture<String> result = future.completeOnTimeout("타임아웃 발생", 1, TimeUnit.SECONDS);
result.thenAccept(System.out::println); // 출력: 타임아웃 발생
9. ProcessHandle
- java 9에서 도입된 인터페이스로, 현재 JVM 프로세스나 다른 시스템 프로세스에 대한 제어와 정보를 제공하는 데 사용
- 시스템에서 실행 중인 프로세스들을 더 쉽게 관리하고, 관련 정보를 얻을 수 있음
// 현재 프로세스
ProcessHandle currentProcess = ProcessHandle.current();
long pid = currentProcess.pid();
System.out.println("현재 프로세스 ID: " + currentProcess.pid());
// 프로세스 정보
ProcessHandle.Info info = currentProcess.info();
info.command().ifPresent(cmd -> System.out.println("명령어: " + cmd));
info.startInstant().ifPresent(time -> System.out.println("시작 시간: " + time));
info.user().ifPresent(user -> System.out.println("사용자: " + user));
// 자식 프로세스 관리
currentProcess.children().forEach(ph -> System.out.println("자식 프로세스 ID: " + ph.pid()));
//실행중인지 확인
if (currentProcess.isAlive()) {
System.out.println("프로세스가 실행 중입니다.");
}
// 프로세스가 종료될 때 실행되는 콜백을 등록
currentProcess.onExit().thenRun(() -> {
System.out.println("프로세스가 종료되었습니다.");
});
// 프로세스 종료
boolean terminated = currentProcess.destroy();
if (terminated) {
System.out.println("프로세스가 정상적으로 종료되었습니다.");
}
10. StackWalker
- StackWalker는 Java에서 스택 프레임을 효율적으로 탐색하고 분석할 수 있게 해주는 도구
- 성능과 유연성을 갖춘 이 도구는 디버깅, 로깅, 보안 등의 다양한 목적에 맞게 사용할 수 있으며, 필요에 따라 호출 스택의 특정 부분만 탐색하거나 분석할 수 있는 기능을 제공
import java.util.stream.Stream;
public class StackWalkerExample {
public static void main(String[] args) {
methodA();
}
public static void methodA() {
methodB();
}
public static void methodB() {
methodC();
}
public static void methodC() {
StackWalker stackWalker = StackWalker.getInstance();
// 전체 스택 프레임을 순회하며 클래스 이름과 메서드 이름을 출력
stackWalker.forEach(frame -> {
System.out.println(frame.getClassName() + " - " + frame.getMethodName());
});
System.out.println("\n--- 특정 조건에 맞는 첫 번째 프레임 ---");
// StackWalker.walk(Function<Stream<StackFrame>, T> mapper): 스택 프레임을 탐색하면서 주어진 함수를 적용
// 특정 조건에 맞는 첫 번째 스택 프레임만 출력
StackWalker.StackFrame frame = stackWalker.walk(frames ->
frames.filter(f -> f.getMethodName().equals("methodB"))
.findFirst()
).orElseThrow();
System.out.println("메서드 이름: " + frame.getMethodName());
System.out.println("클래스 이름: " + frame.getClassName());
}
}
11. 내부 문자열 처리 방식 개선
- char[] 기반에서 byte[] 기반의 문자열 저장 방식으로 변경
- 메모리 사용을 줄이고 성능을 최적화하는 데 중점을 둔 중요한 개선
Java 9 이전: char[] 기반
- Java 8까지는 String 클래스가 내부적으로 char[] 배열을 사용하여 문자열 데이터를 저장
- Java의 char 타입은 16비트(2바이트) 유니코드 문자를 표현할 수 있도록 설계
- 즉, 모든 문자열이 각 문자를 2바이트씩 사용하여 저장
Java 9 이후: byte[] + coder 기반
- Java 9부터 String 클래스는 더 이상 char[] 배열을 사용하지 않으며 대신, byte[] 배열을 사용하여 문자열 데이터를 저장
- byte[]: 문자열 데이터를 저장하는 배열. 이제 각 문자가 1바이트(ISO-8859-1/Latin-1 인코딩) 또는 2바이트(UTF-16 인코딩)로 저장
- coder: 문자열이 어떤 인코딩 방식(1바이트/2바이트)으로 저장되었는지를 나타내는 값. 0은 Latin-1(1바이트), 1은 UTF-16(2바이트)을 의미
11. default GC parallel GC -> G1 GC로 변경
- Parallel GC
- 높은 처리량을 목표로 하며, 여러 CPU 코어를 활용해 빠르게 GC를 수행.
- 그러나 긴 GC 정지 시간으로 인해 응답 시간이 길어질 수 있음
- G1 GC
- 예측 가능한 GC 정지 시간을 목표로 하며, 힙을 여러 개의 Region으로 나누어 효율적으로 관리
- G1 GC는 대규모 힙을 관리하고자 할 때 유용
'IT > Java' 카테고리의 다른 글
Java 리플렉션 reflection (0) | 2024.08.06 |
---|---|
[JAVA] JPMS 자바 플랫폼 모듈 시스템이란 (0) | 2024.07.10 |