Java
Kotlin

はじめてのKotlin:データクラス~プロパティ、コンストラクタ、ゲッター不要~

データクラスとは

 kotlin(コトリン)にはデータクラスというものがあります。これは処理は行わないけれどもデータだけをもつクラスです。
 コトリンと同じJVM言語のScala(スカラ)にはケースクラス(Case Class)と呼ばれるものがあります。コトリンのデータクラスはこのスカラのケースクラスとほぼ同じものだと言っていいと思います。

プロパティについて

 コトリンのデータクラスでは、データはクラスのプロパティとしてもちます。データクラスをインスタンス時に受け取るためのプライマリコンストラクタやプロパティの設定などのクラス内の処理は不要です。

DTO(データ転送オブジェクト)

 このデータクラスをうまく使うとデザインパターンのDTO(データ転送オブジェクト)が簡単に実装可能です。Javaだと結構冗長な記述が必要になります。
 具体的には、まず、プライベートなプロパティの宣言が必要になります。さらにデフォルトコンストラクターを定義し、デフォルトコンストラクタの引数に与えられた値をプライベートなプロパティに代入する処理が必要になります。また、プロパティのゲッターを記述しないといけません。
 コトリンでは言語仕様でプライマリコンストラクタの定義は不要です。また、プロパティのゲッターの定義も不要です。ですので、データクラスの定義をサクッと一行で実装が可能となります。

データクラスの基本書式

 コトリンのデータクラスの基本書式は以下のようになります。まず date class キーワードに続いてクラス名を記述します。
 クラス名の後ろの括弧 () 内にはプライマリーコンストラクタ引数を記述します。ここで、引数は不変変数キーワード val または可変変数キーワード var に続いてプロパティ名、コロン : 、型名を記述します。引数が複数ある場合には、カンマ , で区切って記述します。
 また、データクラスのインスタンス化を行うには クラス名 に続いて括弧 () 内にプロパティ値をカンマ , で区切って記述します。

データクラスの基本書式(定義)
data class クラス名( val または var プロパティ名: 型名, ・・・・・ )
データクラスの基本書式(インスタンス化)
val または var インスタンス変数 = クラス名( プロパティ値, ・・・・・ )

データクラスのコード例

 コトリンのデータクラスの具体例としてデータクラス 書籍() を以下に示します。

データクラスのコード例
data class 書籍( val タイトル: String, val 著者名: String, val 価格: Int )

fun main( args: Array<String> ) {
  val コトリンことはじめ = 書籍( "kotlinことはじめ", "平尾菜", 1800 )
  val ( タイトル, 著者名, 価格 ) = コトリンことはじめ

  println( "◇タイトル:$タイトル ◇著者名:$著者名 ◇価格:$価格 円" )
}

引数の定義

 プライマリーコンストラクタの引数として変更不可な タイトル著者名価格 を定義しています。
 データクラスは処理を持たないのでメソッドの記述はありません。またコトリンのクラスはプライマリコンストラクタの定義やプロパティの定義が不要です。ですので、たったこれだけでデータクラスの定義は終わりまです。

関数 main() の定義

 関数 main() 内ではこのデータクラス 書籍() のプライマリコンストラクタの引数を与えてインスタンス化しています。インスタンス化したものを不変なインスタンス変数 コトリンことはじめ に代入しています。
 そうして、このインスタンス変数をまとめて ( タイトル, 著者名, 価格 ) の形式でに代入しています。この複数の変数をまとめて記述することを
多重定義 といいます。
 ここで、データクラス 書籍() のプライマリコンストラクタの引数の順番に変数 タイトル著者名価格 をそれそれ指定して多重定義しています。

多重定義とは

なお、多重定義とは複数の変数をひとまとめにして宣言し、それぞれの変数の値をまとめて一度に定義するためのデータ記述の方法です。括弧 () 内にカンマ , 区切りで格納する値に対する変数名を複数定義します。この機能はコトリンの旧バージョンでは タプル で実現していました。 タプル はコトリンと同じJVM言語である Scala などでも使われている機能です。

 これで、データクラス 書籍() のプロパティ "kotlinことはじめ""平尾菜々花"1800 がそれぞれ、タプルの変数 タイトル著者名価格 に代入されます。
 最後にデータクラスのプロパティを println() 関数内で $ 記号で文字列内に補間してコンソールに表示しています。

データクラスの実行結果
◇タイトル:kotlinことはじめ ◇著者名:平尾菜々花 ◇価格:1800 円

Javaならどうなるか?

 ここで、コトリンのデータクラスはJavaならどのような実装になるかを見てみましょう。

