Java의 새로운 기능

Java 9의 새로운 기능 - 기타

늦깎이_개발자 2021. 9. 22. 16:41
반응형

1. 개요

 이전 글들에서 Java 9의 새로운 기능들 중 가장 큰 부분인 모듈에 대해 알아봤다. 이 글에서는 모듈을 제외한 새로운 기능들 중 몇 가지를 소개할 것이다.

 

2. 새로운 Http Client

 오랜 기다림 끝에 드디어 HttpURLConnection을 대체할 수 있는 것이 나왔다.

 새로운 API는 java.net.package 패키지 아래에 있다. HTTP/2 프로토콜과 WebSocket 핸드셰이크를 모두 지원하며, Apache HttpClient, Netty 및 Jetty와도 비슷한 수준의 성능을 가진다.
 간단한 HTTP 요청을 만들어 전송하여 이 새로운 기능을 살펴보자.

2.1 GET Request

 API는 빌더 패턴을 사용하여 다음과 같이 매우 쉽게 사용할 수 있다.

HttpRequest request = HttpRequest.newBuilder()
        .uri(new URI("https://www.naver.com"))
        .GET()
        .build();

HttpResponse<String> response = HttpClient.newHttpClient()
        .send(request, HttpResponse.BodyHandlers.ofString());

 

3. 프로세스 API

 운영 체제 프로세스를 제어하고 관리할 수 있도록 프로세스 API가 개선되었다.

 

3.1 프로세스 정보

 java.lang.ProcessHandle 클래스가 대부분의 새로운 기능들을 가지고 있다.

ProcessHandle self = ProcessHandle.current();
long PID = self.pid();
ProcessHandle.Info procInfo = self.info();

Optional<String[]> arguments = procInfo.arguments();
Optional<String> cmd = procInfo.commandLine();
Optional<Instant> startTime = procInfo.startInstant();
Optional<Duration> cupUsage = procInfo.totalCpuDuration();

ProcessHandle.current().children().forEach(processHandle -> {
    processHandle.destroy();
});

 current() 메서드는 현재 실행 중인 JVM 프로세스를 나타내는 객체를 반환한다. Info 하위 클래스는 프로세스에 대한 세부 정보를 제공한다. 그리고 destroy() 메서드를 통해, 실행 중인 차일드 프로세스를 모두 종료시킬 수 있다.

 

4. 일부 작은 수정 사항들

4.1. Try-With-Resources

 Java 7에서 Try-with-Resource 구문을 사용하려면, 이 구문 내에서 자원에 대한 선언을 해야했다. 
 Java 9부터는, 리소스가 final 이거나 effectively final일 경우, 구문 내에서 선언되지 않아도 된다.

// Before Java 9
try (FileReader fileReader1 = new FileReader("/test.txt")) {
    // do something
}

// Java 9
FileReader fileReader2 = new FileReader("/test.txt");

try (fileReader2) {
    // do something
}

 

4.2 다이아몬드 연산자

 이제 익명객체를 생성할 때도 다이아몬드 연산자를 사용할 수 있다.

Function<Integer, Integer> function = new Function<>() {
    @Override
    public Integer apply(Integer input) {
        return input * 3;
    }
};

 

4.3 인터페이스의 private 메서드

 Java 9에서는 인터페이스의 default 메서드에 대한 분할을 가능하게 하기 위해 private 메서드를 사용할 수 있다.

interface InterfaceWithPrivateMethods {
    
    private static String staticPrivate() {
        return "static private";
    }
    
    private String instancePrivate() {
        return "instance private";
    }
    
    default void check() {
        String result = staticPrivate();
        InterfaceWithPrivateMethods pvt = new InterfaceWithPrivateMethods() {
            // anonymous class
        };
        result = pvt.instancePrivate();
    }
}}

 

5. JShell 커멘드 라인 툴

 JShell은 read(읽고)-eval(해석하고)-print(출력하는)-loop(루프), 줄여서 REPL 이다. 다시 말해, 자바 코드를 라인단위로 해석해주는 대화형 툴이다. 이것은 작은 코드들을 테스트해볼 때 매우 편리하다.

$ jshell 
|  Welcome to JShell -- Version 9
|  For an introduction type: /help intro

jshell> "This is my long string. I want a part of it".substring(8,19);
$1 ==> "my long str"

 JShell은 히스토리와 자동 완성 기능도 제공한다. 또한 파일을 저장하거나 로딩하는 기능도 제공한다.

jshell> System.out.println("Hello World")
Hello World

jshell> /save /home/mslim/test.txt

