目次
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 } } |