JEP 390: Warnings for Value-Based Classes

JEP 390: Warnings for Value-Based Classes

Summary

기본 래퍼 클래스를 값 기반 으로 지정하고 제거를 위해 해당 생성자를 더 이상 사용하지 않으며, 새로운 사용 중단 경고가 표시됩니다.
Java 플랫폼에서 값 기반 클래스의 인스턴스에서 동기화하려는 부적절한 시도에 대한 경고를 제공합니다.

Motivation

Valhalla 프로젝트 는 원시 클래스 의 형태로 Java 프로그래밍 모델에 대한 상당한 향상을 추구하고 있습니다.
이러한 클래스는 인스턴스가 ID가 없고 인라인 또는 평면화된 표현이 가능하다고 선언합니다.
여기서 인스턴스는 메모리 위치 간에 자유롭게 복사되고 인스턴스 필드의 값만 사용하여 인코딩될 수 있습니다.

기본 클래스의 설계 및 구현은 충분히 성숙하여 Java 플랫폼의 특정 클래스를 향후 릴리스에서 기본 클래스가 되도록 마이그레이션할 수 있을 것입니다.

마이그레이션 후보 는 API 사양에서 값 기반 클래스 로 비공식적으로 지정됩니다.
대체로 이것은 클래스의 동작에 중요하지 않은 ID를 가진 변경 불가능한 개체를 인코딩하고 각 호출에서 고유한 ID를 약속하는 공용 생성자와 같은 인스턴스 생성 메커니즘을 제공하지 않는다는 것을 의미합니다.

기본 래퍼 클래스( java.lang.Integer, java.lang.Double, 등)도 기본 클래스가 되도록 의도되었습니다.
이러한 클래스는 더 이상 사용되지 않는(Java 9 이후) public 생성자 를 노출한다는 점을 제외하고 값 기반으로 지정해야 하는 대부분의 요구 사항을 충족합니다.
정의를 약간 조정하면 값 기반 클래스로도 간주될 수 있습니다.

값 기반 클래스의 클라이언트는 이러한 클래스 사용에 대한 권장 사항을 위반하는 경우를 제외하고 일반적으로 기본 클래스 마이그레이션의 영향을 받지 않습니다.
특히 마이그레이션이 발생한 향후 Java 릴리스에서 실행할 때:

  1. 이러한 클래스(per ==)의 인스턴스는 동일한(per equals) 것으로 간주 되어 올바른 동작을 위해 결과에 ==의존하는 프로그램을 잠재적으로 중단시킬 수 있습니다.!=
  2. 암시적 박싱이나 팩토리 메서드 호출이 아닌, 등 new Integer을 사용하여 래퍼 클래스 인스턴스를 만들려는 시도 는 s를 생성합니다.new Double valueOf LinkageError
  3. 이러한 클래스의 인스턴스에서 동기화를 시도하면 예외가 발생합니다.

이러한 변경 사항은 일부에게는 불편할 수 있지만 해결 방법은 간단합니다.
ID가 필요한 경우 다른 클래스를 사용합니다. 종종 스스로 정의하지만 적합 Object할 AtomicReference수도 있습니다.
더 나은 성능, 안정적인 평등 의미, 기본 및 클래스 통합과 같은 기본 클래스로 마이그레이션할 때의 이점은 불편을 감수할 가치가 있습니다.

(1) 값 기반 클래스의 팩토리 메서드에서 고유한 ID에 대한 약속을 피함으로써 이미 낙담했습니다.
이러한 사양을 무시하고 현재 구현 동작에 의존하는 프로그램을 자동으로 감지하는 실용적인 방법은 없지만 그러한 경우는 거의 없을 것으로 예상합니다.

