データクラスは、特定のプログラミング言語に縛られていない概念であり、情報を表現し、カプセル化し、移動する簡単な方法として、ほとんどのプログ

データクラスは、フィールドとそれらにアクセスするためのcrudメソッド(getterとsetter)のみを含むクラスを指します。 これらは単に他のクラスで使用されるデータのコンテナです。 これらのクラスには追加の機能は含まれておらず、所有するデータを個別に操作することはできません。

通常、データクラスは現実世界のエンティティを表し、プロジェクトには数十または数百のこれらのクラスがあるのが一般的です。

Javaのデータクラス

これは、データクラスが通常Javaでどのように見えるかです:

toString()equals()、およびhashCode()メソッド(Object.javaクラスで宣言)をオーバーライドしていることがわかります。 これらのメソッドをオーバーライドすることがデータクラスに関連するのはなぜですか?

これらの三つのメソッドを実装するとき、我々は値オブジェクトを作成し、適切に等しいフィールド値を持つ任意の二つのインスタンスが交換可能 (注:完全に真実であるためには、クラスを不変にする必要があります。 フィールドを最終的にし、セッターを削除すると役立ちます。 不変性はしばしば良い方法と考えられ、可能であれば推奨されます)

  • equals() : デフォルトでは、2つの変数が同じオブジェクトを参照している場合、つまりメモリ内の位置が同じ場合にのみtrueを返します。 このメソッドは、オブジェクトに同じ情報が含まれている場合、つまりオブジェクトが同じエンティティを表す場合にtrueを返すためにオーバーライド プロパティが同じであり、同じ値が含まれていることを確認します。
  • hashCode() : デフォルトでは、オブジェクトのメモリアドレスを16進数で返します。 これは、等価テスト中にオブジェクトを識別するための数値です。 このメソッドは、プロパティの値から計算されたハッシュコードを返すように、toString()がオーバーライドされるときにオーバーライドする必要があります。
  • toString(): デフォルトでは、オブジェクトタイプとhashCode()、たとえば[email protected]+を返します。 このメソッドは、User(name=Steve, surname=Jobs)のようなより人間が読めるバージョンのオブジェクトを持つためにオーバーライドします。

このような重要な概念であるにもかかわらず、上記のJavaコードには、このクラスを他のクラスと異なるものにするものは何もありません。 プログラマは、クラス構造とパターンのためにデータクラスとして認識できますが、コンパイラの観点からは、このクラスは単なる別のクラスです。

データクラスの作成は非常に一般的であるため、開発者はIDEやその他のプラグインを使用してこの反復的な作業を支援することがよくあります。 Javaでデータクラスを作成する際の苦痛はプラグインやIDEによって軽減できますが、ほとんどのバグはそれらのクラスのさらなる変更に導入されて フィールドが削除または追加されるたびに、すべてのコンパニオンメソッドを変更することを忘れるのは非常に簡単です。

Javaのデータクラスには言語サポートがありません。 これは、現代のプログラミング言語にとってあまりにも多くの摩擦を表す反復的でバグが発生しやすいタスクです。

Kotlinのデータクラス

Kotlinの同じデータクラスは次のようになります:

data class User(var name: String, var age: Int)

Kotlinはデータクラスをファーストクラスの市民に昇格させ、dataキーワードを導入します。 それを打破しましょう。

  • Getterとsetter

プロパティを宣言すると、getterとsetterがKotlinで自動的に作成されます。 要するに、var name: Stringが意味するのは、Userクラスにはpublic(Kotlinのデフォルトの可視性)、mutable(var)、およびString型のプロパティがあるということです。 それがpublicであるとgetterが作成され、それが可変であるとsetterが作成されます。

クラスを読み取り専用(セッターなし)にしたい場合は、次を使用する必要がありますval :

data class User(val name: String, val age: Int)

同じクラス宣言でvalvarを混在させることができます。 Javaではvalfinal変数と考えることができます。Kotlinのクラス宣言には共通していますが、dataキーワードがここで違いを生み出しています。

  • dataキーワード

クラスをデータクラスとして宣言すると、上記のJavaクラスと同じ方法でtoString()hashCode()equals()が自動的に実装されます。 したがって、User("Steve Jobs",56)のようなuserクラスを作成し、toString()メソッドを呼び出すと、User(name=Steve Jobs, age=56)のようなものが得られます。

デストラクチャリング宣言

dataキーワードは、デストラクチャリング宣言を可能にする関数を提供します。 要するに、すべてのプロパティに対して関数を作成するので、次のようなことができます:

コピー関数

dataキーワードは、いくつかのプロパティの値を変更するクラスをコピーする便利な方法を提供します。 年齢を変更するユーザーのコピーを作成する場合、これは私たちがそれを行う方法です:

クラス本体で宣言されたプロパティは無視されます

