Android(Java)のあれ、Kotlinでどう書くの？

Kotlinに挑戦してみたので、いつも書いてるAndroidのコードを、Kotilnではどう書くのかわからなかったので、調べてみました。

やっていくうちに、Kotlinでできることがたくさんあって楽しくなったので、Javaとの比較だけでなく、Kotlinでできる便利な機能についても一部ご紹介しています。

また、自分で使った部分について記載しているので、情報に偏りがあるかもしれませんが、ご容赦ください。
入門したばかりなので、誤りがあった場合教えていただけるとうれしいです。

#基本
##定数・変数
変数には冒頭にvarを記述します。後で値を変更しない定数などではvalを使用します。

```Java:Java
// 変数
int value = 1;
// 定数
final static int VALUE = 1;
```

```Kotlin:Kotlin
// 値の変更不可
val value = 1
// 値の変更可
var value = 1
```

##型推定
Kotlinでは、入っているデータから型を推定するため、型を指定する必要がありません。
(もちろん、指定することもできます)

```Java:Java
String text = "おはようございます。";
int number = 1234;
```

```Kotlin:Kotlin
val text = "おはようございます。"
val number = 1234

// 型を明記する場合はコロン＋型を追加する
var value: Integer = 1
```

##クラス・メソッド

メソッドの冒頭はfunと記述します。
クラスのextendsとimplementsはクラス名の後に:をつけて記述します

```Java:Java
public class TestActivity extends AppCompatActivity implements OnMapReadyCallback {
    @Override
    public void onCreate(Bundle savedInstanceState) {
    
    }
    @Override
    public void onMapReady(GoogleMap p0) {
    
    }
}
```

```Kotlin:Kotlin
class TestActivity : AppCompatActivity(), OnMapReadyCallback {
    override fun onCreate(savedInstanceState: Bundle?) {
    
    }
    override fun onMapReady(p0: GoogleMap?) {
        
    }
}
```

また、継承はoverrideを冒頭につけます。
なお、継承できるのはopenをつけたメソッドのみです。

```Java:Java
public class Base {
    public void print(String text) {
        Log.d("print", text);
    }
}

public class Sub extends Base {
    @Override
    public void print(String text) {
        super.print(text);
    }
}
```

```Kotlin:Kotlin
// 継承できるクラス・メソッドはopenをつける
open class Base {
    open fun print(text:String) {
        Log.d("print", text)
    }
}

// 継承するクラスは:の後に継承するクラスを記述する
class Sub : Base() {
    // 継承するメソッドにoverrideをつける
    override fun print(text: String) {
        super.print(text)
    }
}
```
##Nullable

?がついていない普通の型にはnullを代入できません。
クラス名の後に?を記述すると、Nullableとなり、nullを代入できます。

```Java:Java
// nullを入れられる
String a = null;
```

```Kotlin:Kotlin
val a:String = "test"
val b:String? = null

// aにはnullを入れられない(コンパイルエラー)
a = null
// nullがあり得ないので、NullPointerExceptionは起こらない
val aLength = a.length

// b(Nullable)にはnullを入れられる
b = null
// nullの可能性があるので、コンパイルエラーとなる
val bLength = b.length
// 下記のように書けば、コンパイルエラーとならない(nullの場合はnullが返却される)
val bLength = b?.length

// 下記のように書けば、nullの場合にはNullPointerExceptionが発生する
val bLength = b!!.length
// ただし、bがnullでない場合、!!を記述した処理以降の処理は、nullableではないString型として扱えるようになる
var chars = b.split("")
```

##文字列操作

Javaだと文字列と変数は+でくっつけたりしますが、Kotlinだと$をつけることで文字列の中に変数を入れることができます

```Java:Java
int first = 1
int second = 2
String value = first + " * " + second + " = " + (first*second) + "です"
```

```Kotlin:Kotlin
val first = 1
val second = 2
val value = "$first * $second = ${first * second}です"
```

##switch文
when文を使用します。switchより複雑なことができます。
また、whenではbreakは必要ありません。

```Java:Java
switch(number) {
    case 1:
        // 1のとき
        Log.d("test", "one");
        break;
    case 2:
    case 3:
        // 2もしくは3のとき
        Log.d("test", "two or three");
        break;
    case 4:
    case 5:
    case 6:
        // 範囲内か
        Log.d("test", "four - six")
        break;
    default:
        Log.d("test", "none")
}
```

```Kotlin:Kotlin
when(number) {
    // 1のとき
    1 -> Log.d("test", "one")
    // 2もしくは3のとき
    2,3 -> Log.d("test", "two or three")
    // 範囲内か
    in 4..6 -> Log.d("test", "four - six")
    // 範囲外か(Kotlinのみ)
    !in 7..9 -> Log.d("test", "not seven - nine")
    // 配列に含まれているか(Kotlinのみ)
    in numberList -> Log.d("test", "list invalid")
    // どれにも当てはまらない場合
    else -> Log.d("test", "none")
}

```

when文を使って型のチェックをすることもできます。