jshell> /open /home/mslim/test.txt
Hello World

 /open 명령어를 통해 로드된 코드 조각은 실행된다.

 

6. JCMD 커멘드 라인 툴

 jcmd 커멘드 라인 유틸리티의 몇 가지 새로운 하위 명령을 살펴보겠다. 우리는 JVM에 로드된 모든 클래스 및 상속 구조의 목록을 확일할 수 있다. 아래 예제에서는, Eclipse Neon을 실행하고 있는 JVM에 로드된 java.lang.Socket의 계층구조를 볼 수 있다.

jdk-9\bin>jcmd 14056 VM.class_hierarchy -i -s java.net.Socket
14056:
java.lang.Object/null
|--java.net.Socket/null
|  implements java.io.Closeable/null (declared intf)
|  implements java.lang.AutoCloseable/null (inherited intf)
|  |--org.eclipse.ecf.internal.provider.filetransfer.httpclient4.CloseMonitoringSocket
|  |  implements java.lang.AutoCloseable/null (inherited intf)
|  |  implements java.io.Closeable/null (inherited intf)
|  |--javax.net.ssl.SSLSocket/null
|  |  implements java.lang.AutoCloseable/null (inherited intf)
|  |  implements java.io.Closeable/null (inherited intf)

 jcmd 명령의 첫 번째 매개 변수는 명령을 실행할 JVM의 프로세스 ID(PID)이다. 

 또 다른 흥미로운 하위 명령은 set_vmflag이다. JVM 프로세스를 다시 시작하고 시작 매개 변수를 수정할 필요 없이, 온라인으로 일부 JVM 매개 변수를 수정할 수 있다. jcmd <pid> VM.flags -all 명령을 통해 수정 가능한 VM Flag들의 목록을 확인할 수 있다.

 

7. Publish-Subscribe 프레임워크

 java.util.concurrent.Flow 클래스는 Reactive Streams을 지원하는 인터페이스를 제공한다. 이러한 인터페이스는 JVM에서 실행되는 여러 비동기 시스템에서의 상호 운용성을 지원한다. 유틸리티 클래스 SubmissionPublisher를 사용하여 커스텀 컴포넌트를 만들 수 있다.

 

8. 통합 JVM 로깅

 이 기능은 JVM의 모든 구성 요소에 대한 공통 로깅 시스템을 도입한다. 로깅을 수행할 인프라를 제공하지만 모든 JVM 구성 요소에서 실제 로깅을 호출하지는 않는다. 또한 JDK의 Java 코드에 로깅을 추가하지도 않는다.
 로깅 프레임워크는 태그의 집합을 정의한다. 예를 들어 gc, 컴파일러, 스레드 등이다. 커멘드 라인 매개 변수 -Xlog를 사용하여 시작 중에 로깅을 설정할 수 있다.
 'debug' 레벨의 'gc' 태그가 붙은 로그들을 'gc.txt'라는 파일에 기록해보자.

java -Xlog:gc=debug:file=gc.txt:none ...

 -Xlog:help는 가능한 옵션과 예시를 보여줄 것이다. 로깅 설정은 jcmd 명령을 통해 런타임에 수정될 수 있다. 아래에서 gc로그의 레벨을 info로, 로깅 파일을 gc_log로 변경해보자.

jcmd <pid> VM.log output=gc_logs what=gc

 

9. 새로운 API

9.1 불변 컬렉션

 java.util.Set.of(), java.util.List.of(), java.util.Map.of() 메서드를 통해 컬렉션을 좀 더 쉽게 만들 수 있다.

List<String> list = List.of("a", "b", "c");
Set<String> set = Set.of("a", "b", "c");
Map<String, Integer> map = Map.of("a", 1, "b", 2); // key와 value 순서로 넣어야함. 개인적으로 이 함수는 매우 구린 것으로 보인다-_-;

 이 메서드들은 JVM의 내부 클래스인 java.util.ImmutableCollections.ListN / SetN / MapN 객체를 반환하는데, 이는 AbstractCollection을 구현한 것들이며 불변이다. 만약 add(), remove(), put()과 같은 함수를 통해 이 컬렉션들에 변형을 가하려고 할 경우, UnsupportedOperationException이 발생된다. (참고로 코틀린에서는 불변 컬렉션이 디폴트이다.)

 

9.2 Optional.stream()

 java.util.Optional.stream() 메서드가 생김으로써, Optional 객체들을 스트림과 함께 더 편리하게 사용하는 것이 가능해졌다.

List<String> filteredList = listOfOptionals.stream()
  .flatMap(Optional::stream)
  .collect(Collectors.toList());

 

※ 참조

https://www.baeldung.com/new-java-9

반응형