コンパイラは、自動的に生成された関数のプライマリコンストラクタ内で定義されたプロパテ

プロパティaddressdataキーワードでは扱われないため、自動生成された実装はそれを無視することを意味します。

PairとTriple

PairTripleはライブラリの標準データクラスですが、Kotin docs自体は、より読みやすくカスタム仕立てのデータクラスを優先してそれらの使用を推奨し

要件と制限

  • データクラスコンストラクタは、少なくとも一つのパラメータを持つ必要があります。
  • すべてのパラメータはvalまたはvarとして市場である必要があります。
  • データクラスは次のようにすることはできませんabstract, open, sealed またはinner
  • equals , toString また、hashCodeメソッドは明示的にオーバーライドできます。
  • componentN()およびcopy()関数の明示的な実装は許可されていません。
  • シグネチャに一致するcopy()関数を持つ型からデータクラスを派生させることは、Kotlin1.2では廃止予定であり、Kotlin1.3では禁止されていました。
  • dataクラスは別のdataクラスから拡張することはできません。
  • Adataクラスは他のクラスを拡張することができます(Kotlin以降1.1)

データクラスはKotlinのファーストクラスの市民です。 非常に短い構文では、それらはすべての利点と妥協のない摩擦のない解決策を提供します。

Androidの場合、どういう意味ですか

AndroidプロジェクトでKotlinデータクラスを使用して見つけた主な利点を説明しようとします。 これらはすべてではなく、最も重要なものではないかもしれませんが、これまでの私の経験から最も明白です。

  • データモデル

Androidのアーキテクチャは、ホットな話題でした(そしてまだです)。 複数の選択肢がありますが、それらのほとんどは共通して懸念の分離と単一の責任の原則を持っています。 Androidコミュニティでは非常に有名なClean Architectureは、アーキテクチャの異なる層に異なるモデルを使用することに重点を置いた優れたアーキテクチャを目指すときに従うべき良いプラクティスのセットです。 これは、3つまたは4つの異なるデータモデルを持つプロジェクトが標準になることを意味します。

つまり、プロジェクト内のデータクラスの数が非常に多く、作成、読み取り、変更、コピー、比較、マップ…データモデルクラスのような操作は、Kotinデータクラスの自動生成 膨大な時間を節約し、バグを導入する機会を減らします。

  • これ以上の自動値

値型を使用することは、特にデータクラスの間で、Androidで非常に拡張された良い習慣です。

値型は、不変の値クラスのオブジェクトです。
値クラスとは、その内容に応じて等価性が決まるクラスのことです。
不変クラスとは、作成後に変更できないクラスのことです。

AutoValueは、値の型を作成するのに役立つGoogleの人気のあるライブラリです。 それはその仕事をしますが、それほど複雑ではないはずのものにとっては非常に冗長です。

kotlindataクラスをvalアクセス修飾子で使用すると、値型に十分近い近似が得られます。

data class User(val name : String, val age : Int)

前のユーザークラスは、値型に十分近いクラスで、構文ははるかに短いです。 多くの人にとって、AutoValueはKotlinに置き換えることができます。 コードが少なく、注釈処理がなく、依存するライブラリが少なくなります。

注:Kotlinはvalキーワードを持つ読み取り専用のプロパティとクラスを提供しています。 読み取り専用と不変は同じではありません(詳細はこちら)が、一般的には実用的な目的のために十分であると考えられています。

  • No more Lombok

開発者がデータクラスを扱うときに時間を節約しようとした方法の一つは、ライブラリを使用してgetterとsetterメソッドを生成することです。 Lombokは、Android/Javaの(in)有名なものの一つです。 これは、ライブラリだけでなく、ASのためのプラグインだけでなく、必要とします。 短い長い話は、lombokは頭痛のように多くの利点をもたらすほとんどの開発者のためのものですので、それはあなたが愛し始めるが、しばらくして、あなた

Kotlinデータクラスがgetter/setterメソッドを手動で記述する必要がないことを考えると、Lombokの主な必要性はなくなりました。

  • RecyclerView DiffUtil

AndroidのRecyclerViewはウィジェットです。 これは、複数の画面内のすべてのアプリにあります。 RecyclerViewアダプターを実装する際の重要なコンポーネントの1つは、DiffUtilクラスです。 Diffutilは、変更がある場合はアダプタにディスパッチするために、2つのリスト間の差分を計算します。 リスト全体を何度も何度も更新するよりもはるかに効率的で、変更を美しくアニメーション化します。

DiffUtilはアイテムの等価性に大きく依存しています。 つまり、2つのオブジェクトに同じ情報が含まれているかどうかを比較する方法が必要です。 これは、Javaデータクラスでequalsをオーバーライドする必要がある理由の1つですが、Kotlindataクラスでは無料です。

