Java民から見た時のKotlinのギャップまとめ

# 経緯
社内PJでKotlinを使ってコードを書くことになりました。
メンバーには自分含めJava民が多いです。Kotlinへの移行がちょっとでもスムーズになるように、Java民から見た「Kotlin特有の書き方だなぁ」ってところをまとめました。
å
## Kotlin慣れに良いサイト（たぶん）

[(公式)イディオム](https://kotlinlang.org/docs/java-to-kotlin-idioms-strings.html)
[(公式)コレクションタイプ](https://kotlinlang.org/docs/java-to-kotlin-collections-guide.html#operations-on-any-collection-type)
Javaでこう書いてたものがKotlinだとこう、みたいな感じ

[リファレンス](https://dogwood008.github.io/kotlin-web-site-ja/docs/reference/basic-types.html)
~~コレも公式。~~
公式を個人が日本語訳したもの。
右上の「TRY ONLINE」からオンライン環境でコーディングできる

[(公式)SpringBootとH2DB使ってAPIつくる](https://kotlinlang.org/docs/jvm-spring-boot-restful.html#add-database-support)
英語が面倒だけど実処理書こうとするとこんな感じ

[Kotlinの基本的な言語仕様を学習したまとめ](https://qiita.com/kerobot/items/ac8fa69955f9d3414f81)
ぶっちゃけ本記事の上位互換。

## 変数定義周り

### Null Safety

変数がデフォルトで非NULL型。コンパイルの時点でエラー。
これによりNullPointerExceptionが起きづらい（後述の演算子もあるので、絶対起きないとは言っていない）
```Some.kt
var a: String = "hogehoge"
a = null //コンパイルエラー Null can not be a value of a non-null type String

var b: Int = "hogehoge"
b = null //コンパイルエラー Null can not be a value of a non-null type Int
```

NULL許容型も作れる
```Some.kt
var a: String？ = "hogehoge"
a = null //コンパイルOK

var b: Int？ = "hogehoge"
b = null //コンパイルOK
```

#### 定義した変数を呼ぶとき

NULL許容で変数定義した場合は、下記の2つのパターンでメソッドを呼ぶ。
後者は非推奨なので実質セーフコールがベター。

**セーフコール演算子**
値がNULLでない場合のみメソッドが呼ばれる。

```Some.kt
var a: String？ = "hogehoge"
println(a?.length)　// 8

var b: String？ = null
println(b?.length)　// null lengthメソッドは呼ばれない
```

**非NULL表明演算子（きっと非推奨）**

[指摘](https://qiita.com/kannna5296/items/8028e992d4c574401410#comment-be4145ad08fc3afc8529)頂いて追記。
NullableなものをnonNullに変更できる。

```Some.kt
val nullable: String? = getNullable()
val nonnull: String = nullable!!
```

またメソッド呼び出しと一緒に使うと、NULLだろうが何だろうがメソッドを呼ぶ。
当然nullとなっている変数に対してメソッドが呼ばれるとNullPointerExceptionが出る。

```Some.kt
var a: String？ = "hogehoge"
println(a！！.length)　// 8

var b: String？ = null
println(b！！.length)　// ぬるぽ
```

### 変数定義時にvar(再代入可能) OR val(再代入不可能)を必ず指定する

`var`...再代入可。
`val`...再代入不可。Javaでいうfinal定義みたいなもん
可能な限りval使えると変数のスコープが小さくなって保守しやすくなりそう

```Some.kt
var a: String = "hogehoge"
a = ”piyo” //OK

val b: String= "hogehoge"
b = ”piyo” //コンパイルエラー。 "Val cannot be reassined"(再代入すんな)
```

### 型推論可能

```Some.kt
val a = "hogehoge"
a.startsWith("h") // startWithはStringクラスが持つメソッド。 コンパイルエラーにならない
```

~~あとlateinitとかあった気がするけどなんだっけ。。。~~
lateinitはインスタンス生成時にまだ初期化したくないフィールドに対して使うもので、型推論とは別物。

## クラス定義周り
クラスを作る側の話。

### CompanionObject

インスタンス生成せずにメソッド/変数を呼びたい時、static定義ではなく、
代わりにCompanionObjectなるものを用いる

```Some2.kt
class Hoge {
//クラス内で定義
    companion object {
        fun fuga(str : String) {
            println("$str")
        }
    }
}

Hoge.fuga("Kotlin")
```

変数定義についても同様
[クラス内での変数定義の話](https://qiita.com/takusemba/items/f278e9e9e9217f0d6632)

### データクラス

クラスにlombok(@Data)が外部ライブラリなしで実現できるようになったイメージ
エンティティクラスとかによく使われそう

`equals`
`hashCode`
`copy`
`toString()`Object(key1=value1, key2=value2)型のもの
`componentN`

```Book.kt
import java.time.LocalDate
data class Book {
    var id: Long? = null,
    var title: String? = null,
    var author: String? = null,
    var releaseDate: LocalDate? = null
)
```

### デフォルトで継承不可(Javaでいうfinalクラスみたいなもん）

```User.kt
class User(val name: String, val age: Int) //継承不可
```

~~明治的に継承させたくない場合は`seald`をつける~~
[指摘](https://qiita.com/kannna5296/items/8028e992d4c574401410#comment-be4145ad08fc3afc8529)頂いて修正。sealdの挙動は下記でした。
* 同じファイルに定義されているクラスからのみ継承を許す (=別ファイルに定義されたクラスから継承不可)
```User.kt
seald class User(val name: String, val age: Int) //「別ファイルに定義されたクラスから」継承不可
```

明示的に継承させたくない場合は`final`をつける(Javaと一緒だが、デフォルトで継承不可なのであんまり使うことなさそう)

```User.kt
final class User(val name: String, val age: Int) //継承不可
```

他ファイルでもそのクラスを継承したい場合は`open`をつける
```User.kt
open class User(val name: String, val age: Int) //継承可
```

### getter/setter定義不要

```User1.kt
  class User1 {
    var name: String = ""
  }
```

```Some.kt
  val user = User1()
  user.name = "Tanaka" // user.setName()とかしなくて良い
  println(user.name) //Tanaka
```

・プロパティをvalで定義するとgetterのみ生成される（再代入不可なので当然っちゃ当然）

#### getter/setterを拡張することもできる

getter拡張
```User2.kt
  class User2 {
    lateinit var name: String
    // isValidNameプロパティに対するget()関数の処理を書き換える
    val isValidName: Boolean
      get() = name != ""
  }
```

```Some.kt
  val user = User2()
  user.name = "Tanaka" 
  println(user.isValidName) //True
```

setter拡張
```User3.kt
  class User3 {
    var name: String = ""
      //空文字の場合はデフォルト値として"Kotlin"を返す拡張
      set(value) {
        if (value == "") {
          field = "Kotlin"
        } else {
          field = value
        }
      }
  }
```

```Some.kt
  val user = User3()
  user.name = "" //空文字を登録しているようで、拡張setterで実質"Kotlin"を代入している
  println(user.name) //"Kotlin"
```

### プライマリコンストラクタ、セカンダリコンストラクタ


**プライマリコンストラクタ**

```Person.kt
class Person　constructor(
  val firstName: String, 
  val lastName: String, 
  var isEmployed: Boolean = true
)
```

コンストラクタに注釈・可視性修飾子がない場合は、`constroctor`を省略できる

```Person.kt
class Person(
  val firstName: String, 
  val lastName: String, 
  var isEmployed: Boolean = true
)
```

コンストラクタに注釈・可視性修飾子がある場合は、`constructor`必須

```Person.kt
class Person public consutructor (
  val firstName: String, 
  val lastName: String, 
  var isEmployed: Boolean = true
)
```

**セカンダリコンストラクタ**

```Person.kt
class Person (private val name: String, private val age: Int) {
    // thisはプライマリコンストラクタを指す
    constructor(name: String) : this(name, 20)
}
```

これ調べてる時、kotlinでSingletonパターン書こうとしたらどうなるんだろうな...と思った。
結果、[objectで生成する方法](https://pouhon.net/kotlin-singleton/3414/)が有力らしい

## インスタンス生成周り
クラスを使う側の話。

### List,Mapのインスタンス生成（ミュータブル or 読み取り専用OK）

```Some.kt
  val mutableList = mutableListOf(1, 2, 3) //可変 add可能
  val List = listOf(1, 2, 3)  //読み取り専用　getのみ可能...★
  val mutableSet = mutableSetOf(1, 2, 3) //可変 add可能
  val set = setOf(1, 2, 3)  //読み取り専用　getのみ可能...★
```

★なお、List,Setは"読み取り専用"なだけで、イミュータブルではない。
一度定義した後でも、下記のように参照先を書き換えると変更可能。
```Some.kt
    val mutableList = mutableListOf(1, 2, 3)
    val list: List<Int> = mutableList //Listインターフェース。 読み取り専用。この時点では(1,2,3)
    println(list) //1,2,3

    mutableList.add(9)
    println(mutableList) //1,2,3,9
    println(list) //1,2,3,9　
```