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.2k
コードで見る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.8k
Other Decks in Programming
See All in Programming
情報漏洩させないための設計
kubotak
0
100
フロントエンドのディレクトリ構成どうしてる? Feature-Sliced Design 導入体験談
osakatechlab
8
4.1k
RWC 2024 DICOM & ISO/IEC 2022
m_seki
0
210
コンテナをたくさん詰め込んだシステムとランタイムの変化
makihiro
1
130
php-conference-japan-2024
tasuku43
0
260
命名をリントする
chiroruxx
1
400
MCP with Cloudflare Workers
yusukebe
2
220
Итераторы в Go 1.23: зачем они нужны, как использовать, и насколько они быстрые?
lamodatech
0
750
PHPとAPI Platformで作る本格的なWeb APIアプリケーション(入門編) / phpcon 2024 Intro to API Platform
ttskch
0
210
17年周年のWebアプリケーションにTanStack Queryを導入する / Implementing TanStack Query in a 17th Anniversary Web Application
saitolume
0
250
DevFest Tokyo 2025 - Flutter のアプリアーキテクチャ現在地点
wasabeef
5
900
アクターシステムに頼らずEvent Sourcingする方法について
j5ik2o
4
260
Featured
See All Featured
The Invisible Side of Design
smashingmag
298
50k
個人開発の失敗を避けるイケてる考え方 / tips for indie hackers
panda_program
95
17k
GitHub's CSS Performance
jonrohan
1030
460k
Building a Modern Day E-commerce SEO Strategy
aleyda
38
7k
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
232
17k
Being A Developer After 40
akosma
87
590k
How to Think Like a Performance Engineer
csswizardry
22
1.2k
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
29
2k
The Art of Programming - Codeland 2020
erikaheidi
53
13k
Docker and Python
trallard
42
3.1k
Measuring & Analyzing Core Web Vitals
bluesmoon
4
170
Building Better People: How to give real-time feedback that sticks.
wjessup
365
19k
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!!