제거를 위해 래퍼 클래스 생성자를 더 이상 사용하지 않음으로써 (2)를 억제할 수 있습니다.
그러면 이러한 생성자에 대한 호출을 컴파일할 때 발생하는 경고가 증폭됩니다.
기존 Java 프로젝트의 상당 부분(아마도 1%-10%)이 래퍼 클래스 생성자를 호출하지만 대부분의 경우 9 이전 Java 릴리스에서만 실행하려고 합니다.
많은 인기 있는 오픈 소스 프로젝트는 이미 소스에서 래퍼 생성자 호출을 제거하여 Java 9의 사용 중단 경고에 응답했으며
“deprecated for removal” 경고의 긴급성이 높아진 점을 감안할 때 더 많은 작업을 수행할 것으로 예상할 수 있습니다.
이 문제를 완화하기 위한 추가 기능은 종속성 섹션에 설명되어 있습니다.

(3) 컴파일 시간과 런타임에 프로그래머에게 동기화 작업이 향후 릴리스에서 작동하지 않을 것임을 알리기 위해 경고를 구현하여 억제할 수 있습니다.

Description

java.lang( Byte, Short, Integer, Long, Float, Double, Boolean및 ) 의 기본 래퍼 클래스는 Character값 기반으로 지정되었습니다.
값 기반 클래스 에 대한 설명은 더 이상 사용되지 않는 생성자 및 내부 팩토리를 허용하고 기본 클래스 마이그레이션 요구 사항과
더 잘 일치하도록 업데이트되었습니다(예: 값 기반 클래스는 인스턴스 필드를 상속해서는 안 됨).

값 기반 클래스 인스턴스의 오용을 방지하려면:

  • Java 9에서 원래 사용되지 않는 기본 래퍼 클래스 생성자는 제거를 위해 사용되지 않습니다. 생성자가 소스에서 호출될 때마다 javac 기본적으로 removal 경고가 생성됩니다.
    이 jdeprscan도구는 바이너리에서 더 이상 사용되지 않는 API의 사용을 식별하는 데 사용할 수 있습니다.

  • javac값 기반 클래스 유형 또는 하위 유형이 모두 값 기반으로 지정된 유형의 피연산자를 synchronization사용하여 문의 사용을 식별 하는 새로운 경고 범주 를 구현합니다.
    synchronized경고 범주는 기본적으로 켜져 있으며 를 사용하여 수동으로 선택할 수 있습니다 -Xlint:synchronization.

  • monitorenterHotSpot 은 값 기반 클래스 인스턴스에서 발생하는 런타임 감지를 구현 합니다.
    명령줄 옵션 -XX:DiagnoseSyncOnValueBasedClasses=1은 작업을 치명적인 오류로 처리합니다.
    명령줄 옵션 -XX:DiagnoseSyncOnValueBasedClasses=2 은 콘솔과 JDK Flight Recorder 이벤트를 통해 로깅을 켭니다.

컴파일 타임 동기화 경고는 정적 유형에 따라 달라지지만 런타임 경고는 Object.

예를 들어:

1
2
3
4
Double d = 20.0;
synchronized (d) { ... } // javac warning & HotSpot warning
Object o = d;
synchronized (o) { ... } // HotSpot warning

monitorexit바이트 코드와 Object메서드 wait, notify및 메서드 는 notifyAll항상 문 또는 메서드 IllegalMonitorStateException외부에서 호출되는 if 를 throw했습니다.
synchronized따라서 이러한 작업에 대한 경고가 필요하지 않습니다.

Identifying value-based classes

JDK 내에서 @jdk.internal.ValueBased주석은 javac클래스가 값 기반이거나 추상 클래스 또는 인터페이스에 값 기반 하위 클래스가 필요하다는 신호를 HotSpot에 사용하는 데 사용됩니다.

