Kotlin
A concise multiplatform language developed by JetBrains
Kotlin 1.5.0-RC リリース: 標準ライブラリとテストライブラリの変更点
Kotlin 1.5.0-RC では 1.5.0 への搭載が予定されているすべての機能が使用できます。今後のリリースの完全なスコープをご覧ください! 新しい言語機能や stdlib の更新、改良されたテストライブラリをはじめとする、さまざまな変更内容が仕上げの最終段階に入っています。 リリース前には、最後の変更として修正作業がいくつか行われます。
実際のプロジェクトで 1.5.0-RC を使って最新の Kotlin API をお試しください。リリースされるバージョンの改善にぜひご協力ください! 問題を発見したら、当社の課題トラッカー YouTrack までご報告ください。
この記事では、1.5.0-RC で Kotlin 標準ライブラリとテストライブラリに加えられた以下の変更内容について見て行きます。
- Stable 化した符号なし整数型
- java.nio.file.Path 向けの拡張機能
- String API と Char API の改善
- Duration API への変更内容
- モジュラ算術に加えられた新しい数学演算
- Collection の新しい関数
- テストライブラリへの変更内容
詳しくは以下をお読みください!
Stable 化した符号なし整数型
標準ライブラリには、負以外の整数を伴う演算に便利な符号なし整数用の API が含まれています。 次を含みます:
- 符号のない数値型 (
UInt
、ULong
、UByte
、UShort
)、および関連する関数 (型変換など)。 - 集合型 (Arrray、Range)、符号なし整数の数列 (
UIntArray
、UIntRange
)、および他の型用に使う類似のコンテナ。
符号なし整数型は、Kotlin 1.3 のベータ版から組み込まれています。 今回のリリースにより、符号なし整数型とそれを伴う演算を Stable 化したしたものと分類し、実際のプロジェクトでオプトインなしで安全に使用できるようになりました。
主に、以下が Stable 化した API となっています。
- 符号なし整数型
- Range および符号なし整数型の数列
- 符号なし整数型を伴う演算ができる関数
符号なし整数の配列は、引き続きベータ版での使用となります。 配列が渡される符号なし整数の varargs も同じです。 コードに使用する場合は、@ExperimentalUnsignedTypes
アノテーションを使ってオプトインできます。
Kotlin の符号なし整数について詳しく見る。
java.nio.file.Path API の拡張機能
Kotlin では、java.nio.file.Path
の拡張関数を使えば、最新の非ブロッキング Java I/O をそのまま Kotlin-idiomatic スタイルで利用できるようになりました。
こちらがその一例です。
これらの拡張機能は、Kotlin 1.4.20 に試験的な機能として導入されたものですが、今回オプトインなしで使用できるようになりました。 使用できる機能の一覧は、kotlin.io.path
パッケージをご覧ください。
File API の既存の拡張機能は引き続き使用できますので、お気に入りの API を自由に選択できます。
ロケールに依存せずに使える大文字・小文字の API
皆さんの多くは、toUpperCase()
、toLowerCase()
、toTitleCase()
など、文字列や文字の大文字・小文字を変換する stdlib 関数についてご存知かと思います。 こうした関数は、普段は問題なく機能するのですが、プラットフォームのロケールが変わると不便なことがあります。ロケールの影響を受ける関数であるため、ロケールによっては結果が変わってしまう場合があるのです。 たとえば、”Kotlin”.toUpperCase()
の実行結果はどうなりますか? 「明らかに KOTLIN
です」と言われるでしょう。 ですが、ロケールがトルコの場合だと、i
の大文字は İ
ですので、実行結果は少し違って KOTLİN
になってしまうのです。
今回のリリースには、文字列や文字の大文字・小文字の変換に便利な uppercase()
、lowercase()
、titlecase()
といった関数がロケールに依存しない API として、それぞれ *Char()
関数と共に盛り込まれています。 すでに 1.4.30 のプレビュー実装をお試しになっているかもしれません。
今回の新しい関数は、プラットフォームのロケール設定を問わず、同じように機能します。 関数を呼び出せば、あとは stdlib が処理してくれます。
新しい関数は、プラットフォームのロケールを問わず、同じように機能します。 関数を呼び出せば、あとは stdlib が処理してくれます。
JVM では、現在のロケールを引数として新しい関数を呼び出せば、ロケールに注意が必要な大文字・小文字の変換でも問題なく実行できます。
新しい関数は、完全に古いものに取って代わり、古いものは非推奨とすることになりました。
分かりやすくなった Char-to-code と Char-to-digit 変換
文字型の UTF-16 コードを取得する操作 (toInt()
関数) は、よく知られた落とし穴となっていました。なぜなら、1 桁の数値文字列に対して実行され、その数値そのものを Int
として作成する String.toInt()
によく似ているからです。
また、Char
'4'
に対して実行されるときに、数値の 4
を返す一般的な関数もありませんでした。
こうした課題を解決するために、文字型とその整数コードおよび数値の間で変換操作を行える以下の関数が開発されました。
Char(code)
とChar.code
は文字とそのコードの間で変換を行います。Char.digitToInt(radix: Int)
および*OrNull
を使ったバージョンは、radix に指定される数値で整数を作成します。Int.digitToChar(radix: Int)
は、radix に指定される整数を表す数値で文字を作成します。
これらの関数には分かりやすい名前が付けられているため、コードが読みやすくなります。
これらは、Kotlin 1.4.30 以来プレビューモードでのみ使用できましたが、今回のリリースで Stable 化されました。 文字を数字に変換する古い関数 (Char.toInt()
および他の数値型に使う類似の関数) および数字を文字に変換する古い関数 (Long.toChar()
および Int.toChar()
を除く類似の関数) は非推奨とされました。
マルチプラットフォーム対応 Char API の拡張
当社は、マルチプラットフォームプロジェクトの共通コードに標準ライブラリのすべての機能を使用できるよう、引き続きマルチプラットフォーム対応機能の拡張に取り組んでいます。
あらゆるプラットフォームや共通コードで使用できる Char
関数をいくつか作成しました。 以下がその関数です。
Char.isDigit()
、Char.isLetter()
、char が文字なのか、数字なのかをチェックするChar.isLetterOrDigit()
。Char.isLowerCase()
、Char.isUpperCase()
、Char が大文字なのか小文字なのかをチェックするChar.isTitleCase()
。- char が
Cn
(未定義) 以外の Unicode 一般カテゴリ を持っているのかをチェックするChar.isDefined()
。 - char が
\u0000
..\u001F
または\u007F
..\u009F
の範囲のコードを持つ ISO 制御文字 なのかをチェックするChar.isISOControl()
。
プロパティ Char.category
およびその返り値の型で、Unicode に従って文字の一般カテゴリーを示す enum クラス CharCategory
がマルチプラットフォームプロジェクトで使用できるようになりました。
String?.toBoolean() の厳密なバージョン
Kotlin の String?.toBoolean()
関数は、文字列から真偽値を作成するのによく使用されています。 その機能は、文字列が "true" であれば、大文字か小文字かにかかわらず true
、それ以外の文字列は null も含めてすべて false
となりとてもシンプルです。
これは自然な挙動に思える一方で、潜在的に誤りのある状況が隠れてしまう場合があります。 この関数で何かを変換すると、文字列に予期せぬ値が代入されていたとしても、boolean が返されてしまいます。
そこで、そうしたミスを避けるために、大文字・小文字を区別する String?.toBoolean() の厳密なバージョンが新しく作成されました。
String.toBooleanStrict()
はリテラル “true” と “false” 以外のすべての入力に対して例外を投げます。String.toBooleanStrictOrNull()
はリテラル “true” と “false” 以外のすべての入力に対して null を返します。
Duration API への変更内容
experimental な Duration and Time Measurement API は、バージョン 1.3.50 以来、stdlib に実装されてきました。 時間間隔を正確に測定するための API を提供してくれます。
この API の主なクラスの 1 つに Duration
クラスがあります。 2 つの時刻のインスタンス間の時間を表します。 バージョン 1.5.0 では、Duration
の API と内部表現の両方に重大な変更が加えられています。
Duration
では内部表現に Double
値ではなく Long
値が使用されるようになりました。 Long
値が幅広い範囲を提供してくれるおかげで、 ナノ秒の精度では 100 年以上、ミリ秒の精度では 1 億年以上の時間を表現することができます。 ただし、以前サポートされていたサブナノ秒の Duration は使用できなくなりました。
また、Duration を Long
値として取得するためのプロパティも導入しています。 これらは、Duration.inWholeMinutes
や Duration.inWholeSeconds
など、さまざまな 時間単位で使用できます。 こうした関数は、Duration.inMinutes
など、Double
ベースのプロパティに取って代わるものとして作成されました。
もう 1 つの変更点として、整数値から Duration
のインスタンスを作成する一連のファクトリ関数が新たに作成されました。 これらは、直接 Duration
型の中に定義され、Int.seconds
のような数値型の古い拡張プロパティに代わって実装されています。
こうした大きな変更が加えられていることもあり、Duration and Time Measurement API は 1.5.0 でも引き続き全体的に experimental 段階に留まっており、使用する場合は @ExperimentalTime
アノテーションによるオプトインが必要になります。
ぜひ、新しいバージョンをお試しいただき、当社の課題トラッカー YouTrack までご感想をお聞かせください。
数学演算: 切り捨て除算と mod 演算子
Kotlin では、整数に対して除算演算子 (/
) を使用することは、切り捨て除算を意味し、演算結果の少数部が省略されます。 合同算術(モジュラ計算)では、演算の結果を (小さい方の整数に向って) 丸める床除算という別の選択肢もあり、負数に対して使用すると異なる結果が得られます。
これまで、床除算を行うには以下のようなカスタム関数が必要でした。
1.5.0-RC では、整数に対して床除算を行う floorDiv()
関数を導入します。
1.5.0 では、新しくなった mod()
関数も導入しています。 今回のリリースからは、その名前の通り、剰余 (床除算の結果の余り) を返すようになりました。
Kotlin の rem()
(または %
演算子) とは異なります。 剰余とは a
と a.floorDiv(b) * b
の差のことです。 0 以外の剰余は常に b
と同じ記号になる一方で、a % b
の場合は違う記号になることがあります。 たとえば、以下のように循環リストを実装する場合に便利です。
Collections: firstNotNullOf() と firstNotNullOfOrNull()
Kotlin の Collections API はビルトイン関数を使ってよく行われる操作を幅広くカバーしています。 稀な処理を行う場合は、こうした関数の呼び出しを組み合わせるのが一般的です。 ちゃんと機能はしますが、すっきりとしたコードを記述できないことがある上に、オーバーヘッドも増えてしまいます。
たとえば、Collection 要素に対し実行されるセレクタ関数の最初の null 以外の結果を取得するには、mapNotNull()
と first()
を呼び出してもよいでしょう。 これを 1.5.0 では、新しい関数 firstNotNullOf()
を一回呼び出すだけでできます。 firstNotNullOf()
に対応する関数として、返す値がないときには null を作成する *orNull()
関数を一緒に追加しています。
この関数を使ってコードを短くする方法の例を 1 つ紹介します。
null 許容プロパティを持つクラスがあり、クラスインスタンスの一覧から最初の null 以外の値を取得する必要があるとします。
これは、以下のように Collection をイテレーションし、プロパティが null でないかどうかを確認することで実装できます。
他の方法として、前から存在する関数 mapNotNull()
と firstOrNull()
を使うこともできます。 mapNotNull()
を使うと、中間コレクションが構築され、特にコレクションが大きい場合はメモリがさらに必要となるため注意が必要です。 したがい、ここではシーケンスへの変換も必要になる可能性があります。
そして、新しい関数を使うと、以下のような記述になります。
テストライブラリへの変更内容
ここ最近のリリースでは、Kotlin のテストライブラリ kotlin-test
のメジャーなアップデートは実現できていませんが、今回ついにいくつか変更を加えることができました。 1.5.0-RC では、新機能をたくさん試していただけます。
- マルチプラットフォームプロジェクトにおける
kotlin-test
に対する依存の単一化。 - Kotlin/JVM ソースセット用テストフレームワークの自動選択。
- アサーション関数の更新。
マルチプラットフォームプロジェクトにおける kotlin-test への依存
当社は、引き続きマルチプラットフォームプロジェクトの設定プロセスの開発に取り組んでいます。 1.5.0 では、あらゆるソースセットにおける kotlin-test
への依存関係を簡単にセットアップできるようにしました。
今回、テスト用の共通ソースセットに kotlin-test
への依存関係を追加するだけでよくなりました。 他のソースセットに対応するプラットフォームの依存については、Gradle プラグインが推論してくれます。
- JVM ソースセット用
kotlin-test-junit
。 明示的に有効化すれば、kotlin-test-junit-5
やkotlin-test-testng
に切り替えることもできます (その方法は後ほど説明します)。 - Kotlin/JS ソースセット用
kotlin-test-js
。 - 共通ソースセット用
kotlin-test-common
およびkotlin-test-annotations-common
。 - Kotlin/Native にはあらかじめ
kotlin-test
API が実装されているため、Kotlin/Native ソースセットに別のアーティファクトは用意されていません。
Kotlin/JVM ソースセット用テストフレームワークの自動選択
上述したとおりに、テスト用の共通ソースセットに kotlin-test
への依存関係をセットアップしたら、JUnit 4 で JVM ソースセットの依存関係が自動的に設定されます。 以上です! テストコードを書いてすぐに実行できます!
Groovy DSL では以下のようなコードになります。
Kotlin DSL の場合はこうなります。
テストタスク内で useJUnitPlatform()
か useTestNG()
を呼び出せば、それぞれ JUnit 5 または TestNG に切り替えることもできます。
kotlin-test
への依存関係を追加すれば、JVM のみ使用するプロジェクトでも同じことを行えます。
アサーション関数の更新
1.5.0 では、新しいアサーション関数をいくつか作成し、既存の関数に改善を加えました。
それでは、まず新しい関数をさっと見てみましょう。
assertIs<T>()
とassertIsNot<T>()
は値の型をチェックします。assertContentEquals()
は配列、シーケンス、Iterable
の中身を比較します。 より正確には、expected
とactual
に同じ要素が同じ順番で格納されているかどうかをチェックします。assertEquals()
とassertNotEquals()
は、Double
とFloat
の要素に対して「precision」(精度)という 3 つ目のパラメーターを使ってオーバーロードができるようになりました。assertContains()
は、contains()
演算子 (配列、リスト、レンジなど) が定義されたオブジェクトの中にアイテムが存在するかどうかをチェックします。
こちらが、これらの関数の簡単な使用例です。
既存のアサーション関数について: 関数 assertTrue()
、assertFalse()
、expect()
はすべてインライン化されたため、それらに渡されるラムダの中でサスペンド関数を呼び出せるようになりました。
Kotlin 1.5.0 の全機能をお試しください
1.5.0-RC で Kotlin の最新 API のすべてを実際のプロジェクトで活用しましょう!
IntelliJ IDEA か Android Studio のどちらかで、Kotlin プラグイン 1.5.0-RC をインストールしてください。 EAP プラグインのバージョンを取得する方法を見る。
既存のプロジェクトを 1.5.0-RC で構築し、1.5.0 での動作を確認しましょう。 プレビューリリース用に簡素化された新しい構成では、Kotlin バージョンを 1.5.0-RC
に変更し、必要に応じて依存関係のバージョンを調整するだけで OK です。
いつものように、最新バージョンは Kotlin Playground からオンラインでお試しいただけます。
互換性
すべての機能リリースと同様に、Kotlin 1.5.0 を以て、以前に発表した変更の使用廃止サイクルが一部終了を迎えます。 すべてのケースは言語委員会による十分な検討の後、「Kotlin 1.5 の互換性ガイド」に記載されています。 また、YouTrack でも変更内容を確認することができます。
リリース候補ノート
Kotlin 1.5.0 のリリース候補を紹介したところで、今度は皆さんがコンパイルと公開を行う番です! 前回のマイルストーンリリースとは異なり、Kotlin 1.5.0-RC で作成されたバイナリーは、Kotlin 1.5.0 との互換性が保証されています。
ご意見をお寄せください
これが次の機能リリースに貢献する最後のチャンスです! 問題を発見されましたら、当社の課題トラッカーにてお知らせください。 コミュニティ全体のために Kotlin 1.5.0 を改善しましょう!