웹사이트 검색

자바 15 기능


6개월 주기 전통에 따라 2020년 3월 17일에 Java 14가 릴리스된 후 이제 2020년 9월 15일에 롤아웃되는 다음 비 LTS 버전인 Java 15가 있습니다.

자바 15 기능

다음은 Java 15의 일부인 기능에 대한 간략한 설명입니다.

  • 밀폐 클래스(미리보기) – JEP 360
  • instanceof에 대한 패턴 일치(두 번째 미리 보기) – JEP 375
  • 기록(두 번째 미리 보기) – JEP 359
  • 텍스트 블록(표준) – JEP 378
  • 숨겨진 클래스 – JEP 371
  • Nashorn JavaScript 엔진 제거 – JEP 372
  • 레거시 DatagramSocket API 재구현 – JEP 373
  • 편향된 잠금 비활성화 및 폐기 – JEP 374
  • Shenandoah: 중단 시간이 짧은 가비지 수집기 – JEP 379
  • Solaris 및 SPARC 포트 제거 – JEP 381
  • 외부 메모리 액세스 API(두 번째 인큐베이터) – JEP 383
  • 제거를 위한 RMI 활성화 사용 중단 – JEP 385

Mac OS에서 Java 15 설치 설정

  • Java 15를 시작하려면 여기에서 JDK를 다운로드하세요.
  • 아래와 같이 /Library/Java/JavaVirtualMachines에서 tar 파일을 복사하고 추출합니다.

$ cd /Library/Java/JavaVirtualMachines

$ sudo cp ~/Downloads/openjdk-15_osx-x64_bin.tar.gz /Library/Java/JavaVirtualMachines

$ sudo tar xzf openjdk-15_osx-x64_bin.tar.gz

$ sudo rm openjdk-15_osx-x64_bin.tar.gz

완료되면 텍스트 편집기를 사용하여 bash_profile을 엽니다. 저는 vim ~/.bash_profile을 사용하고 있습니다. Java15의 경로를 JAVA_HOME으로 설정하고 변경 사항을 저장한 다음 source ~/.bash_profile을 수행하여 변경 사항을 반영합니다.

export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk-15.jdk/Contents/Home

마지막으로 Java 15를 사용하여 프로그램을 컴파일하고 실행할 준비가 되었습니다. 새로운 Java 15 기능을 빠르게 테스트하기 위한 대화형 REPL 명령줄 도구인 JShell을 사용할 것입니다.

Java 15에서 릴리스된 많은 기능이 미리 보기 상태라는 점에 유의해야 합니다. 즉, 지금은 완벽하게 작동하지만 나중에 수정될 수 있습니다. 일부는 표준이 되거나 다음 릴리스 주기에서 간단히 제거될 수 있습니다. 미리보기 기능을 테스트하려면 아래와 같이 JShell 또는 Java 프로그램을 실행할 때 --enable-preview를 명시적으로 설정해야 합니다.

jshell --enable-preview

javac --release 15 --enable-preview Author.java

다음 몇 개의 섹션에서는 Java 15의 중요한 언어 변경 사항에 대해 논의해 보겠습니다.

1. 봉인된 클래스(프리뷰)

봉인된 클래스는 한동안 Kotlin에 있었고 Java 15는 마침내 상속을 더 잘 제어하기 위해 이 기능을 도입했습니다.

이름에서 알 수 있듯이 Sealed 클래스를 사용하면 클래스 계층 구조를 특정 유형으로만 제한하거나 허용할 수 있습니다.

전환할 특정 클래스 수가 있으므로 패턴 일치에 매우 유용합니다.

다음 구문은 Java 15에서 봉인된 클래스를 정의합니다.

public sealed class Vehicle permits Car, Bike, Truck {
...
}

따라서 위의 코드는 permits 키워드 뒤에 정의된 클래스만 Vehicle sealed 클래스를 확장할 수 있음을 의미합니다.

Vehicle과 동일한 파일에 Car, BikeTruck 클래스를 정의한 경우, 는 키워드 permit을 생략할 수 있으며 컴파일러는 아래와 같이 묵시적으로 이를 처리합니다.

sealed class Vehicle {...}

final class Car extends Vehicle {...}
final class Bike extends Vehicle {...}
final class Truck extends Vehicle {...}

위에서 볼 수 있듯이 각 클래스의 최종 수정자를 정의했습니다. 이제 명심해야 할 봉인된 클래스의 중요한 규칙입니다. 모든 허용된 클래스는 명시적 한정자로 설정되어야 합니다. 최종 또는 봉인 또는 비봉인일 수 있습니다.

