Table of Contents
1.2 になって、どのような機能が追加されたのかをまとめてみました。
Annotation における Arrey 記述 の簡略化
従来はアノテーションの記述において、 Array 型 の引数を記述するときに arrayOf 関数 を使う必要がありましたが、 [ ] で囲むことでより簡単に記述することができるようになりました。
従来の書き方
|
1 2 3 4 5 6 7 |
@GetMapping( consumes = arrayOf(MediaType.APPLICATION_JSON_VALUE), produces = arrayOf(MediaType.APPLICATION_JSON_VALUE)) @ResponseBody fun list(): Map<String, Any?> { // ... } |
1.2で可能になった書き方
|
1 2 3 4 5 6 7 |
@GetMapping( consumes = [MediaType.APPLICATION_JSON_VALUE], produces = [MediaType.APPLICATION_JSON_VALUE]) @ResponseBody fun list(): Map<String, Any?> { // ... } |
トップレベル変数への lateinit 修飾子
従来はトップレベルの変数には lateinit を付けることができませんでしたが、それが可能になりました。
エラーの出る書き方
|
1 |
var a: Int |
1.2 で可能になった描き方
|
1 2 |
lateinit var b: Int b = 1 |
従来はこのような書き方をするとエラーになりました。
例えば次のような場合に役に立つと思われます。
|
1 2 3 4 5 6 7 8 9 10 |
var i : Int if (condition) { i = a * b } else { i = a + b process1(i) } process2(i) |
lateinit 修飾子 は、定数に使うことはできません。
そしてこの lateinit で修飾されたプロパティが初期化されているか否かを判定できるようになりました。 :: で プロパティ情報にアクセスし、 isInitialized で初期化情報を取得します。
|
1 2 3 4 5 6 7 |
class Sample { lateinit var a: Int fun check(): Boolean { return if f (this::a.isInitialized) 1 else 2 } } |
プロパティ参照の簡略化
従来は、 クラス内で this::a のように書くとプロパティ参照ができていました。 これが 1.2 になってから、 ::a と書くだけでプロパティ参照できるようになりました。 これにより、ラムダ関数内でのプロパティアクセスが楽になりました。 (参考: https://youtrack.jetbrains.com/issue/KT-1566)
BigInteger, BigDecimal の演算子、変換メソッド追加
BigInteger, BigDecimal は、任意精度の数を扱えるクラスです。 Int, Long 等のクラスから BigInteger, BigDecimal に変換するための toBitInteger, toBigDecimal という関数が追加されました。 クラスと使えるメソッドの対応は下の表のようになっています。
toBigInteger |
toBigDecimal |
|
|---|---|---|
Int |
O | O |
Long |
O | O |
Float |
O | |
Double |
O | |
BigInteger |
O |
そして、これまで BigInteger, BigDecimal の計算では、 add, subtract, multiply, divide, remainder メソッドを記述する必要がありましたが、 2項演算子 +, -, *, /, %、 ビット演算子 and, or, xor, shl, shr、単項演算子 -, ++, -- が導入されて、ずっと記述が楽になりました。
|
1 2 3 4 5 6 |
// 従来の計算方法 >>> BigDecimal("1.0000").add(BigDecimal("3.0000")) 4.0000 // 1.2 で可能になった計算方法 >>> BigDecimal("1.0000") + BigDecimal("3.0000") 4.0000 |
小数表現とビットの相互変換
Double, Float について、 ビット表現に変換するメソッド toBits, toRawBits が実装されました。 返り値の型は次の表のようになります。
toBits, toRowBits |
|
|---|---|
Double |
Long |
Float |
Int |
Double の toBits, toRawBits は、それぞれ java.lang.Double.doubleToLongBits, java.lang.Double.doubleToLongRawBits を呼び出しています。 Float の toBits, toRawBits は、それぞれ java.lang.Float.floatToIntBits, java.lang.Float.floatToIntRawBits を呼び出しています。
実行例
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
// toString(2).padStart(64, ‘0’) でビット表現にして出力しています。 listOf(0.125, 0.25, 0.5, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0).forEach { println(it.toBits().toString(2).padStart(64, '0')) } // 0.125 0011111111000000000000000000000000000000000000000000000000000000 // 0.25 0011111111010000000000000000000000000000000000000000000000000000 // 0.5 0011111111100000000000000000000000000000000000000000000000000000 // 1.0 0011111111110000000000000000000000000000000000000000000000000000 // 2.0 0100000000000000000000000000000000000000000000000000000000000000 // 3.0 0100000000001000000000000000000000000000000000000000000000000000 // 4.0 0100000000010000000000000000000000000000000000000000000000000000 // 5.0 0100000000010100000000000000000000000000000000000000000000000000 // 6.0 0100000000011000000000000000000000000000000000000000000000000000 listOf<Float>(0.125F, 0.25F, 0.5F, 1.0F, 2.0F, 3.0F, 4.0F, 5.0F, 6.0F).forEach { println(it.toRawBits().toString(2).padStart(32, '0')) } 00111110000000000000000000000000 00111110100000000000000000000000 00111111000000000000000000000000 00111111100000000000000000000000 01000000000000000000000000000000 01000000010000000000000000000000 01000000100000000000000000000000 01000000101000000000000000000000 01000000110000000000000000000000 |
ビット表現から Double, Float を生成する fromBits というメソッドも追加されました。 Double.fromBits は java.lang.Double.longBitsToDouble を、 Float.toBits は java.lang.Float.intBitsToFloat を呼び出しています。
toBits と toRawBits は、 NaN をどのように扱うかという点で違いがあります。 NaN は 指数部のビットが全て 1 で,仮数部のビットのどこかが 1 になっているものと定められています。 そのため toRawBits では、 ビット表現が異なれば、出力も異なる値になります。 一方、 toBits ではすべての NaN は同一の値 (Double.NaN) になります。
|
1 2 3 4 5 6 7 8 9 10 |
>>> Double.fromBits(0x7ff8000000000000L).toRawBits().toString(2).padStart(64, '0') 0111111111111000000000000000000000000000000000000000000000000000 // 以下はすべて Double.NaN と同じ >>> Double.fromBits(0x7ff8000000000100L).toRawBits().toString(2).padStart(64, '0') 0111111111111000000000000000000000000000000000000000000100000000 >>> Double.fromBits(0x7ff8000000000100L).toBits().toString(2).padStart(64, '0') 0111111111111000000000000000000000000000000000000000000000000000 >>> Double.fromBits(0x7ff8000000000000L).toBits().toString(2).padStart(64, '0') 0111111111111000000000000000000000000000000000000000000000000000 |
kotlin.text.Regex の Serializable 実装
クラス kotlin.text.Regex が kotlin.io.Serializable を実装しました。 これにより、Regexオブジェクトが Serializable のオブジェクトとして扱えるようになり、一時的にオブジェクトを保存する際に Regex のオブジェクトもまとめてシリアライズできるようになりました。 kotlin.io.Serializable は java.io.Serializable の型エイリアスとなっています。
非推奨化: vararg 引数への単一値代入
vararg で記述されていた関数の引数について、これまではひとつの値でも次のようにして渡すことができていました。
|
1 2 3 4 |
fun test(vararg v: String) { // ... } test(v = “test”) |
これは直感的でないため、 1.2 からは非推奨となりました。 1.2 では test(v = *arrayOf(“test”)) というように、展開演算子を用いて記述する方法が推奨されています。
Kotlin の 1.2ベータ版公開時のブログには、 最終的には test(v = arrayOf("test")) のように書けるようにしたいと書かれており、 1.2 では段階的移項のためにこのようにしたとも書かれています。
従来の test(v = "test") のような書き方は、 1.2 では warning が表示されます。 1.3 では廃止される予定です。
非推奨化: Enum class のエントリの中でのクラス定義
Enum のエントリの中でクラスを定義することが非推奨となりました。 1.3ではエラーとなる予定です。
|
1 2 3 4 5 |
enum class A { B { class C // => Deprecated } } |
型推論の向上
型パラメータによって指定されたクラスの値を返します。
特に Android 開発では Android API level 26 から findViewById などでジェネリクスが導入されているので、この改善による恩恵は大きいです。
Kotlin 標準ライブラリ
Kotlin の標準ライブラリは複数のjarファイルで同一のパッケージのクラスを宣言できないという Java 9 のモジュールシステムと完全互換となりました。これにあわせて kotlin-stdlib-jre7, kotlin-stdlib-jre8 は非推奨となり、それに代わるライブラリ kotlin-stdlib-jdk7, kotlin-stdlib-jdk8 が導入されました。
拡張: windowd, chunked, zipWithNext
Iterable<T>, Sequence<T>, CharSequence に対して、バッチ処理に使うための chunked 関数、 スライドするための windowed 関数、 要素とその次の要素から作られる新しい要素列を作り出す zipWithNext が追加されました。
|
1 2 3 4 5 6 |
>>> sequenceOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10).zipWithNext { a, b -> a * b } .toList() [2, 6, 12, 20, 30, 42, 56, 72, 90] >>> sequenceOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10).windowed(4).toList() [[1, 2, 3, 4], [2, 3, 4, 5], [3, 4, 5, 6], [4, 5, 6, 7], [5, 6, 7, 8], [6, 7, 8, 9], [7, 8, 9, 10]] >>> sequenceOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10).chunked(4).toList() [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10]] |
Listの拡張
MutableList に fill, replaceAll, shuffle が、 List に shuffled が追加されました。
| 関数名 | 挙動 |
|---|---|
| fill | リストのすべての要素を書き換える |
| replaceAll | リストの要素で該当するものを置き換える |
| shuffle | リストの中身をランダムに入れ替える |
| shuffled | リストの中身をランダムに入れ替えた新しいリストを作る |
数値計算のためのライブラリ強化
数値計算のために、 kotlin.math API が追加されました。 π, e(自然対数) や三角関数、対数等が扱えるようになりました。
警告をエラーとして扱う
警告をエラーとして扱えるようになりました。 コマンドラインで オプション -Werror をつける方法と、 gradle に次のように書く方法があります。
|
1 2 3 |
compileKotlin { kotlinOptions.allWarningsAsErrors = true } |
super から呼び出す Java メソッド のエラー化
Java のメソッドを override して作成した Kotlin のメソッド内で、同一の関数を super を使って呼び出すとエラーになります。 ターゲットとなる JVM を 1.8 にすることでエラーが解消されます。
|
1 2 3 4 5 |
class CustomNewClass : SuperClass { override fun sampleMethod() { super.sampleMethod() // => Error } } |



