Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
コードで見るKotlin 1.3
Search
Kohei Yamato
November 07, 2018
Programming
1
2.4k
コードで見るKotlin 1.3
Kohei Yamato
November 07, 2018
Tweet
Share
More Decks by Kohei Yamato
See All by Kohei Yamato
新卒一年目でサーバーサイド開発あるあるを踏み抜いてきた話 / Developers Boost 2019 A-7
daiwahome
4
1.9k
Other Decks in Programming
See All in Programming
Zendeskのチケットを Amazon Bedrockで 解析した
ryokosuge
3
210
個人軟體時代
ethanhuang13
0
260
tool ディレクティブを導入してみた感想
sgash708
1
160
為你自己學 Python - 冷知識篇
eddie
1
300
モバイルアプリからWebへの横展開を加速した話_Claude_Code_実践術.pdf
kazuyasakamoto
0
290
🔨 小さなビルドシステムを作る
momeemt
2
620
JSONataを使ってみよう Step Functionsが楽しくなる実践テクニック #devio2025
dafujii
0
150
デザインシステムが必須の時代に
yosuke_furukawa
PRO
2
130
学習を成果に繋げるための個人開発の考え方 〜 「学習のための個人開発」のすすめ / personal project for leaning
panda_program
1
110
AI OCR API on Lambdaを Datadogで可視化してみた
nealle
0
220
Kiroの仕様駆動開発から見えてきたAIコーディングとの正しい付き合い方
clshinji
1
180
Google I/O recap web編 大分Web祭り2025
kponda
0
2.9k
Featured
See All Featured
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
PRO
185
54k
Git: the NoSQL Database
bkeepers
PRO
431
65k
The World Runs on Bad Software
bkeepers
PRO
70
11k
Build The Right Thing And Hit Your Dates
maggiecrowley
37
2.8k
[Rails World 2023 - Day 1 Closing Keynote] - The Magic of Rails
eileencodes
36
2.5k
RailsConf 2023
tenderlove
30
1.2k
Fantastic passwords and where to find them - at NoRuKo
philnash
52
3.4k
Designing Experiences People Love
moore
142
24k
Large-scale JavaScript Application Architecture
addyosmani
512
110k
Done Done
chrislema
185
16k
Faster Mobile Websites
deanohume
309
31k
Product Roadmaps are Hard
iamctodd
PRO
54
11k
Transcript
コードで見る Kotlin 1.3 どこでもKotlin #6 エムスリー株式会社 大和康平
自己紹介 • 大和 康平 (24) • エムスリー 2018年4月入社 • 仕事の担当:
サーバーサイド • 趣味: モータースポーツ観戦
発表の概要 • 基本的にはこちらの内容 ◦ What's New in Kotlin 1.3 (https://kotl.in/1.3)
• この中から3つをピックアップして紹介 ◦ Coroutines (ごく一部) ◦ Inline Classes ◦ Standard Libraries
Kotlin 1.3 リリース
Kotlin 1.3 事始め コマンドラインの場合: Gradleの場合: $ brew install kotlin plugins
{ id 'org.jetbrains.kotlin.jvm' version '1.3.0' }
Coroutines
Coroutines • 基本は軽量なスレッド • CoroutineScope 中の coroutine builder により起動する ◦
launch ◦ runBlocking ◦ async
Coroutines dependencies { implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.0.0' } coroutine の実行に必要
GrobalScope fun main() { GlobalScope.launch { delay(1000L) println("World!") } println("Hello,")
Thread.sleep(2000L) }
GrobalScope fun main() { GlobalScope.launch { delay(1000L) println("World!") } println("Hello,")
Thread.sleep(2000L) } GlobalScope の coroutine
GrobalScope • CoroutineScope の一種 • ライフタイム: アプリケーション終了時まで
launch coroutine builder • 現在のスレッドをブロックせずに、新しい coroutine を起動 する • Coroutine
への参照を Job として返す (後述)
launch coroutine builder fun main() { GlobalScope.launch { delay(1000L) println("World!")
} println("Hello,") Thread.sleep(2000L) }
launch coroutine builder fun main() { GlobalScope.launch { delay(1000L) println("World!")
} println("Hello,") Thread.sleep(2000L) } メインスレッドをブロックしない が1000ms停止
launch coroutine builder fun main() { GlobalScope.launch { delay(1000L) println("World!")
} println("Hello,") Thread.sleep(2000L) } 先に実行される
launch coroutine builder fun main() { GlobalScope.launch { delay(1000L) println("World!")
} println("Hello,") Thread.sleep(2000L) } => Hello, World!
launch coroutine builder fun main() { GlobalScope.launch { delay(1000L) println("World!")
} println("Hello,") Thread.sleep(2000L) } => Hello, World! 2000ms停止することで待 ち合わせ
launch coroutine builder fun main() { GlobalScope.launch { delay(1000L) println("World!")
} println("Hello,") } => Hello, 実行される前に終了
Job fun main() { GlobalScope.launch { delay(1000L) println("World!") } println("Hello,")
Thread.sleep(2000L) } coroutineの内容によらず 2000ms停止......
Job fun main() { val job = GlobalScope.launch { delay(1000L)
println("World!") } println("Hello,") job.join() }
Job • launch coroutine builder の返り値 • いくつかの状態を持つ ◦ New,
Active, Completing, Cancelling, Cancelled, Completed • Job#join を実行することにより、完了するまで呼び出し元 の coroutine を停止できる
Job fun main() { val job = GlobalScope.launch { delay(1000L)
println("World!") } println("Hello,") job.join() } coroutineが完了するまで待ち合わせ
Job fun main() { val job = GlobalScope.launch { delay(1000L)
println("World!") } println("Hello,") job.join() } => Hello, World!
runBlocking coroutine builder • 現在のスレッドをブロックして、新しい coroutine を起動する • コードブロックの返り値をそのまま返す
runBlocking coroutine builder fun main() { val job = GlobalScope.launch
{ delay(1000L) println("World!") } println("Hello,") job.join() }
runBlocking coroutine builder fun main() { runBlocking { delay(1000L) println("World!")
} println("Hello,") }
runBlocking coroutine builder fun main() { runBlocking { delay(1000L) println("World!")
} println("Hello,") } 完了するまでメインスレッドをブ ロック
runBlocking coroutine builder fun main() { runBlocking { delay(1000L) println("World!")
} println("Hello,") } => World! (約1秒後) Hello,
CoroutineScope fun main() { val job = GlobalScope.launch { delay(1000L)
println("World!") } println("Hello,") job.join() }
CoroutineScope fun main() = runBlocking { val job = GlobalScope.launch
{ delay(1000L) println("World!") } println("Hello,") job.join() }
CoroutineScope fun main() = runBlocking { launch { delay(1000L) println("World!")
} println("Hello,") }
CoroutineScope fun main() = runBlocking { // this: CoroutineScope launch
{ delay(1000L) println("World!") } println("Hello,") }
CoroutineScope • 全ての coroutine builder は、そのコードブロックのスコープ に CroutineScope のインスタンスを追加する •
外のコルーチンは、スコープ中で起動されたコルーチンが全 て終了するまで完了しない
CoroutineScope fun main() = runBlocking { launch { delay(1000L) println("World!")
} println("Hello,") } => Hello, World! coroutine が完了するまで アプリケーションは終了しない
async coroutine builder • 現在のスレッドをブロックせずに、新しい coroutine を起動 する ◦ launch
と同じ • 将来の実行結果を Deferred として返す
async coroutine builder fun main() = runBlocking { val x
= async { delay(1000L) 10 } println(x.await()) }
async coroutine builder fun main() = runBlocking { val x
= async { delay(1000L) 10 } println(x.await()) } async による coroutine
async coroutine builder fun main() = runBlocking { val x
= async { delay(1000L) 10 } println(x.await()) } coroutine の完了まで待つ
async coroutine builder fun main() = runBlocking { val x
= async { delay(1000L) 10 } println(x.await()) } => 10 (約1秒後)
async coroutine builder fun main() = runBlocking { val x
= async { delay(1000L); 10 } val y = async { delay(2000L); 20 } println(x.await() + y.await()) }
async coroutine builder fun main() = runBlocking { val x
= async { delay(1000L); 10 } val y = async { delay(2000L); 20 } println(x.await() + y.await()) }
async coroutine builder fun main() = runBlocking { val x
= async { delay(1000L); 10 } val y = async { delay(2000L); 20 } println(x.await() + y.await()) }
async coroutine builder fun main() = runBlocking { val x
= async { delay(1000L); 10 } val y = async { delay(2000L); 20 } println(x.await() + y.await()) } 最大2000ms停止
async coroutine builder fun main() = runBlocking { val x
= async { delay(1000L); 10 } val y = async { delay(2000L); 20 } println(x.await() + y.await()) } => 30 (約2秒後)
async coroutine builder fun main() = runBlocking { val time
= measureTimeMillis { val x = async { delay(1000L); 10 } val y = async { delay(2000L); 20 } println(x.await() + y.await()) } println("$time ms") } => 30 2033 ms 時間計測しても約2000ms
Coroutines まとめ • Coroutine builder を使用して作成する ◦ launch ◦ runBlocking
◦ async • 階層構造を持たせて実行するとよい
Inline Classes [experimental]
Inline Classes • コンパイル時にオーバーヘッドが少ない形で展開されるクラ ス • プライマリコンストラクタで、プロパティを1つのみ宣言できる
プライマリコンストラクタのみ inline class Password(val value: String) fun main() { val
securePassword = Password("Don't try this in production") println(securePassword.value) }
プライマリコンストラクタのみ inline class Password(val value: String) fun main() { val
securePassword = Password("Don't try this in production") println(securePassword.value) } プロパティを1つ持つ Inline Class
プライマリコンストラクタのみ inline class Password(val value: String) fun main() { val
securePassword = Password("Don't try this in production") println(securePassword.value) } 通常の Class として利用できる
プライマリコンストラクタのみ (decompiled) public static final void main() { String securePassword
= Password.constructor-impl("Don't try this in production"); System.out.println(securePassword); } Java に逆コンパイルした main 関数
プライマリコンストラクタのみ (decompiled) public static final void main() { String securePassword
= Password.constructor-impl("Don't try this in production"); System.out.println(securePassword); } プロパティの型が返る
プライマリコンストラクタのみ (decompiled) public static final void main() { String securePassword
= Password.constructor-impl("Don't try this in production"); System.out.println(securePassword); } static method として実行される
プライマリコンストラクタのみ (decompiled) public final class Password { @NotNull public static
String constructor_impl/* $FF was: constructor-impl*/(@NotNull String value) { Intrinsics.checkParameterIsNotNull(value, "value"); return value; } } 逆コンパイルした Inline class
プライマリコンストラクタのみ (decompiled) public final class Password { @NotNull public static
String constructor_impl/* $FF was: constructor-impl*/(@NotNull String value) { Intrinsics.checkParameterIsNotNull(value, "value"); return value; } } 引数をそのまま返す
プロパティ&メソッド inline class Name(val s: String) { val length: Int
get() = s.length fun greet() { println("Hello, $s") } } fun main() { val name = Name("Kotlin") name.greet() println(name.length) }
プロパティ&メソッド inline class Name(val s: String) { val length: Int
get() = s.length fun greet() { println("Hello, $s") } } fun main() { val name = Name("Kotlin") name.greet() println(name.length) } 引数は1つのみ
プロパティ&メソッド inline class Name(val s: String) { val length: Int
get() = s.length fun greet() { println("Hello, $s") } } fun main() { val name = Name("Kotlin") name.greet() println(name.length) }
プロパティ&メソッド inline class Name(val s: String) { val length: Int
get() = s.length fun greet() { println("Hello, $s") } } fun main() { val name = Name("Kotlin") name.greet() println(name.length) } それぞれ単純な処理
プロパティ&メソッド (decompiled) public static final void main() { String name
= Name.constructor-impl("Kotlin"); Name.greet-impl(name); int var1 = Name.getLength-impl(name); System.out.println(var1); }
プロパティ&メソッド (decompiled) public static final void main() { String name
= Name.constructor-impl("Kotlin"); Name.greet-impl(name); int var1 = Name.getLength-impl(name); System.out.println(var1); } static method で String を返す
プロパティ&メソッド (decompiled) public static final void main() { String name
= Name.constructor-impl("Kotlin"); Name.greet-impl(name); int var1 = Name.getLength-impl(name); System.out.println(var1); } コンストラクタと同様に static method が呼ばれる
プロパティ&メソッド (decompiled) public final class Name { public static final
int getLength_impl/* $FF was: getLength-impl*/(String $this) { return $this.length(); } public static final void greet_impl/* $FF was: greet-impl*/(String $this) { String var1 = "Hello, " + $this; System.out.println(var1); } }
プロパティ&メソッド (decompiled) public final class Name { public static final
int getLength_impl/* $FF was: getLength-impl*/(String $this) { return $this.length(); } public static final void greet_impl/* $FF was: greet-impl*/(String $this) { String var1 = "Hello, " + $this; System.out.println(var1); } } length() を呼び出すだけ
プロパティ&メソッド (decompiled) public final class Name { public static final
int getLength_impl/* $FF was: getLength-impl*/(String $this) { return $this.length(); } public static final void greet_impl/* $FF was: greet-impl*/(String $this) { String var1 = "Hello, " + $this; System.out.println(var1); } } String を結合して出力
Inline Classes まとめ • コンパイル時に static method として展開される • いくつかの制約がある
◦ プライマリコンストラクタのプロパティは1つ ◦ init 文を持てない, class を持てない, etc. • Experimental: 変更される可能性あり
Standard Libraries
Random マルチプラットフォームで利用可能な Random が追加 val number = Random.nextInt(42) println(number) //
0 <= number < 42
Random マルチプラットフォームで利用可能な Random が追加 val number = Random(111).nextInt(42) println(number) //
0 <= number < 42 seed も指定可能
Random IntRange 等の拡張関数も追加されている val number = (0..41).random() println(number) // 0
<= number <= 41
isNullOrEmpty / orEmpty Collection, Map, Array に追加で導入 fun main() {
val s: String? = null if (!s.isNullOrEmpty()) { println(s.length) } }
isNullOrEmpty / orEmpty Contracts によりスマートキャストできる fun main() { val s:
String? = null if (!s.isNullOrEmpty()) { println(s.length) } } スマートキャスト
isNullOrEmpty / orEmpty Contracts によりスマートキャストできる @kotlin.internal.InlineOnly public inline fun CharSequence?.isNullOrEmpty():
Boolean { contract { return(false) implies (this@isNullOrEmpty != null) } return random(Random) }
Array.copyInto 別の Array に要素をコピー可能に val source = "kotlin".toCharArray() val target
= "java".toCharArray() source.copyInto(target, endIndex = target.size) println(target) // kotl
Array.copyInto 別の Array に要素をコピー可能に val source = "kotlin".toCharArray() val target
= "java".toCharArray() source.copyInto(target, endIndex = target.size) println(target) // kotl インデックスを適切に設定しないと ArrayIndexOutOfBoundsException
associateWith キーのリストから値を関連付けてマップを作成可能 val keys = 'a'..'c' val map = keys.associateWith
{ it.toString().repeat(5).capitalize() } map.forEach { println(it) } // a=Aaaaa // b=Bbbbb // c=Ccccc
associateWith キーのリストから値を関連付けてマップを作成可能 val keys = 'a'..'c' val map = keys.associateWith
{ it.toString().repeat(5).capitalize() } map.forEach { println(it) } // a=Aaaaa // b=Bbbbb // c=Ccccc キーに対する値を設定
associateWith キーのリストから値を関連付けてマップを作成可能 val keys = 'a'..'c' val map = keys.associateWith
{ it.toString().repeat(5).capitalize() } map.forEach { println(it) } // a=Aaaaa // b=Bbbbb // c=Ccccc
ifEmpty / ifBlank Collections, Map, Array 等が空の場合の値を指定可能 fun printAllUppercase(data: List<String>)
{ val result = data .filter { it.all { c -> c.isUpperCase() } } .ifEmpty { listOf("<no uppercase>") } result.forEach { println(it) } } printAllUppercase(listOf("foo", "Bar")) // <no uppercase> printAllUppercase(listOf("FOO", "bar")) // FOO
ifEmpty / ifBlank Collections, Map, Array 等が空の場合の値を指定可能 fun printAllUppercase(data: List<String>)
{ val result = data .filter { it.all { c -> c.isUpperCase() } } .ifEmpty { listOf("<no uppercase>") } result.forEach { println(it) } } printAllUppercase(listOf("foo", "Bar")) // <no uppercase> printAllUppercase(listOf("FOO", "bar")) // FOO デフォルト値
ifEmpty / ifBlank Collections, Map, Array 等が空の場合の値を指定可能 fun printAllUppercase(data: List<String>)
{ val result = data .filter { it.all { c -> c.isUpperCase() } } .ifEmpty { listOf("<no uppercase>") } result.forEach { println(it) } } printAllUppercase(listOf("foo", "Bar")) // <no uppercase> printAllUppercase(listOf("FOO", "bar")) // FOO
その他 @SinceKotlin(“1.3”) で検索することで見つけられる @SinceKotlin("1.3") @kotlin.internal.InlineOnly public inline fun IntRange.random(): Int
{ return random(Random) }
まとめ
まとめ • Kotlin 1.3 の新機能についてかいつまんで説明した ◦ Coroutine ◦ Inline Classes
◦ Standard Libraries • Kotlin/Native, Contracts は後続の発表で • Kotlin 1.3 を使ってみよう!
参考 • What's New in Kotlin 1.3 ◦ https://kotl.in/1.3 •
Kotlin Reference ◦ https://kotlinlang.org/docs/reference/coroutines-overview.html ◦ https://kotlinlang.org/docs/reference/inline-classes.html • GitHub ◦ https://github.com/JetBrains/kotlin
Have a nice Kotlin!!