각 수정자가 상속에 미치는 영향은 다음과 같습니다.

  • final로 선언된 허용된 하위 클래스는 더 이상 확장할 수 없습니다.
  • sealed로 선언된 허용된 하위 클래스는 추가 확장이 가능하지만 하위 클래스에서 허용하는 클래스에 의해서만 가능합니다.
  • 허용된 하위 클래스는 선언될 수 있습니다. 비봉인은 모든 클래스에 의해 더 확장될 수 있습니다. 슈퍼클래스는 이 클래스 계층 아래의 하위클래스를 제한할 수 없습니다.

Java 15 이전에는 개발자가 상속을 제어하기 위해 최종 키워드 또는 범위 한정자만 사용할 수 있었습니다. 따라서 봉인된 클래스는 클래스 계층을 정의할 때 Java 개발자에게 추가적인 유연성을 제공합니다.

Java의 Reflection API에는 봉인된 클래스를 처리하기 위한 두 가지 새로운 메서드도 있습니다.

java.lang.constant.ClassDesc[] getPermittedSubclasses();

boolean isSealed()

2. 기록(2차 미리보기)

레코드는 POJO 기반 데이터 캐리어 클래스를 작성할 때 상용구 코드를 줄이기 위한 노력의 일환으로 Java 14의 미리 보기 기능으로 도입되었습니다. 이것은 데이터 클래스의 형태로 오랫동안 Kotlin에 있었던 것입니다.

이제 Java 15를 통해 Records는 두 번째 미리 보기를 얻습니다. 주요 변경 사항은 없지만(일부 사소한 추가 사항) 여전히 알아야 할 몇 가지 주요 설명 및 제한 사항이 있습니다.

  • Java 15 이전에는 레코드에 네이티브 메서드를 선언할 수 있었습니다(좋은 생각은 아니었지만). 이제 JEP는 레코드에서 네이티브 메서드를 선언하는 것을 명시적으로 금지합니다. 당연하게도 네이티브 메서드를 정의하면 외부 상태 종속성을 가져와 레코드의 USP를 훔칩니다.
  • 레코드 클래스의 레코드 구성 요소에 해당하는 암시적으로 선언된 필드는 최종이며 IllegalAccessException을 발생시키므로 지금 리플렉션을 통해 수정하면 안 됩니다.

레코드는 데이터 캐리어 클래스를 의미하며 레코드에 네이티브 메서드를 정의하는 것을 완전히 피해야 합니다.

봉인된 유형의 레코드

우리는 기록이 최종적이고 연장될 수 없다는 것을 알고 있습니다. 다행스럽게도 레코드는 인터페이스를 구현할 수 있습니다.

따라서 다음과 같은 방법으로 봉인된 인터페이스를 정의하고 레코드에 구현할 수 있습니다.

sealed interface Car permits BMW, Audi { ... }

record BMW(int price) implements Car { ... }

record Audi(int price, String model) implements Car { ... }

지역 기록

중간 값을 저장하기 위해 메서드 내에서 레코드를 정의할 수도 있습니다. 로컬 클래스와 달리 로컬 레코드는 암시적으로 정적입니다. 이것은 그들이 레코드에 의해 값을 캡처하는 것을 방지하기 때문에 실제로 좋은 둘러싸는 메서드의 변수 및 인스턴스 멤버에 액세스할 수 없음을 의미합니다.

로컬 레코드는 이전에 도우미 레코드를 만들어야 했던 Java 개발자에게 큰 도움이 됩니다.

로컬 레코드의 도입이 다음 방법을 사용하여 스트림 API에서 값 계산을 수행하는 데 어떻게 도움이 되는지 확인하십시오.

List<Merchant> findTopMerchants(List<Merchant> merchants, int month) {
    // Local record
    record MerchantSales(Merchant merchant, double sales) {}

    return merchants.stream()
        .map(merchant -> new MerchantSales(merchant, computeSales(merchant, month)))
        .sorted((m1, m2) -> Double.compare(m2.sales(), m1.sales()))
        .map(MerchantSales::merchant)
        .collect(toList());
}

결론

위의 두 가지가 Java 15의 두 가지 주요 언어 기능이었지만, 사용자 피드백을 위한 두 번째 미리 보기에는 패턴 일치, 이제 표준 기능인 텍스트 블록, 가장 중요한 새로운 히든 클래스 기능도 있습니다.

숨겨진 클래스는 프레임워크 개발자와 관련된 JVM 기능입니다. Lookup::defineHiddenClass를 사용하여 정의함으로써 클래스 구현을 검색 불가능하게 만들 수 있습니다. 그렇게 함으로써 이러한 클래스는 Class.forName을 사용하거나 바이트코드에서 참조하여 찾을 수 없습니다.

다음은 Java 15에 도입된 주요 변경 사항입니다.