```Kotlin:Kotlin
fun <T> put(key:String, value:T) {
    val pref = context!!.getSharedPreferences(NAME, Context.MODE_PRIVATE)
    val editor = pref.edit()
    when (value) {
        is String -> editor.putString(key, value)
        is Float -> editor.putFloat(key, value)
        is Int -> editor.putInt(key, value)
        is Boolean -> editor.putBoolean(key, value)
        is Long -> editor.putLong(key, value)
        else -> throw IllegalArgumentException("")
    }
    editor.apply()
}
```

##リスト
###リスト作成
```Java:Java
String[] list = {"晴れ", "曇り", "晴れ時々曇り", "雨", "曇りのち雨", "雪"};
```
```Kotlin:Kotlin
val list = arrayOf("晴れ", "曇り", "晴れ時々曇り", "雨", "曇りのち雨", "雪")
```
以降、上記のリストがある前提で説明します
###合致するアイテムを取り出す
```Java:Java
ArrayList<String> outputList = new ArrayList<String>();
for(String item : list) {
    if(item.contains("雨")) {
        outputList.add(item);
    }
}
```
```Kotlin:Kotlin
val outputList = list.filter{ it.contains("雨") }
```

> 抽出結果(outputListの中身)
> "雨", "曇りのち雨"

###合致しないアイテムを取り出す
```Java:Java
ArrayList<String> outputList = new ArrayList<String>();
for(String item : list) {
    if(!item.contains("雨")) {
        outputList.add(item);
    }
}
```
```Kotlin:Kotlin
val outputList = list.filterNot{ it.contains("雨") }
```

> 抽出結果(outputListの中身)
> "晴れ", "曇り", "晴れ時々曇り", "雪"

###先頭から指定数取り出す
2つだけ取り出す

```Java:Java
ArrayList<String> outputList = new ArrayList<String>();
for(int i=0; i<2; i++) {
    outputList.add(list[i]);
}
```
```Kotlin:Kotlin
val outputList = list.take(2)
```

> 抽出結果(outputListの中身)
> "晴れ", "曇り"

###後ろから指定数取り出す
後ろ3つだけ取り出す

```Kotlin:Kotlin
val outputList = list.takeLast(3)
```

> 抽出結果(outputListの中身)
> "雨", "曇りのち雨", "雪"

###先頭から指定数を削除
先頭から3つは削除

```Kotlin:Kotlin
val outputList = list.drop(3)
```

> 抽出結果(outputListの中身)
> "雨", "曇りのち雨", "雪"

#番外編
Kotlinなら簡単にできちゃう！そんな便利な機能のさわりをご紹介します

##Kotlin Android Extensions

もっとKotlinを便利にするために、入れておくと便利なExtensions
これを使用して、findViewByIdを使用せずに直接リソースのIDを使用することができます
(他にも機能があるのかもしれませんが、現時点でこれしか使えてないです)

###導入方法

Build.gradleのdependenciesに
`classpath "org.jetbrains.Kotlin:Kotlin-android-extensions:$Kotlin_version"`
を追加し、ActivityファイルのImport文に
`import Kotlinx.android.synthetic.main.layoutファイル名.*`
を追加する
(layoutファイル名は例えばactivity_main.xmlの場合、activity_mainを記述する)

###setText

指定のIDのTextViewのtextのPropertyに直接アクセスが可能
(直接リソースのIDのtextに代入する)

```Java:Java
TextView tv = (TextView)findViewById(R.id.title);
tv.setText("明日の天気");
```

```Kotlin:Kotlin
// id=titleのtextというPropertyに直接値を代入している
title.text = "明日の天気"
```

###onClick
さらに、ラムダ式と併用することでClickListenerの処理が1行で書けちゃう！

```Java:Java
Button fabBtn = (Button)findViewById(R.id.fab);
fabBtn.setOnClickListener(new OnClickListener(){
    @Override
    public void onClick(View view) {
        Log.d("test", "onClick");
    }
});
```

```Kotlin:Kotlin
// fabはリソースのID
fab.setOnClickListener({ view -> Log.d("test", "onClick")})
```

##拡張関数
既存クラスに対して、よく使う処理などを拡張関数として定義しておくことができる

以下のように、startActivityの拡張関数を定義する（試したときはExtension用クラスを作成して下記を記述した）

```Kotlin:Kotlin
// Activityの指定は必須とする
// Intentを詰める必要があるときだけbundleを設定する、それ以外はnullをデフォルトでセットする
fun <T: Activity> Activity.startActivity(classRef: KClass<T>, bundle: Bundle? = null) {
    val intent = Intent(this, classRef.java).setAction(Intent.ACTION_VIEW)
    bundle?.let {
        intent.putExtra("args", bundle)
    }
    startActivity(intent)
}
```

呼び出す際は以下のように1行記述するだけで上述したstartActivityの処理が実行できます

```Kotlin:Kotlin
startActivity(NextActivity::class)
```

#さいごに
Kotlin楽しいよ！