JEP 359: Records (Preview)

Records (Preview)

Summary

레코드 로 Java 프로그래밍 언어를 향상 시키십시오 .
레코드는 얕은 불변의 데이터를위한 투명한 홀더 인 클래스를 선언하기위한 간단한 구문을 제공합니다.
이것은 JDK 14 의 미리보기 언어 기능 입니다.

Motivation and Goals

“자바가 너무 장황하다”또는 “행사”가 너무 많다는 것이 일반적인 불만입니다.
최악의 범죄자 중 일부는 단순한 집계로 사용되는 일반 “데이터 캐리어”에 지나지 않는 클래스입니다.
제대로 데이터 캐리어 클래스를 작성하려면,
하나 낮은 값, 반복, 오류가 발생하기 쉬운 코드를 많이 쓸 수있다 : constructors, accessors, equals(), hashCode(), toString(), etc.
개발자는 때때로 (이러한 중요한 방법을 생략 선두로 절단 된 모서리에 유혹 놀랍게 행동하거나 디버깅 가능성이 떨어짐)
또는 대체적이지만 완전히 적절한 클래스가 아닌 다른 클래스를 서비스에 제공해야합니다
( “올바른 모양”을 가지고 있고 다른 클래스를 선언하고 싶지 않기 때문입니다).

십오 도움이 될 것입니다 쓰기 대부분의 데이터 캐리어 클래스의 코드를하지만,
도움이 아무것도하지 않는 독자를 증류의 의도 디자인 “나는을위한 데이터 캐리어 해요 x, y그리고 z보일러의 라인의 수십에서”.
간단한 집계를 모델링하는 Java 코드 작성이 더 쉬워야합니다. 쓰기, 읽기 및 올바른지 확인하십시오.

기본적으로 보일러 플레이트 감소에 관한 것으로 레코드를 취급하는 것은 표면적으로 유혹적이지만,
대신 데이터를 데이터로 모델링 하는보다 의미론적인 목표를 선택합니다 .
의미가 맞으면 상용구가 자동으로 처리됩니다. 얕고 불변이고 잘 동작하는 명목 데이터 집계를 쉽고 명확하고 간결하게 선언해야합니다.

Non-Goals

“보일러 플레이트와의 전쟁”을 선언하는 것은 목표가 아닙니다.
특히, JavaBean 이름 지정 규칙을 사용하여 변경 가능한 클래스의 문제점을 해결하는 것은 목표가 아닙니다.
이 문제에 대한 “솔루션”으로 자주 제안 되기는하지만 속성, 메타 프로그래밍 및 주석 기반 코드 생성과 같은 기능을 추가하는 것은 목표가 아닙니다.

Description

레코드 는 Java 언어의 새로운 유형의 선언입니다. enum 과 마찬가지로 a record는 제한된 클래스 형식입니다.
표현을 선언하고 해당 표현과 일치하는 API를 커밋합니다.
레코드는 클래스가 일반적으로 즐기는 자유를 포기합니다.
즉 API를 표현에서 분리하는 기능입니다. 그 대가로, 기록은 상당한 정도의 결정을 얻습니다.

레코드에는 이름과 상태 설명이 있습니다. 상태 설명은 레코드 의 구성 요소 를 선언합니다.
선택적으로 레코드에는 본문이 있습니다. 예를 들면 다음과 같습니다.

1
record Point(int x, int y) { }

레코드는 데이터에 대한 단순하고 투명한 보유자라는 의미 론적 주장을하기 때문에 레코드는 많은 표준 멤버를 자동으로 획득합니다.

  • 상태 설명의 각 구성 요소에 대한 개인 최종 필드.
  • 상태 설명의 각 구성 요소에 대한 공용 읽기 접근 자 방법으로 구성 요소와 이름 및 유형이 동일합니다.
  • 서명이 상태 설명과 동일하고 해당 인수에서 각 필드를 초기화하는 공용 생성자.
  • 구현 equals과 hashCode는 동일한 유형이고 동일한 상태를 포함하는 경우, 두 개의 레코드가 동일한 말; 과
  • 그 구현 toString에는 이름과 함께 모든 레코드 구성 요소의 문자열 표현이 포함됩니다.

다시 말해서, 레코드의 표현은 구성, 해체 (초기 접근 자, 패턴 일치가있을 때 해체 패턴),
평등 및 표시에 대한 프로토콜과 마찬가지로 상태 설명에서 기계적으로 그리고 완전히 도출됩니다.

Restrictions on records

레코드는 다른 클래스를 확장 할 수 없으며 상태 설명의 구성 요소에 해당하는 개인 최종 필드 이외의 인스턴스 필드를 선언 할 수 없습니다.
선언 된 다른 모든 필드는 정적이어야합니다. 이러한 제한 사항은 상태 설명만으로 표현을 정의합니다.

레코드는 암시 적으로 최종적이며 추상적 일 수 없습니다.
이러한 제한 사항은 레코드의 API가 상태 설명만으로 정의되며 나중에 다른 클래스 나 레코드로 향상시킬 수 없음을 강조합니다.

레코드의 구성 요소는 내재적으로 불변입니다. 이 제한은 데이터 집계에 광범위하게 적용 되는 기본 정책에 따라 변경 불가능한 것을 구현합니다 .