@ValueBasedJava Platform API 및 JDK의 다음 선언에 적용됩니다.

  • java.lang 의 기본 래퍼 클래스

  • java.lang.Runtime.Version 클래스

  • The “optional” classes in java.util: Optional, OptionalInt, OptionalLong, and OptionalDouble;

  • java.time API: Instant, LocalDate, LocalTime, LocalDateTime, ZonedDateTime, ZoneId, OffsetTime,
    OffsetDateTime, ZoneOffset, Duration, Period, Year, YearMonth, and MonthDay, and,
    in java.time.chrono: MinguoDate, HijrahDate, JapaneseDate, and ThaiBuddhistDate;

  • The interface java.lang.ProcessHandle and its implementation classes;

  • java.util 에 있는 컬렉션 팩토리의 구현 클래스 : List.of, List.copyOf, Set.of, Set.copyOf, Map.of, Map.copyOf, Map.ofEntries, and Map.entry.

주석이 추상 클래스나 인터페이스에 적용될 때마다 JDK의 모든 하위 클래스에도 적용됩니다.

일부 클래스와 인터페이스는 java.lang.constant값 jdk.incubator.foreign기반이라고 주장했지만 수정된 요구 사항을 충족하지 않습니다(예: 인스턴스 필드를 상속함).
따라서 기본 클래스로 마이그레이션할 수 없습니다. 이 경우 더 이상 가치 기반 클래스로 설명하는 것이 적절하지 않으며 사양이 수정되었습니다.

Scope of changes

Java SE : 이 JEP는 원시 래퍼 클래스, 기존 값 기반 클래스, 관련 인터페이스 및 팩토리 메서드의 사양을 개선하여 Java SE를 수정합니다.
또한 기본 래퍼 클래스 생성자 제거에 대해 더 이상 사용되지 않습니다. Java 언어 또는 Java 가상 머신 사양을 변경 하지 않습니다 .

JDKjavac : JDK에서 이 JEP는 또한 HotSpot 에 새로운 경고 및 로깅 기능을 추가합니다.
그리고 주석을 정의하고 @jdk.internal.ValueBased여러 JDK 클래스에 적용합니다.

Alternatives

이러한 클래스를 기본 클래스로 마이그레이션하려는 노력을 포기할 수 있습니다.
그러나 마이그레이션을 완료하면 개발자가 누릴 수 있는 상당한 이점이 있으며 문제가 있는 동작에 의존하는 개발자에 대한 상대적 영향은 적습니다.

런타임 경고로 컴파일 시간 사용 중단 경고를 보완할 수 있습니다.
이것은 다른 JEP의 향후 작업으로 남겨집니다(아래 참조).

API 클래스 및 와 같은 기능에 의해 생성된 클래스를 포함하여 기본 클래스로 마이그레이션될 수 있는 다른 클래스가 있을 수 있습니다 java.lang.invoke.LambdaMetafactory.
이 JEP는 이미 값 기반으로 지정된 래퍼 클래스 및 클래스로 제한됩니다. 다시 말하지만 향후 작업으로 추가 경고가 도입될 수 있습니다.

Dependencies

값 기반 클래스를 기본 클래스로 마이그레이션하려면 이러한 경고가 있는 적절한 리드 타임이 필요합니다.
가장 중요한 것은 래퍼 클래스를 기본 클래스로 만들기 위한 JEP는 이 JEP가 완료된 후 몇 가지 릴리스가 될 때까지 진행할 수 없다는 것입니다.

래퍼 클래스를 기본 클래스로 만들기 위한 또 다른 전제 조건은 생성자의 레거시 사용을 식별하고 해결하기 위한 충분한 도구입니다. 두 가지 후속 기능은 별도의 JEP에서 조사됩니다.

  • 래퍼 클래스 생성자를 포함하여 더 이상 사용되지 않는 API 사용에 대한 HotSpot 런타임 경고. 이것은 javac및 에 의해 생성된 경고를 보완합니다 jdeprscan.
  • 래퍼 클래스 생성자의 사용법을 업데이트할 수 없는 바이너리 실행을 지원하는 도구입니다.
    valueOf예를 들어 이것은 프로그래머에게 팩토리 메서드 를 사용하기 위해 바이트 코드를 다시 작성할 수 있는 옵션을 제공할 수 있습니다.

참조