2019/8/22 Kotlin 1.3.50がリリースされました
Kotlin 1.3.50 released
併せて
Kotlin coroutiees1.3.0もリリースされましたね!
(こっちは今回触れませんが..)
Kotlin Fest 2019も開催直前でのリリースとなりました!
(登壇された方は直前に1.3.50に対応するため資料修正が大変だったとか..)
以下リリースブログを略しながら翻訳しました。
あまり慣れてないので誤訳があったらごめんなさい
サマリ
- Null-Checkの仕組みが最適化されました
- 新しいDuration and time measurement APIが実装されました(プレビューで利用可能)
- Java-to-Kotlinコンバータが改良されました
- ExperimentalとしてGradle Kotlin/JS projectsにおいて、Dukatを用いてnpmの依存解決を外部に宣言できるようになりました。
- IntelliJ IDEA Ultimate向けにKotlin/Nativeデバッグ用のプラグインが登場
- マルチプラットフォームプロジェクトでのJavaコンパイルのサポート
Kotlin 1.4に向けたNull-checkの最適化
Kotlinは、null許容型をサポートすることにより、NullPointerExceptionsの可能性を減らしますが、Javaコードとの相互運用性のためNPEを完全に回避することは不可能です。開発者がNull possibilityの原因をより理解できるように、Kotlinコンパイラーは純粋なNPEの代わりに明確なエラーメッセージでさまざまなタイプのランタイム例外をスローします。このアプローチには問題があることが判明しました。KotlinコンパイラーまたはAndroid R8オプティマイザーなどのさまざまな種類のバイトコード処理ツールのいずれかによって実行される可能性のあるNullチェックの最適化の妨げになります。
これを解決するために、Kotlin 1.4以降、すべてのランタイムnullチェックはKotlinNullPointerException、IllegalStateException、IllegalArgumentException、およびTypeCastExceptionの代わりにjava.lang.NullPointerExceptionをスローします。以下に適用されます。
- 演算子、メソッドプリアンブルのパラメーターnullチェック
- プラットフォーム型の式nullチェック
- null以外の型のas演算子
※lateinit nullチェックおよびcheckNotNullやrequireNotNullなどの明示的なライブラリ関数呼び出しには適用されません。
開発者の観点からは、それほど変化はありません。Kotlinコードは、以前と同じエラーメッセージで例外をスローします。例外の種類は変わりますが、渡される情報は変わりません。次のコードは現在、エラーメッセージ"avaCode.getNull() must not be null"でIllegalStateExceptionをスローします。
fun main() {
duplicate(JavaCode.getNull()) // 1
}
fun duplicate(s: String) = s + s
public class JavaCode {
public static String getNull() { return null; }
}
JavaCode.getNull()がnullを格納する場合に例外をスローする特別なチェックが働きます。 Kotlin 1.4以降では、このコードはエラーメッセージ"JavaCode.getNull() must not be null"の代わりにNullPointerExceptionをスローします。
この変更によりnullチェックの繰り返しを削減し、バイトコードに存在するnullチェックを減らすことができます。
Standard Libraryの変更点
新たに追加される関数は全て「試験的」な関数です
Duration and time measurement API
プレビュー版の新しいduration and time measurement APIが利用できます。
期間は、秒、ミリ秒、ナノ秒などのさまざまな単位で測定できます。異なる単位は混乱し、バグの原因になります。APIがLongのようなプリミティブ値として格納される期間を予期する場合、ユニット、型システムはそれを防ぐのに役立ちません。 通常のクラスを作成して期間を保存することによりこの問題は解決しますが余分な割り当ての問題が発生します。
インラインクラスは、上記の問題に洗練されたソリューションを提供します。型システムの保証と割り当てのないアプローチの両方をもたらします。APIはDurationタイプを使用できるようになり、すべてのクライアントが目的の単位で時間を明示的に指定する必要があります。 Durationはインラインクラスとして宣言されているため、内部で余分な割り当ては発生しません。
import kotlinx.coroutines.delay
import kotlin.time.*
@ExperimentalTime
suspend fun greetAfterTimeout(duration: Duration) {
delay(duration.toLongMilliseconds())
println("Hi!")
}
@UseExperimental(ExperimentalTime::class)
suspend fun main() {
greetAfterTimeout(100.milliseconds)
greetAfterTimeout(1.seconds)
}
このリリースでは、単調時計を表すMonoClockがサポートされます。プログラムの特定の時点から継続時間を測定するための推奨されるアプローチは、システム時間に依存しない単調時計を使用することです。 システム時間は外部で変更される可能性があり、それが誤った動作につながる可能性があります。単調時計は、指定された時点間の時間差のみを測定できますが、「現在の時刻」はわかりません。
Clockインターフェースは、時間間隔を測定するための一般的なAPIを提供します。 MonoClockは、Clockを実装するオブジェクトです。 異なるプラットフォームでの単調時間のデフォルトのソースを提供します。
Clockインターフェースを使用する場合、アクションの開始時間を明示的にマークし、後で開始ポイントからの経過時間をマークします。 さまざまな機能から時間の測定を開始および終了する場合に特に便利です。
import kotlin.time.*
@UseExperimental(ExperimentalTime::class)
fun main() {
val clock = MonoClock
val mark = clock.markNow() // might be inside the first function
Thread.sleep(10) // action
println(mark.elapsedNow()) // might be inside the second function
}
measureTimedValue関数を使用すると、特定のアクションの期間を測定し、その結果を経過時間間隔の期間と一緒に取得できます。 MonoClockで経過時間を測定します。
import kotlin.time.*
@UseExperimental(ExperimentalTime::class)
fun main() {
val (value, duration) = measureTimedValue {
Thread.sleep(100)
42
}
println(value) // 42
println(duration) // e.g. 103 ms
}
Durationクラスの実装の詳細、および異なるプラットフォームのClockインターフェースとMonoClock実装の詳細については、KEEPを御覧ください。
このAPIは実験的なものであり、フィードバックに基づいて変更される可能性があることに注意してください。
Bit manipulation関数
Standard Libraryに、ビット操作用のAPIが試験的に実装されました。
@UseExperimental(ExperimentalStdlibApi::class)
fun main() {
val number = "1010000".toInt(radix = 2)
println(number.countOneBits())
println(number.countTrailingZeroBits())
println(number.takeHighestOneBit().toString(2))
println(number.rotateRight(3).toString(2))
println(number.rotateLeft(3).toString(2))
}
※Int、Long、Short、Byte、およびそれに対応する符号なし拡張機能が追加されていることに注意してください。
IntelliJ IDEAサポート
Java-to-Kotlinコンバータの改良
変換後に手動で修正するコード量を最小限に抑えるために、JavaからKotlinへのコンバーターを改善する予定です。現在のコンバーターはほとんどの場合、non-nullable型を生成するため、nullabilityの問題は後で手動で修正する必要があります。多くの場合、後でnullabilityの不一致からランタイムエラーが発生する可能性があります。
Java-to-Kotlinコンバーターの新しい改良バージョンは、コード内のJavaタイプの使用に基づいて、nullabilityをより正確に推測しようとします。 100%エラーのないコードを作成するという目標はありません。目標は、コンパイルエラーの数を減らし、生成されたKotlinコードを操作しやすくすることです。新しいコンバーターは、他の多くの既知のバグも修正します。たとえば、暗黙のJava型キャストを正しく処理するようになりました。
将来的には、新しいコンバーターがデフォルトのコンバーターになります。このリリースでは、プレビューで利用できます。オンにするには、設定で"Use New J2K (experimental)"フラグを指定します。
デバッグの改良
Kotlin“Variables”ビューが表示する変数を選択する方法を改善しました。バイトコードには多くの追加の技術情報があるため、“Variables”ビューでは関連する変数のみが強調表示されます。 ラムダ(インラインまたは非インライン)内にブレークポイントを設定すると、より適切に動作するようになりました。 ラムダ内のローカル変数、および外部コンテキストからキャプチャされた変数と外部関数のパラメーターが正しく表示されます。
必要に応じて、関数の最後にブレークポイントを設定できます。
「式の評価」機能のサポートは、ローカル拡張機能やメンバー拡張プロパティのアクセサーなど、多くの重要な言語機能で改善されました。 また、「式の評価」機能で変数を変更できるようになりました。
新しい意図と検査
新しい意図と検査が追加されました。目標の1つは、慣用的なKotlinコードの書き方を学ぶのを支援することです。 たとえば、インデックスの範囲を手動で構築するのではなく、indexesプロパティを使用することを提案します。
インデックスを使用しない場合、ループは要素のforループに自動的に置き換えることができます。
- プリミティブ型のlateinitプロパティをby Delegates.notNull()構文で自動的に置き換えることができます。
- 通常のプロパティをレイジープロパティに変換したり、逆に変換したりできます。
- 配列比較(Arrays.equals()やArray.deepEquals()など)のJavaメソッドの使用を検出し、それらをKotlinの対応するもの(contentEqualsやcontentDeepEqualsなど)に置き換えることを提案します。
- 非推奨のインポートを強調表示します。
Kotlin/JS
- Windowsでorg.jetbrains.kotlin.jsプラグインを使用してKotlin/JS Gradleプロジェクトをビルドおよび実行するためのサポートが追加。
- 他のプラットフォームと同様に、Gradleタスクを使用してプロジェクトをビルドおよび実行でき、Gradle構成に必要なNPMの依存関係が解決可能に。
- webpack-dev-serverを使用してアプリケーションを実行可能に。他のプラットフォームと同様に、ノード、npm、またはYarnの配布を手動でインストールおよび管理が不要に。
- Kotlin 1.3.41と比較してKotlin/JSの一連のパフォーマンスが最大30%高速化。
- NPMとの統合の改善により、プロジェクトが遅延して並行して解決されるようになり、同じプロジェクトのコンパイル間で推移的な依存関係を持つプロジェクトのサポートが追加。
- 生成されたアーティファクトの構造と命名が変更。
- 生成されたアーティファクトは配布フォルダーにバンドルされるようになり、プロジェクトのバージョン番号とarchiveBaseName(デフォルトはプロジェクト名になります)が含まれます。projectName-1.0-SNAPSHOT.js。
Dukat
TypeScript宣言ファイル(.d.ts)をKotlin外部宣言に自動的に変換できます(ts2ktコマンドラインツールを置き換え)。 JSライブラリのラッパーを手動で記述する必要性が大幅に削減されるため、KotlinでJavaScriptエコシステムのライブラリをタイプセーフな方法で快適に使用できます。
Kotlin/JSは、Gradleプロジェクトのdukat統合を試験的にサポートします。Gradleでビルドタスクを実行することにより、npm依存関係に対してタイプセーフラッパーが自動的に生成され、Kotlinから使用できます。
Kotlin/Native
- Kotlin/NativeのバージョンがKotlinと統一
- macOSやiOSを含むすべてのプラットフォーム向けに、事前インポートされたAppleフレームワークが導入
- Kotlin/Nativeコンパイラは、生成されたフレームワークに実際のビットコードを包含
- フレームワークの作成時にkotlin.Deprecatedアノテーションをサポート
- getOriginalKotlinClass()関数が標準ライブラリに追加され、Objective-CクラスまたはプロトコルからKClassを取得可能に
- 標準ライブラリは、Kotlin/Native型のkotlin.reflect.typeOf()関数をサポート
- executeAfter()がWorkerタイプに追加。アクションをディレイ実行します。さらに、ワーカーでprocessQueue()関数を呼び出して、タスクキューを明示的に処理できるようになりました
- ByteArray.stringFromUtf8()、ByteArray.stringFromUtf8OrThrow()が非推奨に
- ByteArray.toKString()関数の実装
- kotlin-platform-native Gradle pluginを廃止し、kotlin-multiplatform Gradle pluginを採用
マルチプラットフォームプロジェクト
Javaコンパイルは、DSLの新しく追加されたwithJava()関数を呼び出すことにより、マルチプラットフォームプロジェクトのKotlin / JVMターゲットに含めることができるようになりました。 デフォルトでsrc / Main / javaおよびsrc / Test / javaパスを使用するようにJavaプラグインを構成します。
plugins {
kotlin("multiplatform") version "1.3.50"
}
kotlin {
jvm {
withJava()
}
}
KotlinのNew Projectウィザードは、新しいプロジェクト用にGradle Kotlin DSLを生成するようになりました。
IntelliJ IDEA UltimateでのKotlin / Nativeコードのデバッグもサポートされるようになりました。
Native Debug for IntelliJ IDEA Ultimate
Scripting
複数の機能が追加され、スクリプトとREPLサポートが改善されます。kotlin-scripting-jsr223を依存関係として追加し、javaxを使用するだけでデフォルトJSR-223を実装したライブラリが利用可能になります。
JSR-223 APIを介して設定されるプロパティは、通常のKotlinプロパティとしてスクリプトからアクセスできるようになりました(以前は、バインディングマップを使用する必要がありました)。
val engine = ScriptEngineManager().getEngineByExtension("kts")!!
engine.put("z", 42)
engine.eval("""println("answer = $z")""")
依存関係を解決するためのRepositoryやDependsOnなどのアノテーションに加えて、現在のスクリプトに別のスクリプトを「インポート」するようにスクリプトコンパイラに指示する@Importアノテーションをサポートするようになりました。
// common.main.kts:
val foo = "common foo"
// script.main.kts:
@file:Import("common.main.kts")
val bar = "bar with $foo"
終わりに
Kotlin 1.4もそろそろ見えてきましたね。
Kotlin/JSやKotlin/Nativeも積極的に改良されており、Kotlinが今後どう成長していくか楽しみです。引き続きウォッチしようと思います
こちらの記事もKotlin1.3.50に対応させました!
Android + Kotlin 1.3のcoroutines(Async, Await)でHTTP通信を非同期処理