JavaとKotlinの比較
Java vs Kotlin
参考にさせて頂いた記事
https://qiita.com/koher/items/bcc58c01c6ff2ece658f
メモ書きで残していたものなのでなぐり書きです
Javaとの違い
- 文末の
;
いらない - asで別名付けられる
import java.sql.Date as SqlDate
変数編
final
な変数はval
- 変更可能な変数は
val s: String = "abc"
- 型推論は
var s = "abc"
と右辺値から判断 - 型宣言に
?
を付けた場合は nullable (Kotlin は明示的に ? を付けないと null を代入できない) - 変数に付けた場合は Safe Call(安全な呼び出し)
aaa?.length
// Java int a = 42; final boolean b = true;
// Kotlin var a: Int = 42 val b: Boolean = true
制御構文
// Java final String foo; if (bar < 42) { foo = "abc"; } else { foo = "xyz"; } // Java final String foo = bar < 42 ? "abc" : "xyz";
// Kotlin val foo = if (bar < 42) { "abc" } else { "xyz" } // Kotlin val foo = if (bar < 42) "abc" else "xyz"
- while 同じ
- c++の拡張forと同じ
// Java for (int number : numbers) { System.out.println(number); } // Java for (int i = 0; i< 100; i++) { System.out.println(i); }
// Kotlin for (number in numbers) { println(number) } // Kotlin for (i in 0 until 100) { println(i) } // Kotlin for (i in 99 downTo 0) println(i) // for (int i = 99; i >= 0; i--) for (i in 0 until 100 step 2) println(i) // for (int i = 0; i < 100; i += 2) for (i in 1..100) println(i) // for (int i = 1; i <= 100; i++)
switch(){}
->when(){}
- newは不要
class
- kotlinはデフォルトがpublic
- kotlinはclassのフィールドがなく,getter/setterが存在しない
- その代わりプロパティと呼ばれるものがある
コンストラクタ
// Kotlin class Person(val firstName: String, val lastName: String) { var age: Int init { age = 0 } ... }
// Java public class Person { private final String firstName; private final String lastName; private int age; public Person(String firstName, String lastName, int age) { this.firstName = firstName; this.lastName = lastName; this.age = age; } public Person(String firstName, String lastName) { this(firstName, lastName, 0); } ... }
// Kotlin class Person(val firstName: String, val lastName: String, var age: Int) { constructor(firstName: String, lastName: String) : this(firstName, lastName, 0) { } ... }
プロパティ?
// Java final int age = person.getAge(); person.setAge(age + 1); // Java public class Person { ... public String getFullName() { return firstName + " " + lastName; } }
// Kotlin val age = person.age person.age = age + 1 // Kotlin class Person { ... val fullName: String get() { return firstName + " " + lastName } }
式が一つで済むときはこれで住む
// Kotlin val fullName: String get() = firstName + " " + lastName
メソッド
- 特に変化は無く
fun
が必要なだけ - fun 関数名(引数):戻り値
// Kotlin class Person(val firstName: String, val lastName: String) { ... // 時間経過を表すメソッド fun elapse(years: Int): Int { age += years return age } }
- 式が一つで済むなら以下のようにかける
// Kotlin fun getFullName(): String = firstName + " " + lastName
カスタムgetter/setter
- 基本的にgetter/setterは必要ないが,何か処理したい時
// カスタムゲッターを定義 val nameLength: Int get(): Int { return this.name.length } // カスタムセッターを定義 var name: String = "" set(value) { println("nameに${value}が設定されました。") // 値は field変数に格納する field = value }
継承
- Kotlin ではデフォルトでクラスやメソッドは final
- final でなくすには open のキーワードをつける
extend
の代わりに:
- override修飾子は必須項目
val
もvar
もついていない -> 何もつけなければそれはただの引数
// Kotlin // `open` で `final` でなくす open class Person(val firstName: String, val lastName: String, var age: Int) { ... open val fullName: String // `final` でなくす get() = firstName + " " + lastName } class EasternPerson(firstName: String, lastName: String, age: Int) : Person(firstName, lastName, age) { override val fullName: String get() = lastName + " " + firstName // 姓 名の順にする }
データクラスとコピー
- データだけ保持したいクラスは
data
修飾子をつける - 以下の要素が自動生成される
- equals()/hashCode()ペア
- "User(name=John, age=42)"って表示するtoString()
- 宣言順で内容を取り出すcomponentN()関数
- copy()
data class User(val name: String, val age: Int)
- fun copyがデータクラスに自動生成される
val jack = User(name = "Jack", age = 1) val olderJack = jack.copy(age = 2) // nameはそのままでageだけ変更したコピーを生成
interface
// Java public interface Foo { int getBar(); void baz(String qux); }
// Kotlin interface Foo { val bar: Int fun baz(qux: String) }
コレクション
// Java final List<Integer> a = Collections.unmodifiableList(Arrays.asList(2, 3, 5)); final List<Integer> b = new ArrayList(); b.add(2); b.add(3); b.add(5);
// Kotlin val a: List<Int> = listOf(2, 3, 5) val b: MutableList<Int> = mutableListOf() b.add(2) // 可変 b.add(3) // 可変 b.add(5) // 可変 // Kotlin val a = mutableListOf(2, 3, 5) val b: List<Int> = a println(b) // [2, 3, 5] a.add(7) println(b) // [2, 3, 5, 7] // Kotlin val a = intArrayOf(2, 3, 5)
deligate(譲位)
https://developer.android.com/training/basics/fragments/communicating.html#kotlin
- 難しいことはよくわからんが,保持されてる側のクラスから,保持してる側のクラスへ通知するしくみ
- playGroundで試せるよ
- 生成される側にListenerインターフェイス定義
- callback変数を定義して,それをsetする関数用意(どこかで生成された関数オブジェクト?を格納)(本系はlateinitじゃなくても動いてた)
- インスタンス保持側でinterfaceの実装(本家はoverrideなかった...)
// インスタンス生成される側に定義 class Fragment(){ internal lateinit var callback: SomeListener fun setSomeListener(callback: SomeListener){ this.callback = callback } fun sendMessage(){ callback.messageRecv("Hello") } // This interface can be implemented by the Activity, parent Fragment, // or a separate test implementation. interface SomeListener{ fun messageRecv(str: String) } } // 実装はインスタンスを持つ側 class Activity(): Fragment.SomeListener{ val fragment = Fragment() //本来onFragmentAttachとか //だから本来この上でいちいちfragment定義せんでもよいのよな //fun onAttachFragment(fragment: Fragment) { // if (fragment is HeadlinesFragment) { // fragment.setOnHeadlineSelectedListener(this) // } //} init { // コンストラクタで渡そう fragment.setSomeListener(this) } override fun messageRecv(str: String){ println("getMessage!: " + str) } } fun main() { val activity = Activity() activity.fragment.sendMessage() }
そんなsetSomeListenerのところコンストラクタで渡せばもっとシンプル!!
lazy
http://atma1333.hatenablog.com/entry/2017/08/02/124122
より
- lazyは引数に関数を取り,この関数は対象のプロパティにセットされる値を返します。
- 対象のプロパティが最初に参照された時lazyの引数に渡された関数が呼び出されます。
- 2回目以降の参照では呼び出されません。
class CustomView(context: Context?) : FrameLayout(context) { var text1: TextView? = null var text2: TextView? = null var image: ImageView? = null init { LayoutInflater.from(context).inflate(R.layout.item_view, this) text1 = findViewById(R.id.text1) text2 = findViewById(R.id.text2) image = findViewById(R.id.image) } }
lazyつかって書くと
class CustomView(context: Context?) : FrameLayout(context) { val text1: TextView by lazy { findViewById<TextView>(R.id.text1) } val text2: TextView by lazy { findViewById<TextView>(R.id.text2) } val image: ImageView by lazy { findViewById<ImageView>(R.id.image) } init { LayoutInflater.from(context).inflate(R.layout.item_view, this) } }
lateinit
- NonNullなプロパティーの初期化をconstructorより後に遅らせられる機能
as
- キャスト 失敗でエラー
- as? はキャストだけど失敗でnullになる
オブジェクト式
- あるクラスの一つだけを修正(オーバーライド)したインスタンスがほしいとき
open class A(x: Int) { public open val y: Int = x } interface B {...} val ab: A = object : A(1), B { override val y = 15 }
ラムダ式
- kotlinは関数が第一級関数だから関数オブジェクトとして扱える
public class Main { fun main(args: Array<String>) { val op = { a:Int, b:Int -> a+b} calc(1,2,op) // 3 } fun calc(a: Int, b: Int, op: (Int, Int) -> Int): Int { return op(a, b) } }
型推論できないときは明示的に
val noReturn : Int -> Unit = { num -> println(num) } val more : (String, Int) -> String = { str, int -> str + int } // クラス拡張としてもラムダ式OK val another : String.(Int) -> String = { this + it }
スコープ関数
val s = "hoge".let { it.toUpperCase() } println(s) //=> HOGE val s = "hoge".run { toUpperCase() } println(s) //=> HOGE val s = "hoge".apply { toUpperCase() } println(s) //=> hoge
let
- 任意の型の拡張関数
- letは引数として関数を受け取り,任意の型で返す
- nullableな変数に対して使うことが多い
val upperCase: String? = foo?.let { it.toUpperCase() } // nullなら?.呼び出しによりletが実行されない // nullじゃないなら,letが実行され大文字で帰ってくる
run
- letとwithが合わさった感じ
- runは任意の型Tの拡張関数でそのTをレシーバとするメソッドのような関数を引数に取る
val frame: JFrame? = frameOrNull() frame?.run { size = Dimension(600, 400) defaultCloseOperation = JFrame.EXIT_ON_CLOSE setVisible(true) }
apply
- letは引数として関数を受け取り,レシーバを返す
val frame: JFrame = JFrame("My App").apply { size = Dimension(600, 400) defaultCloseOperation = JFrame.EXIT_ON_CLOSE setVisible(true) }
class MyFragment: Fragment() { companion object { fun new(foo: Int, bar: Int): MyFragment = MyFragment().apply { arguments = Bundle().apply { putInt("foo", foo) putInt("bar", bar) } } } }
Kotlin : as, !, ? 周りのチートシート
この記事が良くまとまっていて秀逸です http://increment.hatenablog.com/entry/2015/10/31/090743