Kotlin 1.5.20 の新機能
Kotlin 1.5.20 には、1.5.0 の新機能で発見された問題の修正が含まれており、様々なツール改善も含まれています。
変更点の概要は、リリースブログ記事と以下のビデオで確認できます:
Kotlin/JVM
Kotlin 1.5.20 は JVM プラットフォームで以下のアップデートを受けます:
- invokedynamic による文字列結合
- JSpecify nullness アノテーションのサポート
- Kotlin と Java コードを持つモジュール内での Java の Lombok が生成したメソッド呼び出しのサポート
invokedynamic による文字列結合
Kotlin 1.5.20 は、JVM 9 以降をターゲットとする文字列結合を 動的呼び出し (invokedynamic
) にコンパイルすることで、モダンな Java バージョンに対応します。 より具体的には、文字列結合に StringConcatFactory.makeConcatWithConstants()
を使用します。
以前のバージョンで使用されていた StringBuilder.append()
による結合に戻すには、コンパイラオプション -Xstring-concat=inline
を追加します。
コンパイラオプションの追加方法については、Gradle、Maven、コマンドラインコンパイラを参照してください。
JSpecify nullness アノテーションのサポート
Kotlin コンパイラは、様々な種類のnull可能性アノテーションを読み取って、Java から Kotlin へ null可能性情報を渡すことができます。バージョン 1.5.20 では、Java nullness アノテーションの標準的な統一セットを含む JSpecify プロジェクトのサポートが導入されました。
JSpecify を使用すると、より詳細な null可能性情報を提供し、Kotlin が Java とヌル安全性を相互運用するのに役立ちます。宣言、パッケージ、またはモジュールのスコープのデフォルトの null可能性を設定したり、パラメトリックな null可能性を指定したりすることができます。詳細については、JSpecify ユーザーガイドを参照してください。
Kotlin が JSpecify アノテーションをどのように処理できるかの例を次に示します:
// JavaClass.java
import org.jspecify.nullness.*;
@NullMarked
public class JavaClass {
public String notNullableString() { return ""; }
public @Nullable String nullableString() { return ""; }
}
// Test.kt
fun kotlinFun() = with(JavaClass()) {
notNullableString().length // OK
nullableString().length // Warning: receiver nullability mismatch
}
1.5.20 では、JSpecify が提供する null可能性情報に従ったすべての null可能性の不一致は警告として報告されます。 JSpecify を使用する際に strict モード (エラー報告あり) を有効にするには、コンパイラオプション -Xjspecify-annotations=strict
と -Xtype-enhancement-improvements-strict-mode
を使用します。 JSpecify プロジェクトは活発に開発中であることに注意してください。その API と実装は、いつでも大きく変更される可能性があります。
Kotlin と Java コードを持つモジュール内での Java の Lombok が生成したメソッド呼び出しのサポート
Kotlin 1.5.20 では、実験的な Lombok コンパイラプラグインが導入されました。このプラグインにより、Kotlin と Java コードを持つモジュール内で Java の Lombok 宣言を生成および使用することが可能になります。Lombok アノテーションは Java ソースでのみ機能し、Kotlin コードで使用しても無視されます。
このプラグインは次のアノテーションをサポートしています:
@Getter
、@Setter
@NoArgsConstructor
、@RequiredArgsConstructor
、および@AllArgsConstructor
@Data
@With
@Value
このプラグインの開発は継続しています。現在の詳細な状態については、Lombok コンパイラプラグインの README を参照してください。
現在、@Builder
アノテーションのサポートは計画していません。ただし、YouTrack で @Builder
に投票していただければ、検討することができます。
Kotlin/Native
Kotlin/Native 1.5.20 は、新機能とツール改善のプレビューを提供します:
KDoc コメントを生成された Objective-C ヘッダーへオプトインでエクスポートする機能
DANGER
KDoc コメントを生成された Objective-C ヘッダーへエクスポートする機能は実験的です。
いつでも削除または変更される可能性があります。
オプトインが必要であり (詳細は下記参照)、評価目的でのみ使用してください。
YouTrack でのフィードバックをお待ちしております。
Kotlin/Native コンパイラで、Kotlin コードのドキュメントコメント (KDoc) を、そこから生成される Objective-C フレームワークにエクスポートできるようになり、フレームワークの利用者から見えるようになりました。
例えば、KDoc を含む以下の Kotlin コードは:
/**
* Prints the sum of the arguments.
* Properly handles the case when the sum doesn't fit in 32-bit integer.
*/
fun printSum(a: Int, b: Int) = println(a.toLong() + b)
以下の Objective-C ヘッダーを生成します:
/**
* Prints the sum of the arguments.
* Properly handles the case when the sum doesn't fit in 32-bit integer.
*/
+ (void)printSumA:(int32_t)a b:(int32_t)b __attribute__((swift_name("printSum(a:b:)")));
これは Swift とも良好に連携します。
KDoc コメントを Objective-C ヘッダーにエクスポートするこの機能を試すには、-Xexport-kdoc
コンパイラオプションを使用します。コメントをエクスポートしたい Gradle プロジェクトの build.gradle(.kts)
に以下の行を追加してください:
kotlin {
targets.withType<org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget> {
compilations.get("main").kotlinOptions.freeCompilerArgs += "-Xexport-kdoc"
}
}
kotlin {
targets.withType(org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget) {
compilations.get("main").kotlinOptions.freeCompilerArgs += "-Xexport-kdoc"
}
}
この YouTrack チケットを使用してフィードバックを共有していただけると大変ありがたいです。
コンパイラのバグ修正
Kotlin/Native コンパイラは 1.5.20 で複数のバグ修正を受けました。完全なリストはチェンジログで確認できます。
互換性に影響する重要なバグ修正があります。以前のバージョンでは、不正な UTF サロゲートペアを含む文字列定数は、コンパイル中にその値を失っていました。現在はそのような値も保持されます。アプリケーション開発者は 1.5.20 に安全に更新でき、何も壊れることはありません。ただし、1.5.20 でコンパイルされたライブラリは、以前のコンパイラバージョンとは互換性がありません。 詳細については、この YouTrack イシューを参照してください。
単一配列内での Array.copyInto() のパフォーマンス改善
Array.copyInto()
が、ソースとデスティネーションが同じ配列である場合に機能する方法を改善しました。このユースケースにおけるメモリ管理の最適化により、そのような操作は最大で20倍高速化されます(コピーされるオブジェクトの数によります)。
Kotlin/JS
1.5.20 では、新しい IR ベースのバックエンドである Kotlin/JS へプロジェクトを移行するのに役立つガイドを公開します。
JS IR バックエンド向け移行ガイド
新しい JS IR バックエンド向け移行ガイドは、移行中に遭遇する可能性のある問題を特定し、それらの解決策を提供します。ガイドに記載されていない問題を見つけた場合は、イシュー追跡システムに報告してください。
Gradle
Kotlin 1.5.20 では、Gradle エクスペリエンスを向上させる以下の機能が導入されました:
kapt におけるアノテーションプロセッサのクラスローダーのキャッシュ
DANGER
kapt におけるアノテーションプロセッサのクラスローダーのキャッシュは実験的です。
いつでも削除または変更される可能性があります。評価目的でのみ使用してください。
YouTrack でのフィードバックをお待ちしております。
kapt におけるアノテーションプロセッサのクラスローダーをキャッシュできる、新しい実験的な機能が追加されました。 この機能は、連続した Gradle 実行における kapt の速度を向上させることができます。
この機能を有効にするには、gradle.properties
ファイルに以下のプロパティを使用します:
# positive value will enable caching
# use the same value as the number of modules that use kapt
kapt.classloaders.cache.size=5
# disable for caching to work
kapt.include.compile.classpath=false
kapt について詳しく学ぶ。
kotlin.parallel.tasks.in.project ビルドプロパティの非推奨化
このリリースから、Kotlin の並列コンパイルは Gradle の並列実行フラグ --parallel
によって制御されます。 このフラグを使用すると、Gradle はタスクを並行して実行し、コンパイルタスクの速度を向上させ、リソースをより効率的に活用します。
kotlin.parallel.tasks.in.project
プロパティを使用する必要はなくなりました。このプロパティは非推奨となり、次のメジャーリリースで削除されます。
標準ライブラリ
Kotlin 1.5.20 では、文字を扱ういくつかの関数のプラットフォーム固有の実装が変更され、結果としてプラットフォーム間の統一が図られました:
- Kotlin/Native と Kotlin/JS における Char.digitToInt() のすべての Unicode 数字への対応。
- Char.isLowerCase()/isUpperCase() の実装のプラットフォーム間での統一。
Kotlin/Native と Kotlin/JS における Char.digitToInt() のすべての Unicode 数字への対応
Char.digitToInt()
は、文字が表す10進数字の数値的値を返します。1.5.20 より前は、この関数は Kotlin/JVM に対してのみすべての Unicode 数字文字をサポートしていました。Native および JS プラットフォームの実装は ASCII 数字のみをサポートしていました。
今後は、Kotlin/Native と Kotlin/JS の両方で、任意の Unicode 数字文字に対して Char.digitToInt()
を呼び出し、その数値表現を取得できます。
fun main() {
val ten = '\u0661'.digitToInt() + '\u0039'.digitToInt() // ARABIC-INDIC DIGIT ONE + DIGIT NINE
println(ten)
}
Char.isLowerCase()/isUpperCase() の実装のプラットフォーム間での統一
Char.isUpperCase()
および Char.isLowerCase()
関数は、文字のケースに応じて真偽値を返します。Kotlin/JVM の場合、実装は General_Category
と Other_Uppercase
/Other_Lowercase
の両方の Unicode プロパティをチェックします。
1.5.20 より前は、他のプラットフォームの実装は異なっており、一般的なカテゴリのみを考慮していました。 1.5.20 では、実装がプラットフォーム間で統一され、両方のプロパティを使用して文字のケースを決定するようになりました:
fun main() {
val latinCapitalA = 'A' // has "Lu" general category
val circledLatinCapitalA = 'Ⓐ' // has "Other_Uppercase" property
println(latinCapitalA.isUpperCase() && circledLatinCapitalA.isUpperCase())
}