티스토리 뷰

IT/Java

JAVA 9 변경 사항들

forest-33 2024. 8. 6. 22:30

 

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
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
글 보관함