위의 제한 사항 외에도 레코드는 일반 클래스처럼 동작합니다.
레코드는 최상위 수준으로 선언되거나 중첩 될 수 있으며 일반화 될 수 있으며 인터페이스를 구현할 수 있으며 new 키워드 를 통해 인스턴스화됩니다.
레코드의 본문은 정적 메서드, 정적 필드, 정적 초기화 자, 생성자, 인스턴스 메서드 및 중첩 형식을 선언 할 수 있습니다.
상태 설명의 레코드 및 개별 구성 요소에 주석을 달 수 있습니다. 레코드가 중첩되면 내재적으로 정적입니다.
이렇게하면 상태를 레코드에 자동으로 추가하는 즉시 둘러싸는 인스턴스를 피할 수 있습니다.

Explicitly declaring members of a record

상태 설명에서 자동으로 파생 된 멤버도 명시 적으로 선언 할 수 있습니다. 그러나 함부로 접근을 구현하거나 equals/ hashCode기록의 의미 불변 훼손 될 위험.

표준 생성자 (서명이 레코드의 상태 설명과 일치하는 생성자)를 명시 적으로 선언 할 때는 특별히 고려해야합니다.
생성자는 공식 매개 변수 목록없이 선언 될 수 있으며 (이 경우 상태 설명과 동일하다고 가정) 생성자 본문이 정상적으로 완료 될 때 확실히 할당되지 않은
레코드 필드는 해당 형식 매개 변수 ( this.x = x)에서 암시 적으로 초기화 됩니다.
출구. 이를 통해 명시 적 정식 생성자는 매개 변수의 유효성 검증 및 정규화 만 수행하고 명백한 필드 초기화를 생략 할 수 있습니다.

예를 들면 다음과 같습니다.

1
2
3
4
5
6
record Range(int lo, int hi) {
public Range {
if (lo > hi) /* referring here to the implicit constructor parameters */
throw new IllegalArgumentException(String.format("(%d,%d)", lo, hi));
}
}

Grammar

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
RecordDeclaration:
{ClassModifier} record TypeIdentifier [TypeParameters]
(RecordComponents) [SuperInterfaces] [RecordBody]

RecordComponents:
{RecordComponent {, RecordComponent}}

RecordComponent:
{Annotation} UnannType Identifier

RecordBody:
{ {RecordBodyDeclaration} }

RecordBodyDeclaration:
ClassBodyDeclaration
RecordConstructorDeclaration

RecordConstructorDeclaration:
{Annotation} {ConstructorModifier} [TypeParameters] SimpleTypeName
[Throws] ConstructorBody

Annotations on record components

레코드 구성 요소, 매개 변수, 필드 또는 메소드를 기록 할 수있는 경우 레코드 구성 요소에 선언 어노테이션이 허용됩니다.
이러한 대상 중 하나에 적용 할 수있는 선언 주석은 필수 구성원의 암시 적 선언으로 전파됩니다.

레코드 구성 요소의 유형을 수정하는 유형 주석은 위임 된 멤버의 암시 적 선언
(예 : 생성자 매개 변수, 필드 선언 및 메소드 선언)의 유형으로 전파됩니다.
필수 멤버의 명시 적 선언은 형식 주석을 포함하지 않고 해당 레코드 구성 요소의 형식과 정확하게 일치해야합니다.

Reflection API

다음과 같은 공개 방법이 추가됩니다 java.lang.Class.

  • RecordComponent[] getRecordComponents()
  • boolean isRecord()

이 메소드 getRecordComponents()는 java.lang.reflect.RecordComponent객체 의 배열을 반환 합니다.
여기서 java.lang.reflect.RecordComponent 새 클래스가 있습니다.
이 배열의 요소는 레코드 선언에 나타나는 순서대로 레코드의 구성 요소에 해당합니다.
RecordComponent 이름, 유형, 제네릭 형식, 주석 및 해당 접근 자 메서드를 포함하여 각 배열 에서 추가 정보를 추출 할 수 있습니다 .

isRecord()주어진 클래스가 레코드로 선언 된 경우 메소드 는 true를 리턴합니다. (isEnum() 과 비교하십시오 .)

Alternatives

레코드는 명목상의 튜플 로 간주 될 수 있습니다. 레코드 대신에 구조 튜플을 구현할 수 있습니다.
그러나 튜플은 일부 집계를 표현하는 더 가벼운 방법을 제공 할 수 있지만 결과는 종종 열등한 집계입니다.

  • Java 철학의 중심은 이름이 중요 하다는 것 입니다. 클래스와 멤버는 의미있는 이름을 가지고 있지만 튜플과 튜플 구성 요소는 그렇지 않습니다.
    즉, 인 Person 특성을 가진 클래스 firstName와 lastName 가 익명 String하고 String의 튜플보다 명확하고 안전.

  • 클래스는 생성자를 통해 상태 유효성 검사를 지원합니다.
    튜플은하지 않습니다. 숫자 범위와 같은 일부 데이터 집계에는 생성자가 적용하면 이후에 의존 할 수있는 변형이 있습니다.
    튜플은이 기능을 제공하지 않습니다.

  • 클래스는 상태에 따라 동작을 수행 할 수 있습니다. 상태와 동작을 함께 배치하면 동작을보다 쉽게 검색하고 액세스 할 수 있습니다.
    원시 데이터 인 튜플은 그러한 기능을 제공하지 않습니다.

Dependencies

레코드는 봉인 된 유형 (JEP 360) 과 잘 어울 립니다.
기록과 봉인 된 유형은 함께 대수 데이터 유형 이라고도하는 구조를 형성합니다.
또한 레코드는 패턴 일치에 자연스럽게 적용됩니다.
레코드는 API를 상태 설명에 연결하기 때문에 결국 레코드에 대한 해체 패턴을 도출 할 수 있으며
봉인 된 유형 정보를 사용 switch하여 유형 패턴 또는 해체 패턴이 있는 표현식의 소진 성을 결정할 수 있습니다.

참조