注:DiffUtilに慣れていない場合は、このクイックスタートガイドを確認してください。

  • Tests

テストクラスでは、期待値が実際の値と一致するかどうかを常にチェックしています。 オブジェクトの等価性の比較(前に説明したように)は非常に一般的な作業です。

通常のアプリランタイムでequalstoStringtoHashトリプレットをオーバーライドする必要がなくても、テスト目的でこれらのメソッドをオーバーライドする必要がある可能性が高いため、Kotlinデータクラスは言い訳なしでテストへのパスをクリアします。

補遺

Kotlinデータクラスを扱うときに言及する価値のある他の一般的なシナリオについて話しましょう。 これは厳密にはデータクラスに関連していませんが、それらの間で特に一般的です。

  • 複数のコンストラクタ
data class User(val name : String, val age : Int)

前に定義したUserクラスでは、User("Steve", 56)のようなインスタンスを作成するときにnameageを明示的に指定する必要があります。

Kotlinでは、引数の値を渡さない場合にデフォルト値が割り当てられるように、引数のデフォルト値を定義できます。

data class User(val name : String, val age :Int = 0)

User("Steve", 56) まだ有効ですが、2番目のコンストラクタUser("Steve")が許可されます。 その場合、ageの値は0になります。

両方のパラメータにデフォルト値を割り当てることができ、nameが空になり、ageが0になる3番目のコンストラクタUser()を許可します。

data class User(val name : String = "", val age : Int = 0)

だから今User()User("Steve")User("Steve",56)すべてが有効な呼び出しです。

これにはいくつかの制限があります。 次はコンパイルされません。

data class User(val name : String = "", val age : Int)
val user = User(56) // This doesn't compile

もう一つの制限は、複数のオプションパラメータがある場合、それらを右から左にスキップする必要があるということです。

data class User(
val name : String,
val surname : String = "",
val age : Int = 0
)User("Steve")
User("Steve", "Jobs")
User("Steve", "Jobs", 56)
User("Steve",56) // This wont compile

この制限に対処するために、Kotlinは名前付き引数を提供します。 これにより、どの引数がすべての値に属するかを指定することができます。 これで、姓がデフォルト値に割り当てられるUser(name = "Steve", age = 56)—またはより短いUser("Steve", age = 56)—のようなことを行うことができます。

デフォルト引数と名前付き引数は、非常にコンパクトな宣言から複数のコンストラクタとオーバーロードを提供する非常に便利な方法です。

  • @JvmOverloads

前のポイントで説明したすべては、Java側からの呼び出しを考慮していません。 KotlinはJavaと相互運用可能であるため、JavaからUserクラスのインスタンスを作成できる必要があります。

Javaから使用しない場合は完了ですが、それ以外の場合は、Javaが名前付き引数を提供していないため、@JvmOverloads注釈が必要になります。

data class User @JvmOverloads constructor(
val name : String,
val surname : String = "",
val age : Int = 0
)

これは複数のコンストラクタを生成しているので、Javaから呼び出すことができます。

注:すべての可能な順列を作成するのではなく、オプションの引数を右から左に削除した結果の順列を作成することに注意することが重要です。 詳細はこちら

  • Builders

Kotlinが名前付きパラメータとデフォルト引数を提供しているため、buildersの必要性が低くなります。 さらに、Android Studioのような現代のIdeでは、呼び出し側にパラメータの名前が既に表示されているため、読みやすくなり、読みやすさのためだけに面白くな

builderパターンがまだ必要な場合。 Kotlinは私たちを助けるために特別なものを提供していません。 Kotlinのbuilderパターンは次のようになります:

  • 注釈

一部のデータモデルクラスでは、注釈処理を使用するのが非常に一般的です。 たとえば、APIモデル(APIからの逆シリアル化された応答を表すデータクラス)には、GsonまたはMoshi注釈が付けられていることがよくあります。 永続性モデル(ローカルストレージ/データベースに格納されたデータを表すデータクラス)は、多くの場合、ルームまたはレルムの注釈で注釈が付けられます。

Kotlinでは、これらの注釈を引き続き使用できます。 たとえば、これはルームデータベースに格納されるユーザーモデルです:

概要

Kotlinのデータクラスは、Javaのデータクラスに対する苦痛と不満から何年も学んだ結果です。 彼らはすべての利点と欠点のどれも持っていることを目指しています。 それらを使用すると、非常にシンプルで楽しいですし、あなたがそれに慣れると、それは振り返ることは非常に困難です。

Androidでは、さまざまな方法で私たちを助けますが、ほとんどの場合、多くの時間を節約し、バグを減らします。

Kotlinデータクラスは、kotlinがプログラミング言語として何であるかの良い例です:簡潔で実用的で、開発者にとって喜びです。

コメントを残す

メールアドレスが公開されることはありません。

lg