Javaこのエントリは以下の記事を基にしています。Javaのアップデートです。調査目的の文書であり、Java言語の特定のバージョンにおける特定の機能の計画ではありません。Typeが提示されています)。(Preview)http://openjdk.java.net/jeps/360Backgroundよく、「Javaは冗長すぎる」だの、「お作法が多すぎる」だのという苦情を耳にします。これは、クラスが柔軟に様々なプログラミング・パラダイムをモデリングできるものの、それにはモデリングのオーバーヘッドが伴うためです。Carrier)にすぎないクラスの場合、これらのモデリング・オーバーヘッドは、そのクラスが持つ値に見合っていない可能性があります。シンプルなデータキャリアクラスを責任を持って記述するためには、コンストラクタ、アクセサ、equals()、hashCode()、toString()など、低価値で反復的なコードを大量に記述する必要があります。それゆえ、開発者たちは時としてこうした重要なメソッドを省略する誘惑に駆られることがありますが、それが原因で驚くべき動作や貧弱なデバッグにつながったり、または「正しい形」を持っていてさらに別のクラスを定義したくないため、完全に適切ではない代替クラスを使用したりすることになってしまいます。IDEはこうしたコードの大部分を作成するのに役立ちますが、コードの作成は問題のほんの一部にすぎません。readerが何十行もの定型コードから「x、y、およびzの単純なデータキャリアです」という設計意図を抽出する支援をIDEはやりません。ボイラープレート・コードにはよくバグが紛れこみます。可能であれば、隠れ場所を完全に排除するのが最善です。プレーン・データキャリアに公式の定義はありませんし、”plain”がまさに何を意味しているのかという点には様々な意見があります。誰もSocketInputStreamがただのデータキャリアとは思っていないでしょう。複雑で不特定の状態を完全に隠蔽し、内部表現のように見えないインターフェイスコントラクトを公開します。対して、以下は非常に明確です。y)のペアを受け入れて、この表現に直接格納します。この表現への直接アクセスを提供し、その表現から直接コアのObjectメソッドを導出します。中央には、線を引く必要がある灰色の領域があります。classといった、データ指向クラスをモデリングするためのコンパクトな構文形式を調査してきました。これらには、クラスの状態の一部またはすべてをクラスヘッダーに直接記述できるという共通点がありますが、セマンティクスは異なります(フィールドの可変性またはアクセシビリティの制約、クラスの拡張性、およびその他の制限など)。C#https://github.com/dotnet/roslyn/blob/master/docs/features/records.mdクラス宣言で、状態とインターフェースの関係の少なくとも一部にコミットすることにより、多くの一般的なメンバーの適切なデフォルトを導き出すことができます。」と呼びましょう)はすべて、Pointを次のようなものとして定義できるという目標に近づけようとしています。}ここでの明快さとコンパクトさは確かに魅力的です。Pointは2つの整数コンポーネントxとyの単なるキャリアであり、この情報から、読者はコアのObjectメソッドの道理に適った正しい実装があることがすぐにわかります。ボイラープレートのページを読み解いて、セマンティクスについて自信を持って推論できるようにする必要はありません。ほとんどの開発者は、「もちろん、それが欲しい」と言うでしょう。存在するコードだけが明白ではないことを実際にするコードである、という状況に近づきます。読む量が減り、各行が有用であるという点で、コードの読み取りが簡単になります。elephant残念ながら、そのような普遍的なコンセンサスは構文の深さだけです。簡潔さを祝い終えた直後に、そのような構造の自然なセマンティクスと、どのような制限を受け入れるかー拡張可能なのか、フィールドは変更可能なのか、生成されたメソッドの動作やフィールドのアクセシビリティを制御できるのか、追加のフィールドとコンストラクターを使用できるのか、といった議論が始まります。「群盲象を評す」の話のように、開発者はデータクラスのセマンティクスについてまさに異なる仮定を持ち込む可能性があります。これらの暗黙の仮定を公開するために、様々なポジションを命名しましょう。Annieなら、「データクラスは単なる代数的直積型です」と言うでしょう。classのように、パターンマッチングとペアになっており、イミュータブルなものとして提供されます(そして、デザートには、Annieは密封されたインターフェースを注文するでしょう)。Jerryであれば「もちろん、これらはJavaBeansの代替品です。Pattyであれば、彼女がエンタープライズPOJOに圧倒されていると述べ、Hibernateのようなフレームワークによってプロキシ可能になることを期待しています)。Tommyなら、「データクラスは単なる名目上のタプルである」と言うでしょう。コアのObjectメソッド以外のメソッドを持つことを期待してはならず、これらは単なる最も単純な集約だ、ということです(彼は同じ名前の2つのデータクラスを自由に変換できるように、名前の消去を期待しているかもしれません)。Victorなら、「データクラスは実際には、より透過的な値タイプです」と言うでしょう。これらのすべてのペルソナは「データクラス」に賛成して団結していますが、データクラスが何たるかという点で異なる考えを持っているため、全員を満足させるソリューションはありません。boundaries日々取り扱う状態関連のボイラープレートを痛感していますが、ボイラープレートは、より深い問題の症状に過ぎません。Javaは、すべてのクラスに対しカプセル化のコストに対して平等に支払うことを求めています。いえ、すべてのクラスが平等に恩恵を受けられるわけではありません。確かに、カプセル化は不可欠です。状態へのアクセスを仲介し(なので、監視のない状態で操作できません)、表現をカプセル化する(なので、APIコントラクトに影響を与えずに進化させることができます)ことで、さまざまな境界を越えて安全かつ堅牢に動作できるコードを記述できます。整合性の境界:クライアントの意図を信頼し、データをクライアントと共有することを望んではいるが、独自の表現の不変条件を維持するタスクをクライアントに負担したくないために、状態をクライアントに公開したくない場合バージョン管理の境界:あるバージョンのライブラリに対してコンパイルされたクライアントが、後続のバージョンに対して実行されたときに引き続き動作することを保証したい場合。すべてのクラスが境界を等しく評価するわけではありません。これらの境界を守ることは、KeyStoreやSocketInputStreamのようなクラスにとって不可欠ですが、Pointのようなクラスや典型的なドメインクラスにとっては価値がありません。packageまたはmoduleに対してprivateで、クライアントと一緒にコンパイルされるクラスや、クライアントを信頼しているクラス、そして保護が必要な複雑な不変条件を持たないクラスなどのような、多くのクラスにとって境界の保護はまったく関心がありません。これらの境界を確立し保護するコスト(コンストラクター引数を状態にマップする方法、状態から同等性のコントラクトを導出する方法など)はクラス全体で一定ですが、メリットはそうではないため、コストがメリットと一致しない場合があります。これは、Java開発者が「多すぎるお作法」として表現しているものです。作法には価値がないということではなく、十分な価値を提供できない場合でも、作法通りに呼び出すことを強制されます。構築、状態へのアクセス、同等性から表現が完全に切り離されるという、Javaが提供するカプセル化モデルは、多くのクラスが必要とするもの以上のものです。境界との関係が単純なクラスは、クラスをその状態の薄いラッパーとして定義し、そこから状態、コンストラクト、等式、状態アクセスの関係を導出できる単純なモデルの恩恵を受けることができます。表現をAPIから分離するコストは、定型的なメンバーを宣言するオーバーヘッドを上回ります。カプセル化は、その性質上、情報を破壊します。引数xを受け取るコンストラクターとx()というアクセサーを持つクラスの場合、それらがおそらく同じものを参照していることを示すための規則しかありません。この規則に頼ることはかなり安全な推測かもしれませんが、単なる推測にすぎません。人間が仕様(もし一つだけとしても)を読み上げてこの期待を確認せずに、ツールとライブラリコードがこの対応に機械的に依存できればよいのですが。enums問題が非常に一般的なもので単純なものをモデリングしているという場合、単純化は制約から生じています。ある程度の自由を手放すことで、すべてを明示的に指定する義務から解放されることを望んでいます。5で追加されたenumは、このようなトレードオフの優れた例です。言語に列挙型を追加する最初の動機は、このイディオムに必要な定型句に対するいらだちだったかもしれませんが、本当の利点はセマンティック(意味論)です。Editionhttps://www.amazon.com/gp/product/0321356683enumの重要な単純化は、インスタンスのライフサイクルを制限することでした。列挙型定数はシングルトンであり、インスタンス化はランタイムが管理します。シングルトンの認識を言語モデルに組み込むことにより、コンパイラは、タイプセーフな列挙パターンに必要な定型句を安全かつ正しく生成できます。enumは構文上の目標ではなく意味論上の目標から始まったため、enumが他の機能と積極的に対話できました。具体的には、enumを有効にしたり、コストなしで比較と安全なシリアル化するといったことです。驚くべきことに、enumは、クラスが享受する他のほとんどの自由度を放棄せずに、構文およびセマンティックの利点を提供しました。Javaの列挙は、他の多くの言語にあるような単なる整数の列挙ではなく、本格的なクラスです(いくつかの制限があります)。このアプローチの成功をデータクラスで再現しようとする場合、最初の質問は次のとおりです。どのような制約によって、必要なセマンティックおよび構文上のメリットがもたらされるかそしてこれらの制約を受け入れるのか。goalsデータクラスを主にボイラープレートの削減に関するものとして扱うのは表面的には魅力的ですが、データとしてデータをモデリングするという、セマンティックな目標から始めたいのです。目標を正しく選択すると、ボイラープレートがそれ自体を処理し、簡潔さに加えてさらなるメリットを享受できます。「データをデータとしてモデル化する」とはどういうことでしょうか?また、あきらめなければならないものは何でしょうか?モデルを排除し、それによってモデルを単純化できる「単純な」データ集約は、クラスが享受する自由度のどの程度を必要としないのでしょうか?Javaのオブジェクトモデルは、オブジェクトの表現をそのAPIから完全に切り離したいという前提に基づいて構築されています。コンストラクター、アクセサメソッド、およびオブジェクトメソッドのAPIと動作は、オブジェクトの状態に直接一致する必要はなく、相互に一致する必要さえありませんが、実際には多くの場合、より密接につながっています。Pointオブジェクトには、フィールドxとy、xとyを受け取ってそれらのフィールドを初期化するコンストラクター、xとyのアクセッサ、およびxとyの値だけでポイントを特徴付けるObjectメソッドがあります。「単なるデータの単なるキャリア」であるクラスにとって、この結合は信頼できるものであると主張します。そのAPIから(パブリックに宣言された)状態を分離する機能を放棄しているということです。データクラスのAPIは、状態、状態全体をモデル化、つまり状態のみをモデル化します。この結果、データクラスは透過的になり、すべての要求者にデータを自由に明け渡します(それ以外の場合、APIは状態全体をモデル化しません)。この結合を頼りにできると、様々な利点がもたらされます。標準クラスのメンバーに対して、賢明で正しい実装を導出できます。クライアントは、集計を自由に分解および再構築したり、より便利な形式に再構築したりできます(隠蔽されたデータを破棄したり、背後の仮定を損なうことを恐れたりする必要はありません)。フレームワークは、安全かつ機械的にシリアル化またはマーシャリングできます(複雑なマッピングメカニズムを提供する必要はありません)。クラスの状態をそのAPIから切り離す柔軟性を放棄すれば、これらの利点をすべて得ることができます。typesrecordの形式でデータクラスを表示することを提案します。列挙のように、recordはクラスの制限された形式で、その表現を宣言し、その表現に一致するAPIにコミットします。classの最終的な形式であり、subtypeは一切許可されません。typeを使用して単純な算術式をモデル化する場合、次のようになります。}これは、ConstantExpr(1個の整数を保持)、PlusExprとTimesExpr(2つの部分式を保持)、およびNegExpr(1つの部分式を保持)という4つの具象型を宣言しているとともに、式の共通supertypeを宣言し、これらがExprという唯一のsubtypeであるという制約を保存しています。フィールド、コンストラクタ、アクセッサ、equals()、hashCode()、toString()という、あらゆる通常のメンバーを取得します(デフォルト実装が不適切な場合、明示的に指定できます)。recordは、ボイラープレートと情報の比率を調整するために列挙型と同じ戦術を使用します。標準メンバーの派生を可能にするより一般的な機能の制約バージョンを提供します。列挙型は、インスタンス制御をランタイムに委譲するようユーザーに要求します。その代わりに、この言語はインスタンスの効率的な宣言を提供するだけでなく、Object::equals、Enum::values、シリアル化といったコア動作の実装を提供できます。recordについても同様の取引を行っていて、高度に合理化された宣言(およびその他)を取得する代わりに、柔軟性を放棄して、クラスAPIをその状態の説明から切り離しています。matching単なる定型文を減らしたクラスとしてではなく、パブリックに指定された状態記述にAPIを結合する点で、データクラス定義の大きな利点の1つとして、データクラスを集約形態と展開状態の間で自由に変換できる、という点があります。これは、パターンマッチングと自然に結びつきます。patternを導出することもできます。(Preview)https://openjdk.java.net/jeps/305Expr階層を考えると、式を評価するためのコードは次のようになります。}}recordが自動的に取得する機械的に生成されたパターン抽出器を使用しています。typeの両方に、パターンマッチングとの相乗効果があります。typeはコンパイラに網羅的な情報を提供て、すべてのsubtypeをカバーするswitchでdefault句を提供する必要がないようにします。externalizationデータクラスは、安全で機械的な外部化(シリアル化、JSONまたはXMLへのマーシャリングおよびアンマーシャリング、データベース行へのマッピングなど)にも自然に適合します。クラスが状態ベクトルのトランスペアレントキャリアであり、その状態ベクトルのコンポーネントを目的のエンコーディングで外部化できる場合、保証された忠実度でキャリアを安全かつ機械的にマーシャリングおよびアンマーシャリングできます。その際(組み込みのシリアル化が行うように)コンストラクターをバイパスするというセキュリティと整合性のリスクはありません。実際、トランスペアレントキャリアは、外部化をサポートするために特別なことをする必要はありません。外部化フレームワークは、その解体パターンを使用してオブジェクトを解体し、すでにpublicなコンストラクタを使用してオブジェクトを再構築できます。tuples?この時点でタプル(tuple)さえあればデータクラスは必要ない、と考えている人がいらっしゃることでしょう。タプルは集計を表現するためのより軽量な手段を提供しますが、結果はしばしば劣った集計になります。クラスとクラスメンバーには意味のある名前を有していますが、タプルとタプルコンポーネントはそうではありません。Javaの哲学の中心は、名前が重要であるということです。プロパティfirstNameとlastNameを持つPersonは、StringとStringのタプルよりも明確で安全です。クラスは、コンストラクタによる状態検証をサポートしていますが、タプルはサポートしていません。クラスの場合、(数値範囲などの)一部のデータ集計には不変式がありますが、コンストラクターによって実施される場合、その後不変式に依存できます。ところがタプルにはこの機能がありません。クラスは、その状態から導出された動作を持つことができます。状態と派生した動作を同じ場所に配置することで、検出しやすくなり、アクセスしやすくなります。これらすべての理由から、データのモデリングのためにクラスを放棄したくありません。クラスを使ってデータを簡単にモデリングしたいだけです。集計に名前付きクラスを使用する際の問題点は、宣言のオーバーヘッドであり、これを十分に減らすことができれば、より弱く型付けされたメカニズムに手を伸ばしたくなる誘惑が大幅に減ります(recordについて考える上での良い出発点は、それらが名目上のタプルであるということです。type間の重複について、そしてデータ性と値性の交差する場所が居住するのに有用な空間であるかどうかを尋ねてみてもいいでしょう。typeには、明確な類似点があります。両方とも不変(immutable)の集合体であり、拡張に制限があります。これらは本当に同じ機能の表現を変えたものなのでしょうか。両者のセマンティック上のゴールを確認すれば、両者が異なることがわかります。typeは、メモリ内におけるオブジェクトのフラットで密なレイアウトを可能にすることを主目的としており、オブジェクトのIDを放棄することと引き換えに(これにより、可変性とレイアウトのポリモーフィズムを放棄する必要があります)、ランタイムはヒープのレイアウトを最適化し、値の呼び出し規約を最適化する機能を獲得します。recordを使用すると、クラスAPIをその表現から切り離す機能を放棄する代わりに、表記法およびセマンティック上の多くの利点が得られます。typeの場合は依然として状態のカプセル化の恩恵を受けますし、recordの場合は依然としてアイデンティティの恩恵を受ける可能性があるため、まったく同じ取引というわけではありません。recordと呼びます。そのため、必ずしも一方もしくは他方のメカニズムのみを使用する必要はありませんが、連携するメカニズムがほしいのは確かです。union)の組み合わせを指しています。Type)の名前がデカルト積に由来しているのは、その値セットが型のベクトルの値セットのデカルト積であるためです。タプルは、(firstNameとlastNameというStringのフィールドを持つPerson型のような)多くのアドホックドメインクラスと同様に、直積型の一種です。union)は、固定された型セットの区別された和集合です。列挙型は共用体の一種です(共用体メンバーは定数です)。ある言語では代数的データ型を直接サポートしている場合があります。HaskellではExpr階層に相当するものをdataコンストラクトを使って宣言します。Eq);(deriving節は、これらの型が自動的に明示的に相当するObject::equalsとObject::toStringに明示的に相当するものを取得することを示しています。casesrecordおよびrecordのシールされた階層には、多くのユースケースがあります。典型的な例をご紹介します。nodes前述のExprの例では、recordがどのようにドキュメント、クエリ、式を表すツリーノードを手早く片付けることができるのかを示しています。sealを使うことで、開発者やコンパイラは全てのケースを網羅した時期を推論できます。ツリーノードでのパターンマッチングは、Visitorパターンよりも直接的で柔軟なトラバーサルの代替手段を提供します。values効率(1回のパスで複数の量を抽出する方が2回のパスを行うよりも効率的な場合があります)または一貫性(可変データ構造で操作する場合、2番目のパスは別の状態で動作している可能性があります)の理由で、メソッドが1個以上返すことが望まれる場合が多々あります。配列の最小値と最大値の両方を取り出すとします。2つの整数を保持するようにクラスを宣言するのは過剰に思えるかもしれませんが、宣言のオーバーヘッドを十分に減らすことができる場合、カスタムの直積型を使用してこれらの関連する数量を表せると魅力的で、より効率的な(そして読みやすい)計算が可能になります。tuple)を介してこの機能を公開することを確実に好むでしょう。MinMax型を宣言するコストを合理的なところにまで減らしたため、メリットはコストと並び始めました。minやmaxなどの名目上のコンポーネントは、単純な構造タプルよりも読みやすく、エラーが発生しにくくなっています。Pairでは何を表すか、読者はわかりませんが、MinMaxはわかります(また、コンパイラは、両方がintのペアとしてモデル化されていても、誤ってRangeにMinMaxを割り当てられることを防ぎます)。objectsデータ転送オブジェクトは、関連する値をパッケージ化して、単一の操作で別のアクティビティと通信できるようにすることを唯一の目的とする集約です。通常、データ転送オブジェクトには、状態の保存、取得、およびマーシャリング以外の動作はありません。operations組み立て量があるとして、その組み立て量を操作するストリーム操作(フィルタリング、マッピング、ソート)を実行したいとします。(大文字に正規化された)オブジェクトの名前が最大のhashCode()を持つPersonオブジェクトを選択したい場合、recordを使用して1個以上の組み立て量を一時的にアタッチし、それらを操作してから、次のように目的の結果に戻すことができます。.collect(toList());}ここでは、Personに組み立て量を付け加えることから始め、その組み合わせに対して通常のストリーム操作を実行し、完了したらラッパーを破棄してPersonを抽出します。余分なオブジェクトを実体化しなくてもこれを実現できたでしょうが、各要素についてさらに何度もハッシュ(と大文字)を計算する必要が生じる可能性がありました。keys2つの異なるドメイン値の組み合わせをキーとするマップが必要な場合があります。特定の人物が特定の場所で最後に見られた時間を表現したいものとします。キーとしてPersonとPlaceを組み合わせ、値としてLocalDateTimeを持つHashMapでこれを簡単にモデル化できますが、システムにPersonAndPlace型がない場合は、コンストラクタ、equals、hashCodeなどのボイラープレート実装を使用して記述する必要があります。複合マップキーとして使用できます。アクターベースのシステムおよび(Kafkaのような)他のメッセージ指向システムでメッセージを表現する場合に一般的に有用です。アクターが交換するメッセージは、直積が理想的に表現します。アクターが一連のメッセージに応答する場合、これは直積の合計で理想的に表現します。合計タイプの下でメッセージのセット全体を定義できることにより、メッセージングAPIのより効果的なタイプチェックが可能になります。wrappersクラスOptionalは、変装した代数的データ型です。value)とNone型(コンポーネントを持たない、縮退した積)の合計として定義されます。同様にEither型は、Left型とRight型の和として記述できます(JavaにOptionalが追加された時点では、代数的なデータ型もパターンマッチングもなかったため、従来のAPIイディオムを使用して公開することは理にかなっています)。entitiesより洗練された例は、識別されたエンティティを返す必要があるAPIです。APIの呼び出しをコンパイル時により効率的な表現に変換できるメカニズムで拡張されています。processor)」間の会話が含まれます。siteに関する情報をプロセッサに渡し、プロセッサは呼び出しを変換する方法(またはしない)の説明を返します。その選択肢は以下の通りです。typeとrecordを使用すると、APIは次のようになります。siteの情報を受け取り、以下のいずれかを返します。(指定された定数で呼び出しを置き換える)この積和は、宣言がコンパクトで、読みやすく、パターンマッチングで簡単にdeconstructionできます。このようなメカニズムがなければ、APIを読みにくくしたり、エラーを起こしやすい方法で構成したくなるかもしれません。Recordsrecordは、クラスが通常享受する重要な自由度、つまりクラスAPIをその表現から切り離す機能を放棄します。recordには、名前、状態の説明、および本体があります。何者でもない」ので、ほとんどのメンバーを機械的に導出できます。patternsまたはアクセッサ、あるいは両方)、同値性、そして表示のプロトコルは全て同じ状態記述から派生しています。records列挙型(enum)のようなrecordはクラスです。recordの宣言には、アクセシビリティ修飾子、Javadoc、注釈、implements句、および(レコード自体は暗黙的にfinalですが)型変数など、クラス宣言でできることのほとんどが含まれています。コンポーネント宣言には注釈とアクセシビリティ修飾子を含めることができます(コンポーネント自体は暗黙的にprivateでfinalです)。本体には、静的フィールド、静的メソッド、静的初期化子、コンストラクター、インスタンスメソッド、インスタンス初期化子、およびネストされた型が含まれる場合があります。コンパイラーが暗黙的に提供するメンバーのいずれについても、これらを明示的に宣言できますが、不注意にアクセッサやequals、hashCodeをオーバーライドすると、recordのセマンティック不変性を損なう可能性があります。デフォルトコンストラクタ(そのシグネチャがrecordの状態表現のシグネチャと一致するもの)を明示的に宣言するための特別な考慮事項が提供されています。(状態表現と同一であるため)引数リストは省略されます。x)で暗黙的に初期化されます。これにより、コンストラクタ本体では引数の検証と正規化のみを指定し、フィールドの初期化を省略できます。patternを派生します。そのため、これらがオーバーライドされるとdeconstructionのセマンティクスにも反映されます。ネストされたコンテキストで宣言されたrecordは暗黙のうちにstaticです。ends上記はただのスケッチであり、細かい部分でやることがたくさんあります。Javadocフィールドとアクセッサメソッドはクラス宣言の一部として宣言されているため、Javadoc規約を少し調整してこれに対応する必要があります。これは、recordに@paramタグを許可すれば可能で、フィールドとアクセッサのドキュメントに伝播できます。Annotationsrecordコンポーネントは、注釈を付ける新しい場所を構成します。これを反映するために、@Targetメタアノテーションを拡張することになるでしょう。Reflectionrecordとはセマンティックステートメントであるため、recordであること、そして状態コンポーネントの名前と型がリフレクティブに利用可能でなければなりません。(enumクラスにあるように)追加のメソッドや仕様が存在できる、recordの基本型を検討してみるのもよいかもしれません。Serializationrecordの利点の1つに、マーシャリングとアンマーシャリングのより安全なプロトコルを機械的に導出できることがあります。これを利用する賢明な方法は、Serializableを実装するrecordが状態を抽出し、コンストラクターを使って状態を抽出して状態を巻き戻すreadResolveメソッドを自動的に取得して、悪意のあるストリームが不正なデータを注入しないようにすることです。Extensionrecordが抽象recordの拡張を許可することも可能です。これにより、関連するrecordが特定のメンバーを共有できるようになります。この可能性を保持すべきでしょう。Compatibilityコンポーネントの引数の個数、名前、および型を直接メンバーのシグニチャおよび名前に直接伝搬するため、状態記述への変更はソース互換またはバイナリ互換ではない場合があります。APIの一部を形成するため、コンストラクタの名前付き呼び出しへの門戸を開きます。これにより、ほとんどの場合、ドメインクラスに伴うコンパニオンビルダーを廃止できます(すべてのクラスでこれをサポートするのはよいのですが、recordにはこれをそれほど複雑にしない特別なプロパティがあります。recordから始めて拡張することを検討するかもしれません)。Restrictions注意深い読者は、いくつかの制限に気付くでしょう。recordのフィールドは変更できません。状態記述にあるフィールド以外は許可されません。recordは他の型を拡張したり、recordを拡張したりすることはできませんこうした制限のそれぞれが息苦しく感じられて、その適用性を広げるために構造をより柔軟にしようとする誘惑に駆られるような状況は簡単に想像できます。そもそも単一の状態記述からすべてを引き出すことができるという状況を犠牲にするべきではありません。recordは何も拡張できません。同様に、recordを拡張できる場合、その状態記述は、その状態を完全に記述するものではありません(これは、通常の拡張を除外することに加えて、動的プロキシも除外することに注意してください)。Mutability理論的には、目標に反しない例を想像できるため、可変性に対する制約はより複雑です。可変性は、状態とAPIの間の整合に影響を与えます。equals()およびhashCode()のセマンティクスが可変状態に基づくことは一般に正しくありません。可変状態に基づくと、そのような要素がHashSetやHashMapから静かに消えてしまうリスクが生じます。したがって、recordへの可変性の追加は、状態記述とは異なる等値プロトコルが必要になる可能性がありますし、別のconstructプロトコルが必要な場合もあります(多くのドメインオブジェクトは、引数なしのコンストラクタで作成されてsetterを使って状態を変更したり、「主キー」フィールドのみを取るコンストラクタで状態を変更したりします)。今では、単一の状態記述から主要なAPI要素を導き出すことができる、という主要な差別化機能を見失ってしまいます(そして、可変性を導入すると、recordの目標との調整が困難になるスレッド・セーフについて考える必要があります)。Beansなど)や、長年にわたって取得した「ノブ」の数を調べるだけで十分です。これらのクラスは単純に自由度が高すぎて1個のシンプルな記述で把握できません。セマンティクスが明確に定義された名目上のタプルは、多くのユースケースでプログラムをより簡潔かつ信頼性の高いものにすることができますが、それでもタプルの制限を超えるユースケースがあります(これらのクラスに対してできることがないという意味ではなく、単にこの機能ではできない、ということです)。したがって、明確にするために、recordはJavaBeansやその他の変更可能な集合を置き換えるものではありませんし、それで問題ありません。fields関連する懸念に、recordが状態記述の一部であるフィールド以外のフィールドを宣言できるかどうかがあります(また、これが安全な例を簡単に想像できます)。何者でもない」のモットーに反する誘惑、避けた方がよい誘惑が再度出てきます。(finalityは縮退したsealと考えることができます)。sealには2つの明確な目的があります。1つ目は、subtypeにできる人を制限することです。これは主に、API所有者がAPIの整合性を守ることを望む、declaration-siteの懸念事項です。typeの型パターンを切り替える場合など、use-siteで徹底的な分析が可能になることです。クラスにsealedという修飾子を適用してクラスや抽象クラス、インターフェースをsealします。オプションとしてpermitsリストを付加できます。}この明示的な形式では、permitsリストで列挙された型によってのみNodeを拡張できます(さらに、同じパッケージやモジュールのメンバーである必要があります)。多くの状況では、これは過度に明示的である可能性があります。全てのsubtypeを同じコンパイル単位で宣言すると、permits句を省略できます。この場合、コンパイラは現在のコンパイル単位にあるsubtypeを列挙して推論します。typeの匿名subclass(とlambda)は禁止されています。Sealingは、finalityと同様に、言語とJVMの両方の機能です。型の密閉性と許可されるsubtypeのリストは、実行時に強制できるようにクラスファイルで具体化されます。許可されたsubtypeのリストも、何らかの方法でJavadocに組み込む必要があります。これは、現在Javadocに含まれている現在の「すべての実装クラス」リストとまったく同じではないため、「すべての許可されたsubtype」のようなリストが追加される可能性があります(おそらくsubtypeが親よりもアクセスし辛い場合に何らかの指示があるか、もしくはリストになっていない他のものがそこに存在するという注釈が含まれます)。typeの許可されたsubtypeを列挙できることです。typeを含むパターンの切り替え時に徹底的な分析を実行できます。moduleを宣言することは魅力的で、これを使えば、すべてをリストアップせずに、パッケージの仲間またはモジュールの仲間が型を拡張できます。これはパッケージとモジュールが必ずしも同時にコンパイルされるとは限らないため、網羅性について推論するコンパイラの能力を損なうことになります。対して、subtypeはシールされた親のようにアクセス可能である必要はありません。この場合、クライアントの中には徹底的に切り替える機会を得られない場合があります。default句またはその他の全体パターンを使用して、これらのswitchで網羅する必要があります。typeであることはわかりますが、すべてのsubtypeを確認できるわけではないため、ここでは完全な完全性チェックを提供できません。そのためやはりdefaultが必要です。typeの抽象subtypeは暗黙的に封印され、具象subtypeは暗黙的にfinalです。これは、subtypeを明示的にnon-sealで変更すると元に戻すことができます(ただしrecordは対象外で、recordは全てfinalです)。階層内のsubtypeを開封しても、明示的に許可されたsubtypeの(推定される可能性がある)セットが依然として完全なカバーを構成するため、シーリングのすべての利点が損なわれるわけではありませんが、シールされていないsubtypeを知っているユーザーは、この情報を活用できます(必要に応じてIOExceptionとは別にFileNotFoundExceptionをキャッチできます)。明示的にシールされていないprivateのsubtypeが有用な例が、JEP-334にあります。typeの組み合わせにより、強力でよく理解された構造化データの関係するグループの表現パターンに従います。そのため、多くの状況で一般的なコードの可読性と簡潔性を向上させる可能性があります。recordは宣言の定型文の記述を避けたいコードの全てに適しているわけではありません。したユースケースにおける状況を改善するような機能の検討を引き継き計画しています。Inside現在40人フォロワーがいます。購読管理このバーを折りたたむ%d人のブロガーが「いいね」をつけました。