コトリンのデータクラス 書籍() と同じ処理を行うJavaのコード例

 上記のコトリンのデータクラス 書籍() と同じ処理をJavaで実装すると以下の Book.javaUsingBook.java のようになります。
 まず、privateなプロパティ タイトル著者名価格 を宣言しています。
 次に、デフォルトコンストラクタ Book() を定義しています。この Book() の処理としてprivateなプロパティへのデフォルトコンストラクタの引数を代入する処理を記述しています。
 さらに、privateなプロパティ タイトル著者名価格 に対するゲッターをそれぞれ、メソッド getタイトル()get著者名()get価格() で定義しています。
 コトリンのデータクラス 書籍() ではたったの1行の記述が19行にわたって記述が必要となっています。このようなデータクラスはJavaの場合にはフレームワークや統合開発環境のIDEが自動生成してくれることが多いです。しかし、この20倍近いコードを維持管理・メンテナンスするコストもバカにならないのではないでしょうか?。

Book.java
public class Book {
  private String タイトル;
  private String 著者名;
  private int 価格;

  public Book(String タイトル, String 著者名, int 価格) {
    this.タイトル = タイトル;
    this.著者名 = 著者名;
    this.価格 = 価格;
  }

  public String getタイトル() {
    return タイトル;
  }

  public String get著者名() {
    return 著者名;
  }

  public int get価格() {
    return 価格;
  }
}
UsingBook.java
class UsingBook {
  public static void main (String[] args) throws java.lang.Exception {
      Book コトリンことはじめ = new Book( "kotlinことはじめ", "平尾菜々花", 1800 );

      String タイトル = コトリンことはじめ.タイトル;
      String 著者名 = コトリンことはじめ.著者名;
      int 価格 = コトリンことはじめ.価格;

      System.out.println(
        "◇タイトル:" + タイトル + " ◇著者名:" + 著者名 + " ◇価格:" + 価格 +" 円" );
  }
}
同じ処理を行うJavaの実行結果
◇タイトル:kotlinことはじめ ◇著者名:平尾菜々花 ◇価格:1800 円

デフォルトプロパティ値の定義

 コトリンのデータクラスのプロパティにはデフォルト値をあらかじめ定義することができます。デフォルト値を定義した場合には、データクラスのインスタンス時に省略することが可能です。
 ただし、省略したことが明確になるように、インスタンス時に省略せずに指定するプライマリコンストラクタの引数はプロパティ名を明示し、 プロパティ名 = プロパティ値 のように記述します

データクラスのプロパティのデフォルト値の書式(定義)
data class クラス名( val または var プロパティ名: 型名 = デフォルト値, ・・・・・ )
データクラスのプロパティのデフォルト値の書式(インスタンス化)
val または var インスタンス変数 = クラス名( プロパティ名 = プロパティ値, ・・・・・ )

デフォルトプロパティ値の定義の具体例

 デフォルトプロパティ値を定義した具体例は以下のデータクラス 書籍 のようになります。
 プロパティ タイトル のデフォルト値として "はじめてのコトリン" を定義しています。他のプロパティはデフォルト値を定義していません。
 このような場合には、プロパティ タイトル はデータクラス 書籍 のインスタンス化時に省略することが可能です。
 関数 main() 内でデータクラス 書籍 をインスタンス化する際に省略しています。このさい、省略したプロパティ名がわかるように、省略せずにプロパティ値を与える引数のプロパティ名を明示します。
 コード例では省略されたプロパティ タイトル 以外の 著者名価格 について、 著者名 = "平尾菜々花"価格 = 2180 のようにプロパティ名を明示してプロパティ値を設定しています。

デフォルトプロパティ値の定義のコード例
data class 書籍( val タイトル: String = "はじめてのコトリン", val 著者名: String, val 価格: Int )

fun main( args: Array<String> ) {
  val コトリン本 = 書籍( 著者名 = "平尾菜", 価格 = 2180 )
  val ( タイトル, 著者名, 価格 ) = コトリン本

  println( "◇タイトル:$タイトル ◇著者名:$著者名 ◇価格:$価格 円" )
}
実行結果
◇タイトル:はじめてのコトリン ◇著者名:平尾菜々花 ◇価格:2180 円

 ※この記事では日本人の可読性のために関数名、クラス名、変数名などをあえて日本語にしてみました。UTF-8エンコードで問題なくコンパイルし、実行することができます。好き嫌いはあると思いますので、実プロジェクトでは英語表記に変えるなど柔軟に対応してください。