Kotlin 1.7.0の新機能
Kotlin 1.7.0のIDEサポートは、IntelliJ IDEA 2021.2、2021.3、2022.1で利用可能です。
Kotlin 1.7.0がリリースされました。このバージョンでは、新しいKotlin/JVM K2コンパイラのAlpha版が公開され、言語機能が安定化され、JVM、JS、Nativeプラットフォームのパフォーマンスが向上しています。
このバージョンの主要な更新点は以下の通りです。
- 新しいKotlin K2コンパイラのAlpha版が利用可能になり、大幅なパフォーマンス改善を提供します。これはJVM専用であり、kaptを含むどのコンパイラプラグインも動作しません。
- Gradleにおけるインクリメンタルコンパイルの新しいアプローチ。インクリメンタルコンパイルは、依存する非Kotlinモジュール内で行われた変更にも対応し、Gradleと互換性があります。
- オプトイン要件アノテーション、確実な非NULL型、ビルダーインファレンスが安定化されました。
- 型引数にアンダースコア演算子が導入されました。これにより、他の型が指定されている場合に型引数を自動的に推論できます。
- このリリースでは、インラインクラスのインライン値への委譲による実装が可能になりました。これにより、ほとんどの場合メモリを割り当てない軽量ラッパーを作成できます。
変更点の簡単な概要は、こちらのビデオでもご確認いただけます。
JVM向けKotlin K2コンパイラがAlpha版に
このKotlinリリースでは、新しいKotlin K2コンパイラのAlpha版が導入されます。新しいコンパイラは、新しい言語機能の開発を加速し、Kotlinがサポートするすべてのプラットフォームを統一し、パフォーマンスの向上をもたらし、コンパイラ拡張のためのAPIを提供することを目指しています。
新しいコンパイラとその利点について、すでに詳細な説明を公開しています。
新しいK2コンパイラのAlpha版では、パフォーマンスの向上に主に焦点を当てており、JVMプロジェクトでのみ動作することに注意してください。Kotlin/JS、Kotlin/Native、その他のマルチプラットフォームプロジェクトはサポートしておらず、kaptを含むどのコンパイラプラグインも動作しません。
弊社のベンチマークでは、内部プロジェクトで優れた結果が示されています。
プロジェクト | 現在のKotlinコンパイラのパフォーマンス | 新しいK2 Kotlinコンパイラのパフォーマンス | パフォーマンス向上率 |
---|---|---|---|
Kotlin | 2.2 KLOC/s | 4.8 KLOC/s | ~ x2.2 |
YouTrack | 1.8 KLOC/s | 4.2 KLOC/s | ~ x2.3 |
IntelliJ IDEA | 1.8 KLOC/s | 3.9 KLOC/s | ~ x2.2 |
Space | 1.2 KLOC/s | 2.8 KLOC/s | ~ x2.3 |
TIP
KLOC/sのパフォーマンス数値は、コンパイラが1秒あたりに処理するコードの千行数を表します。
ご自身のJVMプロジェクトでパフォーマンス向上を確認し、古いコンパイラの結果と比較することができます。Kotlin K2コンパイラを有効にするには、以下のコンパイラオプションを使用します。
-Xuse-k2
また、K2コンパイラには多数のバグ修正が含まれています。このリストに含まれるState: Openの問題も、実際にはK2で修正済みであることに注意してください。
今後のKotlinリリースでは、K2コンパイラの安定性が向上し、より多くの機能が提供される予定です。ご期待ください!
Kotlin K2コンパイラでパフォーマンスに関する問題が発生した場合は、課題トラッカーに報告してください。
言語
Kotlin 1.7.0では、委譲による実装のサポートと、型引数用の新しいアンダースコア演算子が導入されます。また、以前のリリースでプレビューとして導入されたいくつかの言語機能が安定化されました。
インラインクラスのインライン値への委譲による実装を許可
値またはクラスインスタンスの軽量ラッパーを作成したい場合、すべてのインターフェースメソッドを手作業で実装する必要があります。委譲による実装はこの問題を解決しますが、1.7.0より前のバージョンではインラインクラスで動作しませんでした。この制限が解除され、ほとんどの場合メモリを割り当てない軽量ラッパーを作成できるようになりました。
interface Bar {
fun foo() = "foo"
}
@JvmInline
value class BarWrapper(val bar: Bar): Bar by bar
fun main() {
val bw = BarWrapper(object: Bar {})
println(bw.foo())
}
型引数用のアンダースコア演算子
Kotlin 1.7.0では、型引数用のアンダースコア演算子_
が導入されました。これにより、他の型が指定されている場合に型引数を自動的に推論できます。
abstract class SomeClass<T> {
abstract fun execute(): T
}
class SomeImplementation : SomeClass<String>() {
override fun execute(): String = "Test"
}
class OtherImplementation : SomeClass<Int>() {
override fun execute(): Int = 42
}
object Runner {
inline fun <reified S: SomeClass<T>, T> run(): T {
return S::class.java.getDeclaredConstructor().newInstance().execute()
}
}
fun main() {
// T is inferred as String because SomeImplementation derives from SomeClass<String>
val s = Runner.run<SomeImplementation, _>()
assert(s == "Test")
// T is inferred as Int because OtherImplementation derives from SomeClass<Int>
val n = Runner.run<OtherImplementation, _>()
assert(n == 42)
}
NOTE
アンダースコア演算子は、変数リストの任意の場所で使用して型引数を推論できます。
安定版のビルダーインファレンス
ビルダーインファレンスは、ジェネリックなビルダー関数を呼び出す際に役立つ特殊な型推論です。これにより、コンパイラはラムダ引数内の他の呼び出しに関する型情報を使用して、呼び出しの型引数を推論するのに役立ちます。
1.7.0以降、ビルダーインファレンスは、通常の型推論が型に関する十分な情報を得られない場合に、1.6.0で導入されたコンパイラオプション-Xenable-builder-inference
を指定しなくても自動的に有効になります。
カスタムジェネリックビルダーの書き方をご覧ください。
安定版のオプトイン要件
オプトイン要件は安定版となり、追加のコンパイラ設定は不要になりました。
1.7.0より前は、オプトイン機能自体が警告を避けるために引数-opt-in=kotlin.RequiresOptIn
を必要としました。これは不要になりましたが、-opt-in
コンパイラ引数を使用して、他のアノテーションやモジュールをオプトインすることは引き続き可能です。
安定版の確実な非NULL型
Kotlin 1.7.0では、確実な非NULL型が安定版に昇格しました。これらは、ジェネリックなJavaクラスやインターフェースを拡張する際により良い相互運用性を提供します。
新しい構文T & Any
を使用して、使用箇所でジェネリック型パラメータを確実な非NULLとしてマークできます。この構文形式は交差型の表記法に由来し、現在は&
の左側にNULL許容な上限を持つ型パラメータ、右側に非NULLなAny
がある場合に限定されます。
fun <T> elvisLike(x: T, y: T & Any): T & Any = x ?: y
fun main() {
// OK
elvisLike<String>("", "").length
// Error: 'null' cannot be a value of a non-null type
elvisLike<String>("", null).length
// OK
elvisLike<String?>(null, "").length
// Error: 'null' cannot be a value of a non-null type
elvisLike<String?>(null, null).length
}
確実な非NULL型の詳細については、こちらのKEEPをご覧ください。
Kotlin/JVM
このリリースでは、Kotlin/JVMコンパイラのパフォーマンスが向上し、新しいコンパイラオプションが導入されます。さらに、関数型インターフェースコンストラクタへの呼び出し可能な参照が安定版になりました。なお、1.7.0以降、Kotlin/JVMコンパイルのデフォルトターゲットバージョンは1.8
です。
コンパイラのパフォーマンス最適化
Kotlin 1.7.0では、Kotlin/JVMコンパイラのパフォーマンスが向上します。弊社のベンチマークによると、コンパイル時間はKotlin 1.6.0と比較して平均10%削減されました。例えば、kotlinx.html
を使用するプロジェクトなど、インライン関数の使用が多いプロジェクトでは、バイトコードの後処理の改善によりコンパイルが高速化されます。
新しいコンパイラオプション: -Xjdk-release
Kotlin 1.7.0では、新しいコンパイラオプション-Xjdk-release
が導入されます。このオプションは、javacのコマンドライン--release
オプションに似ています。-Xjdk-release
オプションは、ターゲットとなるバイトコードのバージョンを制御し、クラスパス内のJDKのAPIを指定されたJavaバージョンに制限します。例えば、kotlinc -Xjdk-release=1.8
は、依存関係にあるJDKがバージョン9以上であってもjava.lang.Module
の参照を許可しません。
NOTE
このオプションは、各JDKディストリビューションに対して効果があることを保証するものではありません。
こちらのYouTrackチケットでフィードバックをお寄せください。
関数型インターフェースコンストラクタへの安定版呼び出し可能な参照
関数型インターフェースコンストラクタへの呼び出し可能な参照が安定版になりました。呼び出し可能な参照を使用して、コンストラクタ関数を持つインターフェースから関数型インターフェースへの移行方法を学びましょう。
見つけた問題はYouTrackに報告してください。
JVMターゲットバージョン1.6の削除
Kotlin/JVMコンパイルのデフォルトターゲットバージョンは1.8
です。1.6
ターゲットは削除されました。
JVMターゲット1.8以降に移行してください。JVMターゲットバージョンの更新方法については、以下をご覧ください。
Kotlin/Native
Kotlin 1.7.0には、Objective-CおよびSwiftの相互運用性に関する変更が含まれ、以前のリリースで導入された機能が安定化されています。また、新しいメモリマネージャーのパフォーマンス向上とともに、その他の更新も含まれています。
- 新しいメモリマネージャーのパフォーマンス向上
- JVMおよびJS IRバックエンドとの統合されたコンパイラプラグインABI
- スタンドアロンAndroid実行可能ファイルへの対応
- Swiftのasync/awaitとの相互運用:
KotlinUnit
ではなくVoid
を返す - Objective-Cブリッジを介した未宣言例外の禁止
- CocoaPods連携の改善
- Kotlin/NativeコンパイラのダウンロードURLの上書き
新しいメモリマネージャーのパフォーマンス向上
NOTE
新しいKotlin/NativeメモリマネージャーはAlpha版です。将来的に互換性のない変更が行われる可能性があり、手動での移行が必要になる場合があります。YouTrackでフィードバックをいただければ幸いです。
新しいメモリマネージャーはまだAlpha版ですが、安定版になる途中です。このリリースでは、特にガベージコレクション(GC)において、新しいメモリマネージャーのパフォーマンスが大幅に向上します。具体的には、1.6.20で導入されたスイープフェーズの並行実装がデフォルトで有効になりました。これにより、アプリケーションがGCのために一時停止する時間を削減できます。新しいGCスケジューラは、特に大規模なヒープにおいて、GCの頻度を選択するのに優れています。
また、デバッグバイナリを特に最適化し、メモリマネージャーの実装コードで適切な最適化レベルとリンク時最適化が使用されるようにしました。これにより、弊社のベンチマークでデバッグバイナリの実行時間を約30%向上させることができました。
ご自身のプロジェクトで新しいメモリマネージャーを試してその動作を確認し、YouTrackでフィードバックをお寄せください。
JVMおよびJS IRバックエンドとの統合されたコンパイラプラグインABI
Kotlin 1.7.0以降、Kotlin Multiplatform Gradleプラグインは、デフォルトでKotlin/Native用の埋め込み可能なコンパイラjarを使用します。この機能は1.6.0で実験的として発表されましたが、今回安定版となり利用可能になりました。
この改善は、コンパイラプラグインの開発体験を向上させるため、ライブラリ作者にとって非常に便利です。このリリース以前は、Kotlin/Native用に個別のアーティファクトを提供する必要がありましたが、今ではNativeと他のサポートされているプラットフォームで同じコンパイラプラグインアーティファクトを使用できます。
スタンドアロンAndroid実行可能ファイルへの対応
Kotlin 1.7.0では、Android Nativeターゲット用の標準実行可能ファイルを生成するための完全なサポートが提供されます。1.6.20で導入され、現在デフォルトで有効になっています。
Kotlin/Nativeが共有ライブラリを生成していた以前の動作に戻したい場合は、以下の設定を使用してください。
binaryOptions["androidProgramType"] = "nativeActivity"
Swiftのasync/awaitとの相互運用: KotlinUnit
ではなくVoid
を返す
Kotlinのsuspend
関数は、SwiftでKotlinUnit
ではなくVoid
型を返すようになりました。これは、Swiftのasync
/await
との相互運用性が改善された結果です。この機能は1.6.20で導入され、このリリースではデフォルトでこの動作が有効になっています。
これらの関数で適切な型を返すために、もはやkotlin.native.binary.unitSuspendFunctionObjCExport=proper
プロパティを使用する必要はありません。
Objective-Cブリッジを介した未宣言例外の禁止
Swift/Objective-CコードからKotlinコードを呼び出す場合(またはその逆の場合)で、このコードが例外をスローするときは、適切な変換(例えば@Throws
アノテーションを使用)で言語間の例外転送を特に許可しない限り、例外が発生したコードで処理されるべきです。
以前は、Kotlinには意図しない動作があり、未宣言の例外が場合によってはある言語から別の言語に「漏れる」可能性がありました。Kotlin 1.7.0ではその問題が修正され、現在ではそのようなケースはプログラムの終了につながります。
したがって、例えば、Kotlinで{ throw Exception() }
ラムダがあり、それをSwiftから呼び出す場合、Kotlin 1.7.0では例外がSwiftコードに到達するとすぐにプログラムが終了します。以前のKotlinバージョンでは、そのような例外がSwiftコードに漏れる可能性がありました。
@Throws
アノテーションは以前と同様に動作します。
CocoaPods連携の改善
Kotlin 1.7.0以降、プロジェクトでCocoaPodsを連携させたい場合、cocoapods-generate
プラグインをインストールする必要はなくなりました。
以前は、CocoaPodsを使用するために、例えばKotlin Multiplatform MobileプロジェクトでiOSの依存関係を処理するために、CocoaPods依存関係マネージャーとcocoapods-generate
プラグインの両方をインストールする必要がありました。
CocoaPodsの連携設定が簡単になり、Ruby 3以降でcocoapods-generate
がインストールできない問題を解決しました。Apple M1でより良く動作する最新のRubyバージョンもサポートされています。
CocoaPodsの初期連携の方法をご覧ください。
Kotlin/NativeコンパイラのダウンロードURLの上書き
Kotlin 1.7.0以降、Kotlin/NativeコンパイラのダウンロードURLをカスタマイズできるようになりました。これは、CIで外部リンクが禁止されている場合に役立ちます。
デフォルトのベースURLhttps://download.jetbrains.com/kotlin/native/builds
を上書きするには、以下のGradleプロパティを使用します。
kotlin.native.distribution.baseDownloadUrl=https://example.com
NOTE
ダウンローダーは、実際のコンパイラディストリビューションをダウンロードするために、このベースURLにネイティブバージョンとターゲットOSを追加します。
Kotlin/JS
Kotlin/JSは、JS IRコンパイラバックエンドのさらなる改善と、開発体験を向上させるその他の更新を受けています。
- 新しいIRバックエンドのパフォーマンス向上
- IR使用時のメンバー名のミニファイ
- IRバックエンドでのポリフィルによる古いブラウザのサポート
- js式からのJavaScriptモジュールの動的ロード
- JavaScriptテストランナーの環境変数を指定
新しいIRバックエンドのパフォーマンス向上
このリリースには、開発体験を向上させるためのいくつかの主要な更新が含まれています。
- Kotlin/JSのインクリメンタルコンパイルのパフォーマンスが大幅に改善されました。JSプロジェクトのビルド時間が短縮されます。インクリメンタルリビルドは、多くの場合、レガシーバックエンドと同等の速度になりました。
- Kotlin/JSの最終バンドルは、最終成果物のサイズを大幅に削減したため、より少ないディスクスペースで済みます。一部の大規模プロジェクトでは、レガシーバックエンドと比較して、本番バンドルサイズが最大20%削減されたと計測されています。
- インターフェースの型チェックが桁違いに改善されました。
- Kotlinはより高品質なJSコードを生成します。
IR使用時のメンバー名のミニファイ
Kotlin/JS IRコンパイラは、Kotlinのクラスと関数の関係に関する内部情報を使用して、関数、プロパティ、クラスの名前を短縮するより効率的なミニファイを適用するようになりました。これにより、結果として生成されるバンドルアプリケーションのサイズが縮小されます。
この種類のミニファイは、Kotlin/JSアプリケーションを本番モードでビルドする際に自動的に適用され、デフォルトで有効になっています。メンバー名のミニファイを無効にするには、-Xir-minimized-member-names
コンパイラフラグを使用します。
kotlin {
js(IR) {
compilations.all {
compileKotlinTask.kotlinOptions.freeCompilerArgs += listOf("-Xir-minimized-member-names=false")
}
}
}
IRバックエンドでのポリフィルによる古いブラウザのサポート
Kotlin/JS用のIRコンパイラバックエンドは、レガシーバックエンドと同じポリフィルを含むようになりました。これにより、新しいコンパイラでコンパイルされたコードは、Kotlin標準ライブラリが使用するES2015のすべてのメソッドをサポートしていない古いブラウザでも実行できます。プロジェクトで実際に使用されるポリフィルのみが最終バンドルに含まれるため、バンドルサイズへの潜在的な影響が最小限に抑えられます。
この機能は、IRコンパイラを使用する場合にデフォルトで有効になっており、設定する必要はありません。
js式からのJavaScriptモジュールの動的ロード
JavaScriptモジュールを扱う際、ほとんどのアプリケーションは静的インポートを使用しており、その使用法はJavaScriptモジュール連携でカバーされています。しかし、Kotlin/JSには、アプリケーション内でJavaScriptモジュールをランタイム時に動的にロードするメカニズムが不足していました。
Kotlin 1.7.0以降、JavaScriptのimport
ステートメントがjs
ブロックでサポートされ、ランタイム時にパッケージをアプリケーションに動的に取り込むことが可能になりました。
val myPackage = js("import('my-package')")
JavaScriptテストランナーの環境変数を指定
Node.jsのパッケージ解決を調整したり、外部情報をNode.jsテストに渡したりするために、JavaScriptテストランナーが使用する環境変数を指定できるようになりました。環境変数を定義するには、ビルドスクリプトのtestTask
ブロック内でキーと値のペアを指定してenvironment()
関数を使用します。
kotlin {
js {
nodejs {
testTask {
environment("key", "value")
}
}
}
}
標準ライブラリ
Kotlin 1.7.0では、標準ライブラリにさまざまな変更と改善が加えられました。これらには、新しい機能の導入、実験的な機能の安定化、Native、JS、JVM向けの名前付きキャプチャグループのサポートの統合が含まれます。
- min()およびmax()コレクション関数が非NULL型を返すように
- 特定のインデックスでの正規表現マッチング
- 以前の言語およびAPIバージョンの拡張サポート
- リフレクションによるアノテーションへのアクセス
- 安定版のディープ再帰関数
- デフォルトのタイムソースに対するインラインクラスに基づくタイムマーク
- Java Optional向けの新しい実験的拡張関数
- JSおよびNativeにおける名前付きキャプチャグループのサポート
min()およびmax()コレクション関数が非NULL型を返すように
Kotlin 1.4.0では、min()
およびmax()
コレクション関数をminOrNull()
およびmaxOrNull()
に改名しました。これらの新しい名前は、レシーバコレクションが空の場合にnullを返すという動作をよりよく反映しています。また、KotlinコレクションAPI全体で使用されている命名規則と関数の動作を合わせるのにも役立ちました。
同様に、minBy()
、maxBy()
、minWith()
、maxWith()
もKotlin 1.4.0で*OrNull()の同義語が導入されました。この変更の影響を受けた古い関数は段階的に非推奨になりました。
Kotlin 1.7.0では、元の関数名が再導入されましたが、非NULL戻り値型となりました。新しいmin()
、max()
、minBy()
、maxBy()
、minWith()
、maxWith()
関数は、コレクション要素を厳密に返すか、例外をスローするようになりました。
fun main() {
val numbers = listOf<Int>()
println(numbers.maxOrNull()) // "null"
println(numbers.max()) // "Exception in... Collection is empty."
}
特定のインデックスでの正規表現マッチング
1.5.30で導入された Regex.matchAt()
およびRegex.matchesAt()
関数は、安定版になりました。これらは、正規表現がString
またはCharSequence
の特定の場所で正確な一致を持つかどうかをチェックする方法を提供します。
matchesAt()
は一致をチェックし、真偽値を返します。
fun main() {
val releaseText = "Kotlin 1.7.0 is on its way!"
// regular expression: one digit, dot, one digit, dot, one or more digits
val versionRegex = "\\d[.]\\d[.]\\d+".toRegex()
println(versionRegex.matchesAt(releaseText, 0)) // "false"
println(versionRegex.matchesAt(releaseText, 7)) // "true"
}
matchAt()
は、一致が見つかればそれを返し、そうでなければnull
を返します。
fun main() {
val releaseText = "Kotlin 1.7.0 is on its way!"
val versionRegex = "\\d[.]\\d[.]\\d+".toRegex()
println(versionRegex.matchAt(releaseText, 0)) // "null"
println(versionRegex.matchAt(releaseText, 7)?.value) // "1.7.0"
}
このYouTrackの課題でフィードバックをいただければ幸いです。
以前の言語およびAPIバージョンの拡張サポート
広範囲の以前のKotlinバージョンで利用可能なライブラリを開発するライブラリ作者をサポートし、Kotlinの主要リリースの頻度増加に対応するため、以前の言語およびAPIバージョンのサポートを拡張しました。
Kotlin 1.7.0では、2つではなく3つの以前の言語およびAPIバージョンをサポートします。これにより、Kotlin 1.7.0はKotlin 1.4.0までのバージョンをターゲットとするライブラリの開発をサポートします。後方互換性の詳細については、互換性モードをご覧ください。
リフレクションによるアノテーションへのアクセス
KAnnotatedElement.findAnnotations()
拡張関数は、1.6.0で初めて導入されましたが、今回安定版になりました。このリフレクション関数は、個別に適用されたアノテーションや繰り返し適用されたアノテーションを含む、指定された型のアノテーションをすべて要素上で返します。
@Repeatable
annotation class Tag(val name: String)
@Tag("First Tag")
@Tag("Second Tag")
fun taggedFunction() {
println("I'm a tagged function!")
}
fun main() {
val x = ::taggedFunction
val foo = x as KAnnotatedElement
println(foo.findAnnotations<Tag>()) // [@Tag(name=First Tag), @Tag(name=Second Tag)]
}
安定版のディープ再帰関数
ディープ再帰関数は、Kotlin 1.4.0以来実験的機能として利用可能でしたが、Kotlin 1.7.0で安定版になりました。DeepRecursiveFunction
を使用すると、実際の呼び出しスタックの代わりにヒープにスタックを保持する関数を定義できます。これにより、非常に深い再帰計算を実行できます。ディープ再帰関数を呼び出すには、それをinvoke
します。
この例では、ディープ再帰関数を使用して二分木の深さを再帰的に計算します。このサンプル関数は100,000回再帰的に自身を呼び出しますが、StackOverflowError
はスローされません。
class Tree(val left: Tree?, val right: Tree?)
val calculateDepth = DeepRecursiveFunction<Tree?, Int> { t ->
if (t == null) 0 else maxOf(
callRecursive(t.left),
callRecursive(t.right)
) + 1
}
fun main() {
// Generate a tree with a depth of 100_000
val deepTree = generateSequence(Tree(null, null)) { prev ->
Tree(prev, null)
}.take(100_000).last()
println(calculateDepth(deepTree)) // 100000
}
再帰の深さが1000回を超えるようなコードでは、ディープ再帰関数の使用を検討してください。
デフォルトのタイムソースに対するインラインクラスに基づくタイムマーク
Kotlin 1.7.0では、TimeSource.Monotonic
によって返されるタイムマークをインライン値クラスに変更することで、時間計測機能のパフォーマンスが向上します。これにより、markNow()
、elapsedNow()
、measureTime()
、measureTimedValue()
のような関数を呼び出す際に、それらのTimeMark
インスタンスのラッパークラスが割り当てられなくなります。特にホットパスの一部であるコードを計測する場合、これにより計測のパフォーマンスへの影響を最小限に抑えることができます。
@OptIn(ExperimentalTime::class)
fun main() {
val mark = TimeSource.Monotonic.markNow() // Returned `TimeMark` is inline class
val elapsedDuration = mark.elapsedNow()
}
NOTE
この最適化は、TimeMark
が取得されるタイムソースが静的にTimeSource.Monotonic
であることが判明している場合にのみ利用可能です。
Java Optional向けの新しい実験的拡張関数
Kotlin 1.7.0には、JavaのOptional
クラスを扱う際に便利な新しい関数が導入されます。これらの新しい関数は、JVM上のOptionalオブジェクトをアンラップしたり変換したりするのに使用でき、Java APIをより簡潔に扱えるようになります。
getOrNull()
、getOrDefault()
、getOrElse()
拡張関数を使用すると、Optional
に値が存在する場合にその値を取得できます。それ以外の場合、それぞれnull
、デフォルト値、または関数によって返された値を取得します。
val presentOptional = Optional.of("I'm here!")
println(presentOptional.getOrNull())
// "I'm here!"
val absentOptional = Optional.empty<String>()
println(absentOptional.getOrNull())
// null
println(absentOptional.getOrDefault("Nobody here!"))
// "Nobody here!"
println(absentOptional.getOrElse {
println("Optional was absent!")
"Default value!"
})
// "Optional was absent!"
// "Default value!"
toList()
、toSet()
、asSequence()
拡張関数は、存在するOptional
の値をリスト、セット、またはシーケンスに変換し、そうでない場合は空のコレクションを返します。toCollection()
拡張関数は、Optional
の値を既存の宛先コレクションに追加します。
val presentOptional = Optional.of("I'm here!")
val absentOptional = Optional.empty<String>()
println(presentOptional.toList() + "," + absentOptional.toList())
// ["I'm here!"], []
println(presentOptional.toSet() + "," + absentOptional.toSet())
// ["I'm here!"], []
val myCollection = mutableListOf<String>()
absentOptional.toCollection(myCollection)
println(myCollection)
// []
presentOptional.toCollection(myCollection)
println(myCollection)
// ["I'm here!"]
val list = listOf(presentOptional, absentOptional).flatMap { it.asSequence() }
println(list)
// ["I'm here!"]
これらの拡張関数は、Kotlin 1.7.0で実験的機能として導入されます。Optional
拡張の詳細については、こちらのKEEPをご覧ください。いつものように、Kotlin課題トラッカーでフィードバックをお待ちしております。
JSおよびNativeにおける名前付きキャプチャグループのサポート
Kotlin 1.7.0以降、名前付きキャプチャグループはJVMだけでなく、JSおよびNativeプラットフォームでもサポートされます。
キャプチャグループに名前を付けるには、正規表現で(?<name>group
)構文を使用します。グループに一致したテキストを取得するには、新しく導入されたMatchGroupCollection.get()
関数を呼び出し、グループ名を渡します。
名前によるマッチしたグループ値の取得
都市の座標をマッチングするこの例を考えてみましょう。正規表現に一致したグループのコレクションを取得するには、groups
を使用します。グループの内容をその番号(インデックス)で取得する場合と、value
を使用してその名前で取得する場合を比較します。
fun main() {
val regex = "\\b(?<city>[A-Za-z\\s]+),\\s(?<state>[A-Z]{2}):\\s(?<areaCode>[0-9]{3})\\b".toRegex()
val input = "Coordinates: Austin, TX: 123"
val match = regex.find(input)!!
println(match.groups["city"]?.value) // "Austin" — by name
println(match.groups[2]?.value) // "TX" — by number
}
名前付き後方参照
グループを後方参照する際に、グループ名を使用することもできるようになりました。後方参照は、以前にキャプチャグループによって一致したのと同じテキストに一致します。これには、正規表現で\k<name>
構文を使用します。
fun backRef() {
val regex = "(?<title>\\w+), yes \\k<title>".toRegex()
val match = regex.find("Do you copy? Sir, yes Sir!")!!
println(match.value) // "Sir, yes Sir"
println(match.groups["title"]?.value) // "Sir"
}
置換式における名前付きグループ
名前付きグループ参照は、置換式とともに使用できます。入力内の指定された正規表現のすべての出現箇所を置換式で置き換えるreplace()
関数と、最初の一致のみを置き換えるreplaceFirst()
関数を考えてみましょう。
置換文字列内の${name}
の出現箇所は、指定された名前のキャプチャグループに対応する部分シーケンスに置き換えられます。グループ参照の置換を名前とインデックスで比較できます。
fun dateReplace() {
val dateRegex = Regex("(?<dd>\\d{2})-(?<mm>\\d{2})-(?<yyyy>\\d{4})")
val input = "Date of birth: 27-04-2022"
println(dateRegex.replace(input, "\${yyyy}-\${mm}-\${dd}")) // "Date of birth: 2022-04-27" — by name
println(dateRegex.replace(input, "\$3-\$2-\$1")) // "Date of birth: 2022-04-27" — by number
}
Gradle
このリリースでは、新しいビルドレポート、Gradleプラグインバリアントのサポート、kaptの新しい統計などが導入されます。
- インクリメンタルコンパイルの新しいアプローチ
- コンパイラのパフォーマンス追跡のための新しいビルドレポート
- GradleおよびAndroid Gradleプラグインの最小サポートバージョンの変更
- Gradleプラグインバリアントのサポート
- Kotlin GradleプラグインAPIの更新
- plugins APIを介したsam-with-receiverプラグインの利用
- コンパイルタスクの変更
- kaptにおける各アノテーションプロセッサによる生成ファイルの新しい統計
- kotlin.compiler.execution.strategyシステムプロパティの非推奨化
- 非推奨オプション、メソッド、プラグインの削除
インクリメンタルコンパイルの新しいアプローチ
DANGER
インクリメンタルコンパイルの新しいアプローチは実験的です。これはいつでも廃止または変更される可能性があります。オプトインが必要です(詳細は下記参照)。評価目的でのみ使用することを推奨しており、YouTrackでフィードバックをいただければ幸いです。
Kotlin 1.7.0では、モジュール間の変更に対するインクリメンタルコンパイルを再設計しました。これにより、依存する非Kotlinモジュール内で行われた変更に対してもインクリメンタルコンパイルがサポートされ、Gradleビルドキャッシュと互換性があります。コンパイル回避のサポートも改善されました。
ビルドキャッシュを使用している場合、または非Kotlin Gradleモジュールで頻繁に変更を行う場合、この新しいアプローチで最も大きなメリットが得られると期待しています。kotlin-gradle-plugin
モジュールにおけるKotlinプロジェクトでの弊社のテストでは、キャッシュヒット後の変更で80%以上の改善が示されています。
この新しいアプローチを試すには、gradle.properties
に以下のオプションを設定してください。
kotlin.incremental.useClasspathSnapshot=true
NOTE
インクリメンタルコンパイルの新しいアプローチは、現在のところGradleビルドシステムにおけるJVMバックエンドでのみ利用可能です。
インクリメンタルコンパイルの新しいアプローチが内部でどのように実装されているかについては、こちらのブログ投稿で詳しく説明されています。
私たちはこの技術を安定化させ、他のバックエンド(例えばJS)やビルドシステムへのサポートを追加することを計画しています。このコンパイルスキームで遭遇したいかなる問題や奇妙な動作についても、YouTrackに報告していただければ幸いです。ありがとうございます!
Kotlinチームは、Ivan Gavrilovic、Hung Nguyen、Cédric Champeau、およびその他の外部貢献者の皆様の協力に深く感謝しています。
Kotlinコンパイラタスクのビルドレポート
DANGER
Kotlinビルドレポートは実験的です。これらはいつでも廃止または変更される可能性があります。オプトインが必要です(詳細は下記参照)。評価目的でのみ使用してください。YouTrackでフィードバックをいただければ幸いです。
Kotlin 1.7.0では、コンパイラのパフォーマンスを追跡するのに役立つビルドレポートが導入されます。レポートには、異なるコンパイルフェーズの期間と、コンパイルがインクリメンタルにならなかった理由が含まれています。
ビルドレポートは、コンパイラタスクに関する問題を調査したい場合に役立ちます。例えば、以下のようなケースです。
- Gradleビルドに時間がかかりすぎ、パフォーマンス低下の根本原因を理解したい場合。
- 同じプロジェクトのコンパイル時間が異なる場合(数秒で終わることもあれば、数分かかることもある)。
ビルドレポートを有効にするには、gradle.properties
でビルドレポートの出力先を宣言します。
kotlin.build.report.output=file
以下の値(およびその組み合わせ)が利用可能です。
file
はビルドレポートをローカルファイルに保存します。build_scan
はビルドレポートをビルドスキャンのcustom values
セクションに保存します。NOTE
Gradle Enterpriseプラグインは、カスタム値の数とその長さを制限します。大規模なプロジェクトでは、一部の値が失われる可能性があります。
http
はHTTP(S)を使用してビルドレポートを投稿します。POSTメソッドはJSON形式でメトリクスを送信します。データはバージョンによって変更される可能性があります。送信されるデータの現在のバージョンは、Kotlinリポジトリで確認できます。
長時間のコンパイルに対するビルドレポートの分析が解決に役立つ一般的なケースが2つあります。
- ビルドがインクリメンタルではなかった場合。理由を分析し、根本的な問題を修正します。
- ビルドはインクリメンタルであったが、時間がかかりすぎた場合。ソースファイルを再編成してみてください — 大きなファイルを分割する、個々のクラスを別のファイルに保存する、大きなクラスをリファクタリングする、トップレベル関数を別のファイルで宣言する、など。
新しいビルドレポートの詳細については、こちらのブログ投稿をご覧ください。
皆様のインフラストラクチャでビルドレポートを使用してみることを歓迎します。フィードバック、問題の発見、改善の提案などございましたら、お気軽に課題トラッカーまでご報告ください。よろしくお願いいたします!
最小サポートバージョンの引き上げ
Kotlin 1.7.0以降、Gradleの最小サポートバージョンは6.7.1です。Gradleプラグインバリアントと新しいGradle APIをサポートするために、バージョンを引き上げる必要がありました。Gradleプラグインバリアント機能のおかげで、今後は最小サポートバージョンを頻繁に引き上げる必要はなくなるはずです。
また、最小サポートAndroid Gradleプラグインバージョンは現在3.6.4です。
Gradleプラグインバリアントのサポート
Gradle 7.0では、Gradleプラグイン作者向けの新しい機能 — バリアントを持つプラグイン — が導入されました。この機能により、Gradle 7.1より前のバージョンとの互換性を維持しながら、新しいGradle機能のサポートを簡単に追加できるようになります。Gradleでのバリアント選択について詳しく学びましょう。
Gradleプラグインバリアントを使用すると、異なるGradleバージョンに対応する異なるKotlin Gradleプラグインバリアントを出荷できます。目標は、最も古いサポート対象のGradleバージョンに対応するmain
バリアントで基本的なKotlinコンパイルをサポートすることです。各バリアントは、対応するリリースからのGradle機能の実装を持ちます。最新のバリアントは、最も広範なGradle機能セットをサポートします。このアプローチにより、機能が制限された古いGradleバージョンへのサポートを拡張できます。
現在、Kotlin Gradleプラグインには2つのバリアントのみがあります。
- Gradleバージョン6.7.1~6.9.3向けの
main
- Gradleバージョン7.0以降向けの
gradle70
今後のKotlinリリースでは、さらに追加される可能性があります。
ビルドがどのバリアントを使用しているかを確認するには、--info
ログレベルを有効にし、出力でUsing Kotlin Gradle plugin
で始まる文字列(例: Using Kotlin Gradle plugin main variant
)を見つけます。
NOTE
以下は、Gradleでのバリアント選択に関する既知の問題の回避策です。
こちらのYouTrackチケットでフィードバックをお寄せください。
Kotlin GradleプラグインAPIの更新
Kotlin GradleプラグインAPIアーティファクトにいくつかの改善が加えられました。
ユーザーが設定可能な入力を持つKotlin/JVMおよびKotlin/kaptタスクの新しいインターフェースが追加されました。
すべてのKotlinプラグインが継承する新しい
KotlinBasePlugin
インターフェースが追加されました。このインターフェースは、任意のKotlin Gradleプラグイン(JVM、JS、Multiplatform、Native、およびその他のプラットフォーム)が適用されるたびに何らかの設定アクションをトリガーしたい場合に使用します。kotlinproject.plugins.withType<org.jetbrains.kotlin.gradle.plugin.KotlinBasePlugin>() { // Configure your action here }
KotlinBasePlugin
に関するフィードバックは、こちらのYouTrackチケットにお寄せください。Android GradleプラグインがKotlinコンパイルを自身で設定できるようにするための基盤を構築しました。つまり、ビルドにKotlin Android Gradleプラグインを追加する必要がなくなります。Android Gradle Pluginリリースアナウンスをフォローして、追加されたサポートについて学び、試してみてください!
plugins APIを介したsam-with-receiverプラグインの利用
sam-with-receiverコンパイラプラグインが、Gradle plugins DSLを介して利用可能になりました。
plugins {
id("org.jetbrains.kotlin.plugin.sam.with.receiver") version "$kotlin_version"
}
コンパイルタスクの変更
コンパイルタスクは、このリリースで多くの変更を受けました。
- Kotlinコンパイルタスクは、Gradleの
AbstractCompile
タスクを継承しなくなりました。DefaultTask
のみを継承します。 AbstractCompile
タスクにはsourceCompatibility
およびtargetCompatibility
入力がありました。AbstractCompile
タスクが継承されなくなったため、これらの入力はKotlinユーザーのスクリプトでは利用できなくなりました。SourceTask.stableSources
入力は利用できなくなり、sources
入力を使用する必要があります。setSource(...)
メソッドは引き続き利用可能です。- すべてのコンパイルタスクは、コンパイルに必要なライブラリのリストとして
libraries
入力を使用するようになりました。KotlinCompile
タスクには、将来のリリースで削除される非推奨のKotlinプロパティclasspath
がまだあります。 - コンパイルタスクは引き続き
PatternFilterable
インターフェースを実装しており、これによりKotlinソースのフィルタリングが可能です。sourceFilesExtensions
入力は、PatternFilterable
メソッドを使用することに置き換えられ削除されました。 - 非推奨の
Gradle destinationDir: File
出力は、destinationDirectory: DirectoryProperty
出力に置き換えられました。 - Kotlin/Nativeの
AbstractNativeCompile
タスクは、AbstractKotlinCompileTool
基本クラスを継承するようになりました。これは、Kotlin/Nativeビルドツールを他のすべてのツールに統合するための最初のステップです。
こちらのYouTrackチケットでフィードバックをお寄せください。
kaptにおける各アノテーションプロセッサによる生成ファイルの新しい統計
kotlin-kapt
Gradleプラグインは、すでに各プロセッサのパフォーマンス統計を報告しています。Kotlin 1.7.0以降、各アノテーションプロセッサによって生成されたファイルの数に関する統計も報告できるようになりました。
これは、ビルドの一部として未使用のアノテーションプロセッサがあるかどうかを追跡するのに役立ちます。生成されたレポートを使用して、不要なアノテーションプロセッサをトリガーするモジュールを見つけ、それを防ぐためにモジュールを更新することができます。
統計を有効にするには、2つのステップが必要です。
build.gradle.kts
でshowProcessorStats
フラグをtrue
に設定します。kotlinkapt { showProcessorStats = true }
gradle.properties
でkapt.verbose
Gradleプロパティをtrue
に設定します。nonekapt.verbose=true
NOTE
コマンドラインオプションverbose
を介して詳細出力を有効にすることもできます。
統計はinfo
レベルでログに表示されます。Annotation processor stats:
行に続いて、各アノテーションプロセッサの実行時間に関する統計が表示されます。これらの行の後に、Generated files report:
行に続いて、各アノテーションプロセッサによって生成されたファイルの数に関する統計が表示されます。例:
[INFO] Annotation processor stats:
[INFO] org.mapstruct.ap.MappingProcessor: total: 290 ms, init: 1 ms, 3 round(s): 289 ms, 0 ms, 0 ms
[INFO] Generated files report:
[INFO] org.mapstruct.ap.MappingProcessor: total sources: 2, sources per round: 2, 0, 0
こちらのYouTrackチケットでフィードバックをお寄せください。
kotlin.compiler.execution.strategyシステムプロパティの非推奨化
Kotlin 1.6.20では、Kotlinコンパイラの実行戦略を定義するための新しいプロパティが導入されました。Kotlin 1.7.0では、新しいプロパティを優先して、古いシステムプロパティkotlin.compiler.execution.strategy
の非推奨化サイクルが開始されました。
kotlin.compiler.execution.strategy
システムプロパティを使用すると、警告が表示されます。このプロパティは将来のリリースで削除されます。以前の動作を維持するには、システムプロパティを同名のGradleプロパティに置き換えてください。これはgradle.properties
で行うことができます。例:
kotlin.compiler.execution.strategy=out-of-process
コンパイルタスクプロパティcompilerExecutionStrategy
も使用できます。これについては、Gradleページで詳しく学ぶことができます。
非推奨オプション、メソッド、プラグインの削除
useExperimentalAnnotationメソッドの削除
Kotlin 1.7.0では、useExperimentalAnnotation
Gradleメソッドの非推奨化サイクルが完了しました。モジュールでAPIの使用をオプトインするには、代わりにoptIn()
を使用してください。
例えば、Gradleモジュールがマルチプラットフォームの場合:
sourceSets {
all {
languageSettings.optIn("org.mylibrary.OptInAnnotation")
}
}
Kotlinのオプトイン要件について詳しく学びましょう。
非推奨コンパイラオプションの削除
いくつかのコンパイラオプションの非推奨化サイクルが完了しました。
kotlinOptions.jdkHome
コンパイラオプションは1.5.30で非推奨となり、現在のリリースで削除されました。このオプションを含むGradleビルドは失敗するようになりました。Kotlin 1.5.30以降サポートされているJavaツールチェーンの使用を推奨します。- 非推奨の
noStdlib
コンパイラオプションも削除されました。Gradleプラグインは、kotlin.stdlib.default.dependency=true
プロパティを使用してKotlin標準ライブラリが存在するかどうかを制御します。
NOTE
コンパイラ引数-jdkHome
および-no-stdlib
は引き続き利用可能です。
非推奨プラグインの削除
Kotlin 1.4.0でkotlin2js
およびkotlin-dce-plugin
プラグインは非推奨となり、このリリースで削除されました。kotlin2js
の代わりに、新しいorg.jetbrains.kotlin.js
プラグインを使用してください。デッドコード除去(DCE)は、Kotlin/JS Gradleプラグインが適切に設定されている場合に動作します。
Kotlin 1.6.0で、KotlinGradleSubplugin
クラスの非推奨レベルをERROR
に変更しました。開発者はこのクラスをコンパイラプラグインの記述に使用していました。このリリースでは、このクラスが削除されました。代わりにKotlinCompilerPluginSupportPlugin
クラスを使用してください。
TIP
ベストプラクティスは、プロジェクト全体でKotlinプラグインのバージョン1.7.0以降を使用することです。
非推奨のコルーチンDSLオプションとプロパティの削除
非推奨のkotlin.experimental.coroutines
Gradle DSLオプションと、gradle.properties
で使用されていたkotlin.coroutines
プロパティを削除しました。これからは、単に_中断関数_を使用するか、ビルドスクリプトにkotlinx.coroutines
の依存関係を追加するだけで済みます。
コルーチンに関する詳細については、コルーチンガイドをご覧ください。
ツールチェーン拡張メソッドにおける型キャストの削除
Kotlin 1.7.0より前は、Kotlin DSLでGradleツールチェーンを設定する際に、JavaToolchainSpec
クラスへの型キャストを行う必要がありました。
kotlin {
jvmToolchain {
(this as JavaToolchainSpec).languageVersion.set(JavaLanguageVersion.of(<MAJOR_JDK_VERSION>)
}
}
今では、(this as JavaToolchainSpec)
の部分を省略できます。
kotlin {
jvmToolchain {
languageVersion.set(JavaLanguageVersion.of(<MAJOR_JDK_VERSION>)
}
}
Kotlin 1.7.0への移行
Kotlin 1.7.0をインストール
IntelliJ IDEA 2022.1およびAndroid Studio Chipmunk (212)は、Kotlinプラグインを1.7.0に自動的に更新することを推奨します。
NOTE
IntelliJ IDEA 2022.2、Android Studio Dolphin (213)、またはAndroid Studio Electric Eel (221)の場合、Kotlinプラグイン1.7.0は今後のIntelliJ IDEAおよびAndroid Studioのアップデートとともに提供されます。
新しいコマンドラインコンパイラは、GitHubのリリースページからダウンロードできます。
既存プロジェクトの移行またはKotlin 1.7.0での新規プロジェクトの開始
既存のプロジェクトをKotlin 1.7.0に移行するには、Kotlinのバージョンを
1.7.0
に変更し、GradleまたはMavenプロジェクトを再インポートします。Kotlin 1.7.0への更新方法をご覧ください。Kotlin 1.7.0で新しいプロジェクトを開始するには、Kotlinプラグインを更新し、File | New | Projectからプロジェクトウィザードを実行します。
Kotlin 1.7.0の互換性ガイド
Kotlin 1.7.0は機能リリースであるため、以前の言語バージョンで書かれたコードと互換性のない変更をもたらす可能性があります。そのような変更の詳細なリストは、Kotlin 1.7.0の互換性ガイドで確認できます。