Deep Dive Kotlin :
du Hello World au ByteCode
Deep Dive Kotlin :
Speakers
Roadmap
Introduction
ByteCode Java ?
Introduction Kotlin
Les bases
null-safety
Les types
Les fonctions
Les lambdas
Les classes
Pause
ByteCode Android
Autres structures
Extensions de fonctions
Les collections
Les delegates
inline
Coroutines
Conclusion
ByteCode Java ?
ByteCode Java ?
javac
HelloWorld.java
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello RivieraDev");
}
}
javac HelloWorld.java
Java ByteCode binary
hexdump -C HelloWorld.class
00000000 ca fe ba be 00 00 00 34 00 1d 0a 00 06 00 0f 09 |.......4........|
00000010 00 10 00 11 08 00 12 0a 00 13 00 14 07 00 15 07 |................|
00000020 00 16 01 00 06 3c 69 6e 69 74 3e 01 00 03 28 29 |.....<init>...()|
00000030 56 01 00 04 43 6f 64 65 01 00 0f 4c 69 6e 65 4e |V...Code...LineN|
00000040 75 6d 62 65 72 54 61 62 6c 65 01 00 04 6d 61 69 |umberTable...mai|
00000050 6e 01 00 16 28 5b 4c 6a 61 76 61 2f 6c 61 6e 67 |n...([Ljava/lang|
00000060 2f 53 74 72 69 6e 67 3b 29 56 01 00 0a 53 6f 75 |/String;)V...Sou|
00000070 72 63 65 46 69 6c 65 01 00 0f 48 65 6c 6c 6f 57 |rceFile...HelloW|
00000080 6f 72 6c 64 2e 6a 61 76 61 0c 00 07 00 08 07 00 |orld.java.......|
00000090 17 0c 00 18 00 19 01 00 0c 48 65 6c 6c 6f 20 44 |.........Hello D|
000000a0 65 76 6f 78 78 07 00 1a 0c 00 1b 00 1c 01 00 19 |evoxx...........|
000000b0 5f 30 30 5f 68 65 6c 6c 6f 77 6f 72 6c 64 2f 48 |_00_helloworld/H|
000000c0 65 6c 6c 6f 57 6f 72 6c 64 01 00 10 6a 61 76 61 |elloWorld...java|
000000d0 2f 6c 61 6e 67 2f 4f 62 6a 65 63 74 01 00 10 6a |/lang/Object...j|
000000e0 61 76 61 2f 6c 61 6e 67 2f 53 79 73 74 65 6d 01 |ava/lang/System.|
000000f0 00 03 6f 75 74 01 00 15 4c 6a 61 76 61 2f 69 6f |..out...Ljava/io|
00000100 2f 50 72 69 6e 74 53 74 72 65 61 6d 3b 01 00 13 |/PrintStream;...|
00000110 6a 61 76 61 2f 69 6f 2f 50 72 69 6e 74 53 74 72 |java/io/PrintStr|
00000120 65 61 6d 01 00 07 70 72 69 6e 74 6c 6e 01 00 15 |eam...println...|
00000130 28 4c 6a 61 76 61 2f 6c 61 6e 67 2f 53 74 72 69 |(Ljava/lang/Stri|
00000140 6e 67 3b 29 56 00 21 00 05 00 06 00 00 00 00 00 |ng;)V.!.........|
00000150 02 00 01 00 07 00 08 00 01 00 09 00 00 00 1d 00 |................|
00000160 01 00 01 00 00 00 05 2a b7 00 01 b1 00 00 00 01 |.......*........|
00000170 00 0a 00 00 00 06 00 01 00 00 00 03 00 09 00 0b |................|
00000180 00 0c 00 01 00 09 00 00 00 25 00 02 00 01 00 00 |.........%......|
00000190 00 09 b2 00 02 12 03 b6 00 04 b1 00 00 00 01 00 |................|
000001a0 0a 00 00 00 0a 00 02 00 00 00 06 00 08 00 07 00 |................|
000001b0 01 00 0d 00 00 00 02 00 0e |.........|
000001b9
Explorons le ByteCode
javap -c HelloWorld.class
Compiled from "HelloWorld.java"
public class _00_helloworld.HelloWorld {
public _00_helloworld.HelloWorld();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #3 // String Hello RivieraDev
5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
}
À propos du ByteCode
- Environ 200 opérations possibles (maxi. 256 opscodes)
-
Préfixe pour le type d'opérations (
i
pour entier,d
pour double, ...) -
Manipulation de la pile, des variables locales (
iconst_0
,istore
,iload
, ...) -
Contrôle du flux des instructions (
if_icmpgt
,goto
, ...) -
Arithmétique et conversion de type (
iadd
,iinc
,i2d
, ...) -
Manipulation d'objets (
invokevirtual
,invokedynamic
, ...) -
Autres (
athrow
, ...)
Jouons un peu
Liens
- Mastering Java Bytecode at the Core of the JVM
- Introduction to Java Bytecode
- The Java® Virtual Machine Specification
- The Java Virtual Machine Instruction Set
- Que se passe-t-il sous le capot ? Exploration au coeur de la JVM (Sylvain Wallez)
- Byte Buddy
- asm
Soyez curieux, regardez comment ça marche avec
javap -c
!
Introduction Kotlin
Introduction Kotlin
Historique
- 2011 - 2015
Dévoilé par JetBrains
- 2016
v1.0
Support annoncé par Spring
- 2017
v1.1 : coroutines, JS, ...
Support par Google
v1.2 : multiplatform
- 2018
v1.3
Coroutine stable
Kotlin Native beta
Kotlin Foundation
- 2019
corountine-flow
v1.4 ?
???
- ...
Cibles
JVM et Android
JavaScript
Native avec LLVM
HelloWorld.kt
fun main() {
println("Hello RivieraDev")
}
kotlinc HelloWorld.kt
kotlinc
hexdump
00000000 ca fe ba be 00 00 00 32 00 2b 01 00 0c 48 65 6c |.......2.+...Hel|
00000010 6c 6f 57 6f 72 6c 64 4b 74 07 00 01 01 00 10 6a |loWorldKt......j|
00000020 61 76 61 2f 6c 61 6e 67 2f 4f 62 6a 65 63 74 07 |ava/lang/Object.|
00000030 00 03 01 00 04 6d 61 69 6e 01 00 03 28 29 56 01 |.....main...()V.|
00000040 00 16 28 5b 4c 6a 61 76 61 2f 6c 61 6e 67 2f 53 |..([Ljava/lang/S|
00000050 74 72 69 6e 67 3b 29 56 0c 00 05 00 06 0a 00 02 |tring;)V........|
00000060 00 08 01 00 10 48 65 6c 6c 6f 20 52 69 76 69 65 |.....Hello Rivie|
00000070 72 61 44 65 76 08 00 0a 01 00 10 6a 61 76 61 2f |raDev......java/|
00000080 6c 61 6e 67 2f 53 79 73 74 65 6d 07 00 0c 01 00 |lang/System.....|
00000090 03 6f 75 74 01 00 15 4c 6a 61 76 61 2f 69 6f 2f |.out...Ljava/io/|
000000a0 50 72 69 6e 74 53 74 72 65 61 6d 3b 0c 00 0e 00 |PrintStream;....|
000000b0 0f 09 00 0d 00 10 01 00 13 6a 61 76 61 2f 69 6f |.........java/io|
000000c0 2f 50 72 69 6e 74 53 74 72 65 61 6d 07 00 12 01 |/PrintStream....|
000000d0 00 07 70 72 69 6e 74 6c 6e 01 00 15 28 4c 6a 61 |..println...(Lja|
000000e0 76 61 2f 6c 61 6e 67 2f 4f 62 6a 65 63 74 3b 29 |va/lang/Object;)|
000000f0 56 0c 00 14 00 15 0a 00 13 00 16 01 00 11 4c 6b |V.............Lk|
00000100 6f 74 6c 69 6e 2f 4d 65 74 61 64 61 74 61 3b 01 |otlin/Metadata;.|
00000110 00 02 6d 76 03 00 00 00 01 03 00 00 00 0f 01 00 |..mv............|
00000120 02 62 76 03 00 00 00 00 03 00 00 00 03 01 00 01 |.bv.............|
00000130 6b 03 00 00 00 02 01 00 02 64 31 01 00 13 c0 80 |k........d1.....|
00000140 06 0a c0 80 0a 02 10 02 1a 06 10 c0 80 1a 02 30 |...............0|
00000150 01 01 00 02 64 32 01 00 00 01 00 0d 48 65 6c 6c |....d2......Hell|
00000160 6f 57 6f 72 6c 64 2e 6b 74 01 00 04 43 6f 64 65 |oWorld.kt...Code|
00000170 01 00 0f 4c 69 6e 65 4e 75 6d 62 65 72 54 61 62 |...LineNumberTab|
00000180 6c 65 01 00 0a 53 6f 75 72 63 65 46 69 6c 65 01 |le...SourceFile.|
00000190 00 14 53 6f 75 72 63 65 44 65 62 75 67 45 78 74 |..SourceDebugExt|
000001a0 65 6e 73 69 6f 6e 01 00 19 52 75 6e 74 69 6d 65 |ension...Runtime|
000001b0 56 69 73 69 62 6c 65 41 6e 6e 6f 74 61 74 69 6f |VisibleAnnotatio|
000001c0 6e 73 00 31 00 02 00 04 00 00 00 00 00 02 00 19 |ns.1............|
000001d0 00 05 00 06 00 01 00 26 00 00 00 29 00 02 00 02 |.......&...)....|
000001e0 00 00 00 0d 12 0b 4b 03 3c b2 00 11 2a b6 00 17 |......K.<...*...|
000001f0 b1 00 00 00 01 00 27 00 00 00 0a 00 02 00 00 00 |......'.........|
00000200 02 00 0c 00 03 10 09 00 05 00 07 00 01 00 26 00 |..............&.|
00000210 00 00 10 00 00 00 01 00 00 00 04 b8 00 09 b1 00 |................|
00000220 00 00 00 00 03 00 28 00 00 00 02 00 25 00 29 00 |......(.....%.).|
00000230 00 00 54 53 4d 41 50 0a 48 65 6c 6c 6f 57 6f 72 |..TSMAP.HelloWor|
00000240 6c 64 2e 6b 74 0a 4b 6f 74 6c 69 6e 0a 2a 53 20 |ld.kt.Kotlin.*S |
00000250 4b 6f 74 6c 69 6e 0a 2a 46 0a 2b 20 31 20 48 65 |Kotlin.*F.+ 1 He|
00000260 6c 6c 6f 57 6f 72 6c 64 2e 6b 74 0a 48 65 6c 6c |lloWorld.kt.Hell|
00000270 6f 57 6f 72 6c 64 4b 74 0a 2a 4c 0a 31 23 31 2c |oWorldKt.*L.1#1,|
00000280 34 3a 31 0a 2a 45 0a 00 2a 00 00 00 3a 00 01 00 |4:1.*E..*...:...|
00000290 18 00 05 00 19 5b 00 03 49 00 1a 49 00 1a 49 00 |.....[..I..I..I.|
000002a0 1b 00 1c 5b 00 03 49 00 1a 49 00 1d 49 00 1e 00 |...[..I..I..I...|
000002b0 1f 49 00 20 00 21 5b 00 01 73 00 22 00 23 5b 00 |.I. .![..s.".#[.|
000002c0 02 73 00 05 73 00 24 |.s..s.$|
000002c7
Java ByteCode
Compiled from "HelloWorld.kt"
public final class HelloWorldKt {
public static final void main();
Code:
0: ldc #11 // String Hello RivieraDev
2: astore_0
3: iconst_0
4: istore_1
5: getstatic #17 // Field java/lang/System.out:Ljava/io/PrintStream;
8: aload_0
9: invokevirtual #23 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
12: return
public static void main(java.lang.String[]);
Code:
0: invokestatic #9 // Method main:()V
3: return
}
HelloWorld-java
import kotlin.Metadata;
@Metadata(
mv = {1, 1, 15},
bv = {1, 0, 3},
k = 2,
d1 = {"\u0000\b\n\u0000\n\u0002\u0010\u0002\n\u0000\u001a\u0006\u0010\u0000\u001a\u00020\u0001¨\u0006\u0002"},
d2 = {"main", "", "kotlinDee"}
)
public final class HelloWorldKt {
public static final void main() {
String var0 = "Hello RivieraDev";
boolean var1 = false;
System.out.println(var0);
}
// $FF: synthetic method
public static void main(String[] var0) {
main();
}
}
Bilan HelloWorld.kt
- Kotlin ajoute du contenu
- du coup, on a besoin de JARs en plus
jar | version | taille | |
---|---|---|---|
kotlin-stdlib | kotlin-stdlib | 1.3.31 | 1.3M |
kotlin-stdlib-jdk7 | kotlin-stdlib-jdk7 | 1.3.31 | 3.1k |
kotlin-stdlib-jdk8 | kotlin-stdlib-jdk8 | 1.3.31 | 13k |
kotlin-reflect | kotlin-reflect | 1.3.31 | 2.8M |
lombok | lombok | 1.18.6 | 1.7M |
spring-core | spring-core | 5.1.6 | 1.3M |
Les bases
Les bases
val-var.kt
var x: Int = 10
val y: Int = 3
x += 4
// y += 4 <== 💣 Compilation Error
println(x * y) // 42
string-template.kt
fun greeting(who: Someone) {
println("Hello $who!")
println("Hello ${who.firstName} ${who.lastName}!")
println("""
multi
line "$who"
string""".trimIndent())
}
string-template.java
import kotlin.Metadata;
import kotlin.jvm.internal.Intrinsics;
import kotlin.text.StringsKt;
import org.jetbrains.annotations.NotNull;
@Metadata(
mv = {1, 1, 15},
bv = {1, 0, 3},
k = 2,
d1 = {"\u0000\u000e\n\u0000\n\u0002\u0010\u0002\n\u0000\n\u0002\u0018\u0002\n\u0000\u001a\u000e\u0010\u0000\u001a\u00020\u00012\u0006\u0010\u0002\u001a\u00020\u0003¨\u0006\u0004"},
d2 = {"greeting", "", "who", "LSomeone;", "kotlinDee"}
)
public final class GreetingKt {
public static final void greeting(@NotNull Someone who) {
Intrinsics.checkParameterIsNotNull(who, "who");
String var1 = "Hello " + who + '!';
boolean var2 = false;
System.out.println(var1);
var1 = "Hello " + who.getFirstName() + ' ' + who.getLastName() + '!';
var2 = false;
System.out.println(var1);
var1 = StringsKt.trimIndent("\n multi\n line \"" + who + "\"\n string");
var2 = false;
System.out.println(var1);
}
}
ByteCode de string-template
Compiled from "greeting.kt"
public final class GreetingKt {
public static final void greeting(Someone);
Code:
0: aload_0
1: ldc #9 // String who
3: invokestatic #15 // Method kotlin/jvm/internal/Intrinsics.checkParameterIsNotNull:(Ljava/lang/Object;Ljava/lang/String;)V
6: new #17 // class java/lang/StringBuilder
9: dup
10: invokespecial #21 // Method java/lang/StringBuilder."<init>":()V
13: ldc #23 // String Hello
15: invokevirtual #27 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
18: aload_0
19: invokevirtual #30 // Method java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder;
22: bipush 33
24: invokevirtual #33 // Method java/lang/StringBuilder.append:(C)Ljava/lang/StringBuilder;
27: invokevirtual #37 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
30: astore_1
31: iconst_0
32: istore_2
33: getstatic #43 // Field java/lang/System.out:Ljava/io/PrintStream;
36: aload_1
37: invokevirtual #49 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
40: new #17 // class java/lang/StringBuilder
43: dup
44: invokespecial #21 // Method java/lang/StringBuilder."<init>":()V
47: ldc #23 // String Hello
49: invokevirtual #27 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
52: aload_0
53: invokevirtual #54 // Method Someone.getFirstName:()Ljava/lang/String;
56: invokevirtual #27 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
59: bipush 32
61: invokevirtual #33 // Method java/lang/StringBuilder.append:(C)Ljava/lang/StringBuilder;
64: aload_0
65: invokevirtual #57 // Method Someone.getLastName:()Ljava/lang/String;
68: invokevirtual #27 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
71: bipush 33
73: invokevirtual #33 // Method java/lang/StringBuilder.append:(C)Ljava/lang/StringBuilder;
76: invokevirtual #37 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
79: astore_1
80: iconst_0
81: istore_2
82: getstatic #43 // Field java/lang/System.out:Ljava/io/PrintStream;
85: aload_1
86: invokevirtual #49 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
89: new #17 // class java/lang/StringBuilder
92: dup
93: invokespecial #21 // Method java/lang/StringBuilder."<init>":()V
96: ldc #59 // String \n multi\n line \"
98: invokevirtual #27 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
101: aload_0
102: invokevirtual #30 // Method java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder;
105: ldc #61 // String \"\n string
107: invokevirtual #27 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
110: invokevirtual #37 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
113: invokestatic #67 // Method kotlin/text/StringsKt.trimIndent:(Ljava/lang/String;)Ljava/lang/String;
116: astore_1
117: iconst_0
118: istore_2
119: getstatic #43 // Field java/lang/System.out:Ljava/io/PrintStream;
122: aload_1
123: invokevirtual #49 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
126: return
}
numeric.kt
val anInt = 42 // type inference: Int
val aLong = 42L // type inference: Long
var aDouble: Double? = null
numeric.java
import kotlin.Metadata;
import org.jetbrains.annotations.Nullable;
@Metadata(
mv = {1, 1, 15},
bv = {1, 0, 3},
k = 2,
d1 = {"\u0000\u001a\n\u0000\n\u0002\u0010\u0006\n\u0002\b\u0006\n\u0002\u0010\t\n\u0002\b\u0003\n\u0002\u0010\b\n\u0002\b\u0003\"\u001e\u0010\u0000\u001a\u0004\u0018\u00010\u0001X\u0086\u000e¢\u0006\u0010\n\u0002\u0010\u0006\u001a\u0004\b\u0002\u0010\u0003\"\u0004\b\u0004\u0010\u0005\"\u0014\u0010\u0007\u001a\u00020\bX\u0086D¢\u0006\b\n\u0000\u001a\u0004\b\t\u0010\n\"\u0014\u0010\u000b\u001a\u00020\fX\u0086D¢\u0006\b\n\u0000\u001a\u0004\b\r\u0010\u000e¨\u0006\u000f"},
d2 = {"aDouble", "", "getADouble", "()Ljava/lang/Double;", "setADouble", "(Ljava/lang/Double;)V", "Ljava/lang/Double;", "aLong", "", "getALong", "()J", "anInt", "", "getAnInt", "()I", "kotlinDee"}
)
public final class NumericKt {
private static final int anInt = 42;
private static final long aLong = 42L;
@Nullable
private static Double aDouble;
public static final int getAnInt() {
return anInt;
}
public static final long getALong() {
return aLong;
}
@Nullable
public static final Double getADouble() {
return aDouble;
}
public static final void setADouble(@Nullable Double var0) {
aDouble = var0;
}
}
ByteCode de numeric
Compiled from "numeric.kt"
public final class NumericKt {
public static final int getAnInt();
Code:
0: getstatic #11 // Field anInt:I
3: ireturn
public static final long getALong();
Code:
0: getstatic #19 // Field aLong:J
3: lreturn
public static final java.lang.Double getADouble();
Code:
0: getstatic #26 // Field aDouble:Ljava/lang/Double;
3: areturn
public static final void setADouble(java.lang.Double);
Code:
0: aload_0
1: putstatic #26 // Field aDouble:Ljava/lang/Double;
4: return
static {};
Code:
0: bipush 42
2: putstatic #11 // Field anInt:I
5: ldc2_w #14 // long 42l
8: putstatic #19 // Field aLong:J
11: return
}
C'est simple
-
Plus de
;
* - 😍 String templating
- 😘 Plus de types primitifs (avant la compilation)
- 🧐 Inférence de type
- 🤝 On peut mélanger du code Java et Kotlin
null-safety
null-safety
Null References: The Billion Dollar MistakeI call it my billion-dollar mistake. It was the invention of the
null
reference in 1965. [...] This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years.
null-safety.kt
fun main() {
val somethingNotNull: String = "aString"
// somethingNotNull: String = null => compilation error
var length = somethingNotNull.length
var something: String? = null
length = something?.length ?: 0
length = createSomething()?.length ?: 0
// length = createSomething()!!.length // throw kotlin.KotlinNullPointerException
// SmartCast
something = "aString"
length = something.length // auto cast to String (no need of `?.`)
}
fun createSomething(): String? = null
null-safety.java
import kotlin.Metadata;
import org.jetbrains.annotations.Nullable;
@Metadata(
mv = {1, 1, 15},
bv = {1, 0, 3},
k = 2,
d1 = {"\u0000\u000e\n\u0000\n\u0002\u0010\u000e\n\u0000\n\u0002\u0010\u0002\n\u0000\u001a\b\u0010\u0000\u001a\u0004\u0018\u00010\u0001\u001a\u0006\u0010\u0002\u001a\u00020\u0003¨\u0006\u0004"},
d2 = {"createSomething", "", "main", "", "kotlinDee"}
)
public final class Null_safetyKt {
public static final void main() {
String somethingNotNull = "aString";
int length = somethingNotNull.length();
String something = (String)null;
int length = false;
String var10000 = createSomething();
length = var10000 != null ? var10000.length() : 0;
something = "aString";
length = something.length();
}
// $FF: synthetic method
public static void main(String[] var0) {
main();
}
@Nullable
public static final String createSomething() {
return null;
}
}
Bilan null-safety
-
🎸 Elvis operator:
?:
-
🙌 plus de
NullPointerException
-
⚠️ quand on appelle du Java
- Le compilateur Kotlin peut interpréter des annotions de nullabilité (JSR-305, Android, ...)
-
Pas de
Optional
, si nécessaire voir Arrow
Les types
Les types
Types basiques
Types basiques nullable
todo.kt
fun `is P = NP`(): Boolean =
TODO()
fun main(args: Array<String>) {
println("P = NP is ${`is P = NP`()}")
}
Hiérarchie des types
-
🤝 le
TODO()
est l'ami du TDD
Les fonctions
Les fonctions
named-params.kt
fun buildString(prefix: String,
who: String,
enhanced: Boolean): String {
var msg = "$prefix $who"
if (enhanced) {
msg += '!'
}
return msg
}
fun greetings(): String =
buildString(enhanced = true, who = "RivieraDev", prefix = "Hello")
named-params.java
import kotlin.Metadata;
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;
@Metadata(
mv = {1, 1, 15},
bv = {1, 0, 3},
k = 2,
d1 = {"\u0000\u0012\n\u0000\n\u0002\u0010\u000e\n\u0002\b\u0003\n\u0002\u0010\u000b\n\u0002\b\u0002\u001a\u001e\u0010\u0000\u001a\u00020\u00012\u0006\u0010\u0002\u001a\u00020\u00012\u0006\u0010\u0003\u001a\u00020\u00012\u0006\u0010\u0004\u001a\u00020\u0005\u001a\u0006\u0010\u0006\u001a\u00020\u0001¨\u0006\u0007"},
d2 = {"buildString", "", "prefix", "who", "enhanced", "", "greetings", "kotlinDee"}
)
public final class Named_paramsKt {
@NotNull
public static final String buildString(@NotNull String prefix, @NotNull String who, boolean enhanced) {
Intrinsics.checkParameterIsNotNull(prefix, "prefix");
Intrinsics.checkParameterIsNotNull(who, "who");
String msg = prefix + ' ' + who;
if (enhanced) {
msg = msg + '!';
}
return msg;
}
@NotNull
public static final String greetings() {
String var0 = "Hello";
String var1 = "RivieraDev";
boolean var2 = true;
return buildString(var0, var1, var2);
}
}
default-value.kt
fun buildString2(prefix: String = "Hello",
who: String,
enhanced: Boolean = true): String {
var msg = "$prefix $who"
if (enhanced) {
msg += '!'
}
return msg
}
fun greetings2(): String =
buildString2(who = "RivieraDev")
Comment ça marche
// In my-app.jar
fun main() {
println(compute())
}
// In lib-v1.0.0
fun compute(result: Int = 1) = result
// In lib-v1.0.1
fun compute(result: Int = 42) = result
-
Compile
my-app
aveclib-v1.0.0
-
java my-app.jar -cp lib-v1.0.0.jar
-
java my-app.jar -cp lib-v1.0.1.jar
-
Résultat ?
default-value.java
import kotlin.Metadata;
@Metadata(
mv = {1, 1, 15},
bv = {1, 0, 3},
k = 2,
d1 = {"\u0000\b\n\u0000\n\u0002\u0010\u0002\n\u0000\u001a\u0006\u0010\u0000\u001a\u00020\u0001¨\u0006\u0002"},
d2 = {"main", "", "kotlinDee"}
)
public final class My_appKt {
public static final void main() {
int var0 = LibKt.compute$default(0, 1, (Object)null);
boolean var1 = false;
System.out.println(var0);
}
// $FF: synthetic method
public static void main(String[] var0) {
main();
}
}
ByteCode de default-value
import kotlin.Metadata;
@Metadata(
mv = {1, 1, 15},
bv = {1, 0, 3},
k = 2,
d1 = {"\u0000\n\n\u0000\n\u0002\u0010\b\n\u0002\b\u0002\u001a\u0010\u0010\u0000\u001a\u00020\u00012\b\b\u0002\u0010\u0002\u001a\u00020\u0001¨\u0006\u0003"},
d2 = {"compute", "", "result", "kotlinDee"}
)
public final class LibKt {
public static final int compute(int result) {
return result;
}
// $FF: synthetic method
public static int compute$default(int var0, int var1, Object var2) {
if ((var1 & 1) != 0) {
var0 = 42;
}
return compute(var0);
}
}
Kotlin c'est fun !
- Toujours typer le retour de vos fonctions
-
(sauf si c'est évident et une surcharge comme le
toString
) - Kotlin est plus concis que Java
- => évitez de faire des fonctions trop longues
-
Sautez une ligne après le
Utilisez le passage des arguments par nom quand ça lève des ambiguïtés=
Les lambdas
Les lambdas
function.kt
// Declare apply function with function as parameter
fun compute(x: Int, y: Int, operation: (Int, Int) -> Int): Int =
operation(x, y)
// Declare function
fun sumf(x: Int, y: Int): Int =
x + y
// call compute with function reference
val sum5 = compute(2, 3, ::sumf)
// store function reference
val sumLam = ::sumf
// call compute with the function reference
val sum6 = compute(1, 5, sumLam)
function.java
import kotlin.Metadata;
import kotlin.jvm.functions.Function2;
import kotlin.jvm.internal.Intrinsics;
import kotlin.reflect.KFunction;
import org.jetbrains.annotations.NotNull;
@Metadata(
mv = {1, 1, 15},
bv = {1, 0, 3},
k = 2,
d1 = {"\u0000\u001e\n\u0000\n\u0002\u0010\b\n\u0002\b\u0005\n\u0002\u0018\u0002\n\u0002\u0018\u0002\n\u0002\b\u0007\n\u0002\u0018\u0002\n\u0002\b\u0002\u001a0\u0010\u000e\u001a\u00020\u00012\u0006\u0010\n\u001a\u00020\u00012\u0006\u0010\u000b\u001a\u00020\u00012\u0018\u0010\u000f\u001a\u0014\u0012\u0004\u0012\u00020\u0001\u0012\u0004\u0012\u00020\u0001\u0012\u0004\u0012\u00020\u00010\u0010\u001a\u0016\u0010\u0011\u001a\u00020\u00012\u0006\u0010\n\u001a\u00020\u00012\u0006\u0010\u000b\u001a\u00020\u0001\"\u0011\u0010\u0000\u001a\u00020\u0001¢\u0006\b\n\u0000\u001a\u0004\b\u0002\u0010\u0003\"\u0011\u0010\u0004\u001a\u00020\u0001¢\u0006\b\n\u0000\u001a\u0004\b\u0005\u0010\u0003\"A\u0010\u0006\u001a2\u0012\u0013\u0012\u00110\u0001¢\u0006\f\b\b\u0012\b\b\t\u0012\u0004\b\b(\n\u0012\u0013\u0012\u00110\u0001¢\u0006\f\b\b\u0012\b\b\t\u0012\u0004\b\b(\u000b\u0012\u0004\u0012\u00020\u00010\u0007¢\u0006\b\n\u0000\u001a\u0004\b\f\u0010\r¨\u0006\u0012"},
d2 = {"sum5", "", "getSum5", "()I", "sum6", "getSum6", "sumLam", "Lkotlin/reflect/KFunction2;", "Lkotlin/ParameterName;", "name", "x", "y", "getSumLam", "()Lkotlin/reflect/KFunction;", "compute", "operation", "Lkotlin/Function2;", "sumf", "kotlinDee"}
)
public final class FunctionKt {
private static final int sum5;
@NotNull
private static final KFunction sumLam;
private static final int sum6;
public static final int compute(int x, int y, @NotNull Function2 operation) {
Intrinsics.checkParameterIsNotNull(operation, "operation");
return ((Number)operation.invoke(x, y)).intValue();
}
public static final int sumf(int x, int y) {
return x + y;
}
public static final int getSum5() {
return sum5;
}
@NotNull
public static final KFunction getSumLam() {
return sumLam;
}
public static final int getSum6() {
return sum6;
}
static {
sum5 = compute(2, 3, (Function2)null.INSTANCE);
sumLam = null.INSTANCE;
sum6 = compute(1, 5, (Function2)sumLam);
}
}
lambda.kt
// Declare lambda
val suml: (Int, Int) -> Int = { x: Int, y: Int ->
x + y
}
// call compute with suml lambda
val sum3 = compute(1, 2, suml)
// call compute with lamda
val sum4 = compute(1, 3) { x, y ->
x + y
}
lambda.java
import kotlin.Metadata;
import kotlin.jvm.functions.Function2;
import org.jetbrains.annotations.NotNull;
@Metadata(
mv = {1, 1, 15},
bv = {1, 0, 3},
k = 2,
d1 = {"\u0000\u0012\n\u0000\n\u0002\u0010\b\n\u0002\b\u0005\n\u0002\u0018\u0002\n\u0002\b\u0003\"\u0011\u0010\u0000\u001a\u00020\u0001¢\u0006\b\n\u0000\u001a\u0004\b\u0002\u0010\u0003\"\u0011\u0010\u0004\u001a\u00020\u0001¢\u0006\b\n\u0000\u001a\u0004\b\u0005\u0010\u0003\"#\u0010\u0006\u001a\u0014\u0012\u0004\u0012\u00020\u0001\u0012\u0004\u0012\u00020\u0001\u0012\u0004\u0012\u00020\u00010\u0007¢\u0006\b\n\u0000\u001a\u0004\b\b\u0010\t¨\u0006\n"},
d2 = {"sum3", "", "getSum3", "()I", "sum4", "getSum4", "suml", "Lkotlin/Function2;", "getSuml", "()Lkotlin/jvm/functions/Function2;", "kotlinDee"}
)
public final class LambdaKt {
@NotNull
private static final Function2 suml;
private static final int sum3;
private static final int sum4;
@NotNull
public static final Function2 getSuml() {
return suml;
}
public static final int getSum3() {
return sum3;
}
public static final int getSum4() {
return sum4;
}
static {
suml = (Function2)null.INSTANCE;
sum3 = FunctionKt.compute(1, 2, suml);
sum4 = FunctionKt.compute(1, 3, (Function2)null.INSTANCE);
}
}
let.kt
val other = sumf(1, 2)
.let { it + 1 }
val nullable = maybeAnInt()
?.let { it + 1 }
let.java
import kotlin.Metadata;
import org.jetbrains.annotations.Nullable;
@Metadata(
mv = {1, 1, 15},
bv = {1, 0, 3},
k = 2,
d1 = {"\u0000\n\n\u0000\n\u0002\u0010\b\n\u0002\b\u0007\"\u0015\u0010\u0000\u001a\u0004\u0018\u00010\u0001¢\u0006\n\n\u0002\u0010\u0004\u001a\u0004\b\u0002\u0010\u0003\"\u0011\u0010\u0005\u001a\u00020\u0001¢\u0006\b\n\u0000\u001a\u0004\b\u0006\u0010\u0007¨\u0006\b"},
d2 = {"nullable", "", "getNullable", "()Ljava/lang/Integer;", "Ljava/lang/Integer;", "other", "getOther", "()I", "kotlinDee"}
)
public final class LetKt {
private static final int other;
@Nullable
private static final Integer nullable;
public static final int getOther() {
return other;
}
@Nullable
public static final Integer getNullable() {
return nullable;
}
static {
int var0 = FunctionKt.sumf(1, 2);
boolean var1 = false;
boolean var2 = false;
int var4 = false;
other = var0 + 1;
Integer var10000 = PlopKt.maybeAnInt();
if (var10000 != null) {
Integer var5 = var10000;
var1 = false;
var2 = false;
int it = ((Number)var5).intValue();
var4 = false;
var10000 = it + 1;
} else {
var10000 = null;
}
nullable = var10000;
}
}
Les lambdas
-
⚠️ pas de
return
-
pensez à mettre vos lambda comme dernier argument
-
voir aussi les
apply
,also
,run
,use
,with
- the tldr; on Kotlin’s let, apply, also, with and run functions
Les classes
Les classes
astronomy.kt
interface AstronomicalBody {
val name: String
}
data class Planet(override val name: String,
val moons: List<Moon> = emptyList()) : AstronomicalBody {
init {
require(name.isNotEmpty())
}
operator fun plus(moon: Moon): Planet {
return this.copy(moons = moons + moon)
}
}
data class Moon(override val name: String) : AstronomicalBody
object SolarSystem {
val moon = Moon(name = "Moon")
val earth = Planet(name = "Earth") + moon
val bodies: List<AstronomicalBody> = listOf(
earth,
Planet(name = "Jupiter")
)
}
enum class PlanetKind {
Terrestrial, GasGiant, IceGiant;
companion object {
fun fromName(name: String): PlanetKind {
return PlanetKind.valueOf(name) // enumValueOf(name)
}
}
}
fun getMoons(planet: Planet): List<Moon> {
val (_, moons) = planet
return moons
}
astronomy.java
import java.util.Collection;
import java.util.List;
import kotlin.Metadata;
import kotlin.collections.CollectionsKt;
import kotlin.jvm.internal.DefaultConstructorMarker;
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@Metadata(
mv = {1, 1, 15},
bv = {1, 0, 3},
k = 1,
d1 = {"\u00000\n\u0002\u0018\u0002\n\u0002\u0018\u0002\n\u0000\n\u0002\u0010\u000e\n\u0000\n\u0002\u0010 \n\u0002\u0018\u0002\n\u0002\b\t\n\u0002\u0010\u000b\n\u0000\n\u0002\u0010\u0000\n\u0000\n\u0002\u0010\b\n\u0002\b\u0004\b\u0086\b\u0018\u00002\u00020\u0001B\u001d\u0012\u0006\u0010\u0002\u001a\u00020\u0003\u0012\u000e\b\u0002\u0010\u0004\u001a\b\u0012\u0004\u0012\u00020\u00060\u0005¢\u0006\u0002\u0010\u0007J\t\u0010\f\u001a\u00020\u0003HÆ\u0003J\u000f\u0010\r\u001a\b\u0012\u0004\u0012\u00020\u00060\u0005HÆ\u0003J#\u0010\u000e\u001a\u00020\u00002\b\b\u0002\u0010\u0002\u001a\u00020\u00032\u000e\b\u0002\u0010\u0004\u001a\b\u0012\u0004\u0012\u00020\u00060\u0005HÆ\u0001J\u0013\u0010\u000f\u001a\u00020\u00102\b\u0010\u0011\u001a\u0004\u0018\u00010\u0012HÖ\u0003J\t\u0010\u0013\u001a\u00020\u0014HÖ\u0001J\u0011\u0010\u0015\u001a\u00020\u00002\u0006\u0010\u0016\u001a\u00020\u0006H\u0086\u0002J\t\u0010\u0017\u001a\u00020\u0003HÖ\u0001R\u0017\u0010\u0004\u001a\b\u0012\u0004\u0012\u00020\u00060\u0005¢\u0006\b\n\u0000\u001a\u0004\b\b\u0010\tR\u0014\u0010\u0002\u001a\u00020\u0003X\u0096\u0004¢\u0006\b\n\u0000\u001a\u0004\b\n\u0010\u000b¨\u0006\u0018"},
d2 = {"LPlanet;", "LAstronomicalBody;", "name", "", "moons", "", "LMoon;", "(Ljava/lang/String;Ljava/util/List;)V", "getMoons", "()Ljava/util/List;", "getName", "()Ljava/lang/String;", "component1", "component2", "copy", "equals", "", "other", "", "hashCode", "", "plus", "moon", "toString", "kotlinDee"}
)
public final class Planet implements AstronomicalBody {
@NotNull
private final String name;
@NotNull
private final List moons;
@NotNull
public final Planet plus(@NotNull Moon moon) {
Intrinsics.checkParameterIsNotNull(moon, "moon");
return copy$default(this, (String)null, CollectionsKt.plus((Collection)this.moons, moon), 1, (Object)null);
}
@NotNull
public String getName() {
return this.name;
}
@NotNull
public final List getMoons() {
return this.moons;
}
public Planet(@NotNull String name, @NotNull List moons) {
Intrinsics.checkParameterIsNotNull(name, "name");
Intrinsics.checkParameterIsNotNull(moons, "moons");
super();
this.name = name;
this.moons = moons;
CharSequence var3 = (CharSequence)this.getName();
boolean var4 = false;
boolean var8 = var3.length() > 0;
var4 = false;
boolean var5 = false;
var5 = false;
boolean var6 = false;
if (!var8) {
boolean var7 = false;
String var9 = "Failed requirement.";
throw (Throwable)(new IllegalArgumentException(var9.toString()));
}
}
// $FF: synthetic method
public Planet(String var1, List var2, int var3, DefaultConstructorMarker var4) {
if ((var3 & 2) != 0) {
var2 = CollectionsKt.emptyList();
}
this(var1, var2);
}
@NotNull
public final String component1() {
return this.getName();
}
@NotNull
public final List component2() {
return this.moons;
}
@NotNull
public final Planet copy(@NotNull String name, @NotNull List moons) {
Intrinsics.checkParameterIsNotNull(name, "name");
Intrinsics.checkParameterIsNotNull(moons, "moons");
return new Planet(name, moons);
}
// $FF: synthetic method
@NotNull
public static Planet copy$default(Planet var0, String var1, List var2, int var3, Object var4) {
if ((var3 & 1) != 0) {
var1 = var0.getName();
}
if ((var3 & 2) != 0) {
var2 = var0.moons;
}
return var0.copy(var1, var2);
}
@NotNull
public String toString() {
return "Planet(name=" + this.getName() + ", moons=" + this.moons + ")";
}
public int hashCode() {
String var10000 = this.getName();
int var1 = (var10000 != null ? var10000.hashCode() : 0) * 31;
List var10001 = this.moons;
return var1 + (var10001 != null ? var10001.hashCode() : 0);
}
public boolean equals(@Nullable Object var1) {
if (this != var1) {
if (var1 instanceof Planet) {
Planet var2 = (Planet)var1;
if (Intrinsics.areEqual(this.getName(), var2.getName()) && Intrinsics.areEqual(this.moons, var2.moons)) {
return true;
}
}
return false;
} else {
return true;
}
}
}
Héritage en Kotlin
open class SmallBody {
open fun sizeRange(): IntRange = 0..10
}
// Inherit SmallBody
data class Comet(val name: String): SmallBody()
// Inherit SmallBody
data class Asteroid(val name: String): SmallBody() {
override fun sizeRange(): IntRange = 0..4
}
fun main(args: Array<String>) {
val bodies = listOf(Comet("Halley"), Asteroid("Adeona"))
bodies.forEach { body ->
println("$body: ${body.sizeRange()}")
}
}
Génériques
- ⚠️ Les contrôles de types génériques ne sont faits qu'au moment de la compilation
- Covariant:
out
, en java? extends T
- Contravariant:
in
, en java? super T
- Projection
*
correspondant àAny?
ouNothing
Borne supérieure
fun <T : Comparable<T>> sort(list: List<T>): List<T>
Les détails: https://kotlinlang.org/docs/reference/generics.html
Sealed
sealed class JsonValue
data class JsonObject(val attributes: Map<String, JsonValue>) : JsonValue()
data class JsonArray(val values: List<JsonValue>) : JsonValue()
data class JsonString(val value: String) : JsonValue()
data class JsonNumber(val value: Number) : JsonValue()
data class JsonBoolean(val value: Boolean) : JsonValue()
object JsonNull : JsonValue()
Alias en Kotlin
interface Entity
typealias Id = String
typealias Version = Int
typealias EntityKey = Pair<Id, Version>
typealias Entities = List<Entity>
// fun getAllEntities(): Map<Pair<String, Int>, List<Entity>> = emptyMap()
fun getAllEntities(): Map<EntityKey, Entities> = emptyMap()
ByteCode d'alias
Compiled from "typealias.kt"
public final class TypealiasKt {
public static final java.util.Map<kotlin.Pair<java.lang.String, java.lang.Integer>, java.util.List<Entity>> getAllEntities();
Code:
0: invokestatic #13 // Method kotlin/collections/MapsKt.emptyMap:()Ljava/util/Map;
3: areturn
}
Classe, le bilan
-
🤩
data class
-
🤔 Mais pourquoi on n'a pas ça en Java ?
- JEP draft: Records and Sealed Types
-
Une seule classe par fichier n'est pas utile
-
🤓
sealed
permet de faire des types algébriques de données (Algebraic Data Type)
Pause
Pause
ByteCode Android
ByteCode Android
Compilation pour Android
Dalvik EXecutable format
java -jar ./scripts/lib/d8.jar --release \
--output ./target/android/dex \
./target/android/hello.jar
00000000 64 65 78 0a 30 33 35 00 06 50 f0 61 50 10 7c c0 |dex.035..P.aP.|.|
00000010 b2 f9 77 2d 54 df 60 f3 ac dd b0 10 eb 55 53 e1 |..w-T.`......US.|
00000020 28 f6 10 00 70 00 00 00 78 56 34 12 00 00 00 00 |(...p...xV4.....|
00000030 00 00 00 00 4c f5 10 00 12 17 00 00 70 00 00 00 |....L.......p...|
00000040 31 03 00 00 b8 5c 00 00 2a 08 00 00 7c 69 00 00 |1....\..*...|i..|
00000050 30 03 00 00 74 cb 00 00 20 1a 00 00 f4 e4 00 00 |0...t... .......|
00000060 75 02 00 00 f4 b5 01 00 94 f1 0e 00 94 04 02 00 |u...............|
00000070 4a f1 07 00 4c f1 07 00 75 f1 07 00 a4 f1 07 00 |J...L...u.......|
00000080 c2 f1 07 00 e0 f1 07 00 00 f2 07 00 23 f2 07 00 |............#...|
00000090 71 f2 07 00 b9 f2 07 00 07 f3 07 00 37 f3 07 00 |q...........7...|
000000a0 69 f3 07 00 90 f3 07 00 bc f3 07 00 e3 f3 07 00 |i...............|
000000b0 27 f4 07 00 71 f4 07 00 8f f4 07 00 ad f4 07 00 |'...q...........|
000000c0 cb f4 07 00 ed f4 07 00 0f f5 07 00 2c f5 07 00 |............,...|
000000d0 49 f5 07 00 79 f5 07 00 b1 f5 07 00 e9 f5 07 00 |I...y...........|
000000e0 1a f6 07 00 51 f6 07 00 7b f6 07 00 a6 f6 07 00 |....Q...{.......|
000000f0 d1 f6 07 00 0a f7 07 00 47 f7 07 00 84 f7 07 00 |........G.......|
00000100 c1 f7 07 00 02 f8 07 00 43 f8 07 00 84 f8 07 00 |........C.......|
00000110 f1 f8 07 00 12 f9 07 00 41 f9 07 00 6e f9 07 00 |........A...n...|
00000120 b0 f9 07 00 dd f9 07 00 0a fa 07 00 39 fa 07 00 |............9...|
00000130 68 fa 07 00 ab fa 07 00 e0 fa 07 00 25 fb 07 00 |h...........%...|
00000140 f3 fb 07 00 3b fc 07 00 79 fc 07 00 b1 fc 07 00 |....;...y.......|
00000150 eb fc 07 00 26 fd 07 00 68 fd 07 00 9e fd 07 00 |....&...h.......|
00000160 e7 fd 07 00 2a fe 07 00 5c fe 07 00 9d fe 07 00 |....*...\.......|
00000170 de fe 07 00 25 ff 07 00 5b ff 07 00 90 ff 07 00 |....%...[.......|
00000180 c0 ff 07 00 fc ff 07 00 75 00 08 00 ca 00 08 00 |........u.......|
00000190 30 01 08 00 a7 01 08 00 2f 02 08 00 c9 02 08 00 |0......./.......|
000001a0 74 03 08 00 30 04 08 00 fd 04 08 00 db 05 08 00 |t...0...........|
000001b0 ca 06 08 00 ca 07 08 00 db 08 08 00 fd 09 08 00 |................|
000001c0 30 0b 08 00 76 0c 08 00 cd 0d 08 00 35 0f 08 00 |0...v.......5...|
000001d0 ae 10 08 00 38 12 08 00 d3 13 08 00 7f 15 08 00 |....8...........|
000001e0 3c 17 08 00 7b 17 08 00 b8 17 08 00 f5 17 08 00 |<...{...........|
000001f0 34 18 08 00 80 18 08 00 cc 18 08 00 18 19 08 00 |4...............|
00000200 64 19 08 00 b0 19 08 00 fc 19 08 00 48 1a 08 00 |d...........H...|
00000210 94 1a 08 00 c8 1a 08 00 ff 1a 08 00 3f 1b 08 00 |............?...|
00000220 87 1b 08 00 62 1c 08 00 a8 1c 08 00 16 1d 08 00 |....b...........|
00000230 57 1d 08 00 a4 1d 08 00 e8 1d 08 00 31 1e 08 00 |W...........1...|
00000240 86 1e 08 00 d1 1e 08 00 23 1f 08 00 7a 1f 08 00 |........#...z...|
00000250 bf 1f 08 00 06 20 08 00 4d 20 08 00 f8 20 08 00 |..... ..M ... ..|
00000260 4f 21 08 00 84 21 08 00 b9 21 08 00 f8 21 08 00 |O!...!...!...!..|
00000270 4e 22 08 00 9d 22 08 00 e7 22 08 00 21 23 08 00 |N"..."..."..!#..|
00000280 6b 23 08 00 d2 23 08 00 0e 24 08 00 4a 24 08 00 |k#...#...$..J$..|
00000290 8d 24 08 00 e1 24 08 00 43 25 08 00 c6 25 08 00 |.$...$..C%...%..|
000002a0 14 26 08 00 6c 26 08 00 b9 26 08 00 0c 27 08 00 |.&..l&...&...'..|
000002b0 61 27 08 00 9f 27 08 00 e3 27 08 00 55 28 08 00 |a'...'...'..U(..|
000002c0 d1 28 08 00 2a 29 08 00 db 29 08 00 8c 2a 08 00 |.(..*)...)...*..|
000002d0 e5 2a 08 00 3e 2b 08 00 97 2b 08 00 e6 2b 08 00 |.*..>+...+...+..|
000002e0 8c 2c 08 00 a5 2f 08 00 ed 2f 08 00 1a 31 08 00 |.,.../.../...1..|
000002f0 6f 31 08 00 c4 31 08 00 31 32 08 00 88 32 08 00 |o1...1..12...2..|
00000300 fa 32 08 00 87 33 08 00 2c 34 08 00 75 34 08 00 |.2...3..,4..u4..|
00000310 da 34 08 00 85 35 08 00 ed 35 08 00 50 36 08 00 |.4...5...5..P6..|
00000320 a1 36 08 00 fe 36 08 00 48 37 08 00 8e 37 08 00 |.6...6..H7...7..|
00000330 ce 37 08 00 6f 38 08 00 dc 38 08 00 23 39 08 00 |.7..o8...8..#9..|
00000340 64 39 08 00 a1 39 08 00 f4 39 08 00 47 3a 08 00 |d9...9...9..G:..|
00000350 b1 3a 08 00 0f 3b 08 00 ae 3b 08 00 5a 3c 08 00 |.:...;...;..Z<..|
00000360 e4 3c 08 00 c0 3d 08 00 4a 3e 08 00 ae 3e 08 00 |.<...=..J>...>..|
00000370 0f 3f 08 00 b0 3f 08 00 83 40 08 00 f4 40 08 00 |.?...?...@...@..|
00000380 3f 41 08 00 8b 41 08 00 06 42 08 00 6d 42 08 00 |?A...A...B..mB..|
00000390 14 43 08 00 a7 43 08 00 0e 44 08 00 75 44 08 00 |.C...C...D..uD..|
000003a0 41 45 08 00 9b 45 08 00 f5 45 08 00 61 46 08 00 |AE...E...E..aF..|
000003b0 14 47 08 00 c7 47 08 00 25 48 08 00 78 48 08 00 |.G...G..%H..xH..|
000003c0 11 49 08 00 d7 49 08 00 44 4a 08 00 b3 4a 08 00 |.I...I..DJ...J..|
000003d0 20 4b 08 00 b1 4b 08 00 d7 4d 08 00 58 4e 08 00 | K...K...M..XN..|
000003e0 f5 4e 08 00 99 4f 08 00 36 50 08 00 cd 50 08 00 |.N...O..6P...P..|
000003f0 44 51 08 00 c4 51 08 00 3d 52 08 00 af 52 08 00 |DQ...Q..=R...R..|
00000400 2c 53 08 00 aa 53 08 00 15 54 08 00 af 54 08 00 |,S...S...T...T..|
00000410 4a 55 08 00 68 56 08 00 7b 57 08 00 5a 58 08 00 |JU..hV..{W..ZX..|
00000420 19 59 08 00 1c 5a 08 00 13 5b 08 00 91 5b 08 00 |.Y...Z...[...[..|
00000430 f8 5b 08 00 7c 5c 08 00 5d 5d 08 00 2a 5e 08 00 |.[..|\..]]..*^..|
00000440 8d 5e 08 00 41 5f 08 00 ef 5f 08 00 ab 60 08 00 |.^..A_..._...`..|
00000450 2f 61 08 00 ba 61 08 00 54 62 08 00 4a 63 08 00 |/a...a..Tb..Jc..|
00000460 2c 64 08 00 8d 64 08 00 58 65 08 00 dc 65 08 00 |,d...d..Xe...e..|
00000470 5c 66 08 00 dc 66 08 00 43 67 08 00 eb 67 08 00 |\f...f..Cg...g..|
00000480 71 68 08 00 f5 68 08 00 9a 69 08 00 5a 6a 08 00 |qh...h...i..Zj..|
00000490 1a 6b 08 00 e5 6c 08 00 3d 76 08 00 42 77 08 00 |.k...l..=v..Bw..|
000004a0 c5 77 08 00 8e 78 08 00 39 79 08 00 15 7a 08 00 |.w...x..9y...z..|
000004b0 f4 7a 08 00 06 7c 08 00 95 7c 08 00 63 7d 08 00 |.z...|...|..c}..|
000004c0 03 7e 08 00 b9 7e 08 00 73 7f 08 00 4b 80 08 00 |.~...~..s...K...|
000004d0 cf 80 08 00 8a 81 08 00 13 82 08 00 a0 82 08 00 |................|
000004e0 6f 83 08 00 1b 84 08 00 ce 84 08 00 9d 85 08 00 |o...............|
000004f0 2a 86 08 00 ee 86 08 00 7f 88 08 00 84 89 08 00 |*...............|
00000500 54 8a 08 00 22 8b 08 00 34 8c 08 00 47 8d 08 00 |T..."...4...G...|
00000510 f7 8d 08 00 7d 8e 08 00 03 8f 08 00 89 8f 08 00 |....}...........|
00000520 0f 90 08 00 95 90 08 00 1b 91 08 00 a0 91 08 00 |................|
00000530 25 92 08 00 aa 92 08 00 2f 93 08 00 b4 93 08 00 |%......./.......|
00000540 39 94 08 00 be 94 08 00 4d 95 08 00 52 96 08 00 |9.......M...R...|
00000550 02 97 08 00 16 98 08 00 b1 99 08 00 35 9a 08 00 |............5...|
00000560 ca 9a 08 00 56 9b 08 00 c2 9c 08 00 dc 9d 08 00 |....V...........|
00000570 8b 9e 08 00 95 9f 08 00 4e a1 08 00 7d a2 08 00 |........N...}...|
00000580 66 a3 08 00 61 a4 08 00 fe a4 08 00 93 a5 08 00 |f...a...........|
00000590 2e a6 08 00 f3 a6 08 00 bb a7 08 00 83 a8 08 00 |................|
000005a0 4b a9 08 00 13 aa 08 00 db aa 08 00 a3 ab 08 00 |K...............|
000005b0 8a ac 08 00 6a ad 08 00 3e ae 08 00 f6 ae 08 00 |....j...>.......|
000005c0 b0 b0 08 00 ab b1 08 00 94 b2 08 00 bb b3 08 00 |................|
000005d0 2a b5 08 00 bf b5 08 00 40 b6 08 00 2f b7 08 00 |*.......@.../...|
000005e0 47 b8 08 00 5f b9 08 00 3c ba 08 00 b7 bb 08 00 |G..._...<.......|
000005f0 a9 bc 08 00 d3 bd 08 00 eb be 08 00 f0 bf 08 00 |................|
00000600 b9 c0 08 00 59 c1 08 00 4b c2 08 00 08 c3 08 00 |....Y...K.......|
00000610 d5 c3 08 00 d6 c4 08 00 36 c6 08 00 86 c7 08 00 |........6.......|
00000620 66 c8 08 00 65 c9 08 00 e3 ca 08 00 d9 cb 08 00 |f...e...........|
00000630 b0 cc 08 00 d0 cd 08 00 6b cf 08 00 4f d0 08 00 |........k...O...|
00000640 33 d1 08 00 0e d2 08 00 2c d5 08 00 72 da 08 00 |3.......,...r...|
00000650 69 db 08 00 88 dd 08 00 99 df 08 00 83 e0 08 00 |i...............|
00000660 3c e3 08 00 c7 e4 08 00 5f e6 08 00 2b e7 08 00 |<......._...+...|
00000670 e6 e8 08 00 9a ea 08 00 40 eb 08 00 e3 ed 08 00 |........@.......|
00000680 59 f5 08 00 85 f6 08 00 bd f7 08 00 ac f8 08 00 |Y...............|
00000690 86 fa 08 00 f4 fb 08 00 83 fd 08 00 9e ff 08 00 |................|
000006a0 0d 01 09 00 e8 01 09 00 9e 03 09 00 50 06 09 00 |............P...|
000006b0 ff 08 09 00 a3 0b 09 00 40 12 09 00 66 14 09 00 |........@...f...|
000006c0 89 15 09 00 1e 17 09 00 76 19 09 00 1f 1b 09 00 |........v.......|
000006d0 ab 1c 09 00 99 1e 09 00 32 20 09 00 77 22 09 00 |........2 ..w"..|
000006e0 e7 25 09 00 a2 27 09 00 46 2a 09 00 8f 36 09 00 |.%...'..F*...6..|
000006f0 d2 38 09 00 65 40 09 00 20 43 09 00 35 46 09 00 |.8..e@.. C..5F..|
00000700 5f 4d 09 00 5f 5b 09 00 46 61 09 00 00 68 09 00 |_M.._[..Fa...h..|
00000710 06 6b 09 00 d6 7e 09 00 e5 9f 09 00 e7 9f 0a 00 |.k...~..........|
00000720 72 b7 0a 00 b5 e4 0a 00 7b eb 0a 00 7e eb 0a 00 |r.......{...~...|
00000730 81 eb 0a 00 85 eb 0a 00 8b eb 0a 00 b2 eb 0a 00 |................|
00000740 b8 eb 0a 00 bd eb 0a 00 cb eb 0a 00 d2 eb 0a 00 |................|
00000750 de eb 0a 00 f9 eb 0a 00 0e ec 0a 00 18 ec 0a 00 |................|
00000760 33 ec 0a 00 4b ec 0a 00 60 ec 0a 00 79 ec 0a 00 |3...K...`...y...|
00000770 8b ec 0a 00 d2 ec 0a 00 1d ed 0a 00 2c ed 0a 00 |............,...|
00000780 49 ed 0a 00 5e ed 0a 00 71 ed 0a 00 95 ed 0a 00 |I...^...q.......|
00000790 9d ed 0a 00 b7 ed 0a 00 c3 ed 0a 00 da ed 0a 00 |................|
000007a0 f0 ed 0a 00 f9 ed 0a 00 02 ee 0a 00 0a ee 0a 00 |................|
000007b0 22 ee 0a 00 2f ee 0a 00 3c ee 0a 00 49 ee 0a 00 |".../...<...I...|
000007c0 5e ee 0a 00 6b ee 0a 00 7c ee 0a 00 86 ee 0a 00 |^...k...|.......|
000007d0 91 ee 0a 00 a1 ee 0a 00 ae ee 0a 00 b7 ee 0a 00 |................|
000007e0 bf ee 0a 00 ce ee 0a 00 d6 ee 0a 00 e1 ee 0a 00 |................|
000007f0 e7 ee 0a 00 f5 ee 0a 00 fd ee 0a 00 0c ef 0a 00 |................|
00000800 17 ef 0a 00 21 ef 0a 00 29 ef 0a 00 3a ef 0a 00 |....!...)...:...|
00000810 53 ef 0a 00 5f ef 0a 00 6a ef 0a 00 7d ef 0a 00 |S..._...j...}...|
00000820 87 ef 0a 00 90 ef 0a 00 9e ef 0a 00 b4 ef 0a 00 |................|
00000830 bb ef 0a 00 c6 ef 0a 00 d2 ef 0a 00 d9 ef 0a 00 |................|
00000840 e8 ef 0a 00 f5 ef 0a 00 fc ef 0a 00 0b f0 0a 00 |................|
00000850 17 f0 0a 00 27 f0 0a 00 2a f0 0a 00 2e f0 0a 00 |....'...*.......|
00000860 32 f0 0a 00 37 f0 0a 00 3c f0 0a 00 41 f0 0a 00 |2...7...<...A...|
00000870 46 f0 0a 00 4b f0 0a 00 67 f0 0a 00 79 f0 0a 00 |F...K...g...y...|
00000880 90 f0 0a 00 a4 f0 0a 00 bd f0 0a 00 d2 f0 0a 00 |................|
00000890 ec f0 0a 00 02 f1 0a 00 17 f1 0a 00 2e f1 0a 00 |................|
000008a0 42 f1 0a 00 58 f1 0a 00 6d f1 0a 00 83 f1 0a 00 |B...X...m.......|
000008b0 9c f1 0a 00 ba f1 0a 00 d4 f1 0a 00 ee f1 0a 00 |................|
dexdump
~/.android-sdk/build-tools/23.0.1/dexdump -d \
./target/android/dex/classes.dex \
> ./target/android/dex/classes.dex.dump
Processing './target/android/dex/classes.dex'...
Opened './target/android/dex/classes.dex', DEX version '035'
Class #0 -
Class descriptor : 'L_00_helloworld/HelloWorldKt;'
Access flags : 0x0011 (PUBLIC FINAL)
Superclass : 'Ljava/lang/Object;'
Interfaces -
Static fields -
Instance fields -
Direct methods -
#0 : (in L_00_helloworld/HelloWorldKt;)
name : 'main'
type : '([Ljava/lang/String;)V'
access : 0x0019 (PUBLIC STATIC FINAL)
code -
registers : 2
ins : 1
outs : 2
insns size : 13 16-bit code units
020494: |[020494] _00_helloworld.HelloWorldKt.main:([Ljava/lang/String;)V
0204a4: 1a00 1310 |0000: const-string v0, "args" // string@1013
0204a8: 7120 a811 0100 |0002: invoke-static {v1, v0}, Lkotlin/jvm/internal/Intrinsics;.checkParameterIsNotNull:(Ljava/lang/Object;Ljava/lang/String;)V // method@11a8
0204ae: 1a01 0808 |0005: const-string v1, "Hello RivieraDev" // string@0808
0204b2: 6200 0c00 |0007: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@000c
0204b6: 6e20 3f00 1000 |0009: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/Object;)V // method@003f
0204bc: 0e00 |000c: return-void
catches : (none)
positions :
0x0007 line=4
locals :
Virtual methods -
source_file_idx : 2057 (HelloWorld.kt)
...
smali
sh ./scripts/lib/dextools/d2j-dex2smali.sh \
./target/android/dex/classes.dex -f \
-o ./target/android/smali
.class public final L_00_helloworld/HelloWorldKt;
.super Ljava/lang/Object;
.source "HelloWorld.kt"
.annotation system Ldalvik/annotation/SourceDebugExtension;
value = "SMAP\nHelloWorld.kt\nKotlin\n*S Kotlin\n*F\n+ 1 HelloWorld.kt\n_00_helloworld/HelloWorldKt\n*L\n1#1,5:1\n*E\n"
.end annotation
.annotation runtime Lkotlin/Metadata;
bv = {
1,
0,
2
}
d1 = {
"\u0000\u0012\n\u0000\n\u0002\u0010\u0002\n\u0000\n\u0002\u0010\u0011\n\u0002\u0010\u000e\n\u0000\u001a\u0019\u0010\u0000\u001a\u00020\u00012\u000c\u0010\u0002\u001a\u0008\u0012\u0004\u0012\u00020\u00040\u0003\u00a2\u0006\u0002\u0010\u0005"
}
d2 = {
"main",
"",
"args",
"",
"",
"([Ljava/lang/String;)V"
}
k = 2
mv = {
1,
1,
9
}
.end annotation
.method public final static main([Ljava/lang/String;)V
.parameter # [Ljava/lang/String;
.annotation build Lorg/jetbrains/annotations/NotNull;
.end annotation
.end parameter
.registers 2
const-string v0, "args"
invoke-static { p0, v0 }, Lkotlin/jvm/internal/Intrinsics;->checkParameterIsNotNull(Ljava/lang/Object;Ljava/lang/String;)V
const-string p0, "Hello RivieraDev"
.line 4
sget-object v0, Ljava/lang/System;->out:Ljava/io/PrintStream;
invoke-virtual { v0, p0 }, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V
return-void
.end method
Autres structures
Autres structures
if-then-else.kt
fun handleAstronomicalBody(body: AstronomicalBody) {
val message =
if (body is Planet && body.name == "Earth") {
"Welcome Earth"
} else {
"Welcome martian"
}
println(message)
}
for.kt
fun main(args: Array<String>) {
for (body in SolarSystem.bodies) { // 🤢
print(body)
}
}
Mais aussi des while
et do while
et des break
, continue
, et label
when.kt
for (body in SolarSystem.bodies) { // 🤢
val message = when (body) {
is Planet -> "Planet ${body.name}"
is Star -> "Star ${body.name}"
else -> null
}
if (message != null) {
println(message)
}
}
for-factorial.kt
// Note: assert(n >= 0)
fun forFactorial(n: Int): Int { // 🤢
var acc = 1
for (i in 1..n) {
acc *= i
}
return acc
}
ByteCode factoriel avec for
Compiled from "for-factorial.kt"
public final class For_factorialKt {
public static final int forFactorial(int);
Code:
0: iconst_1
1: istore_1
2: iconst_1
3: istore_2
4: iload_0
5: istore_3
6: iload_2
7: iload_3
8: if_icmpgt 26
11: iload_1
12: iload_2
13: imul
14: istore_1
15: iload_2
16: iload_3
17: if_icmpeq 26
20: iinc 2, 1
23: goto 11
26: iload_1
27: ireturn
}
rec-factorial.kt
// Note: assert(n >= 0)
fun recFactorial(n: Int): Int =
if (n < 1) 1
else n * recFactorial(n - 1)
ByteCode factoriel avec récursivité
Compiled from "rec-factorial.kt"
public final class Rec_factorialKt {
public static final int recFactorial(int);
Code:
0: iload_0
1: iconst_1
2: if_icmpge 9
5: iconst_1
6: goto 17
9: iload_0
10: iload_0
11: iconst_1
12: isub
13: invokestatic #8 // Method recFactorial:(I)I
16: imul
17: ireturn
}
Récursion non terminale
- `fact(x)`
-
- `x xx fact(x-1)`
-
- `x`
- `x xx (x-1) xx fact(x-2)`
-
- `x - 1`
- `x`
- `x xx (x-1) xx (x-2) xx ...`
-
- ...
- `x - 1`
- `x`
- `x xx (x-1) xx (x-2) xx ... xx 2 xx 1`
-
- `1`
- `2`
- ...
- `x - 1`
- `x`
Récursion terminale
- `fact(x) = fact(x, 1)`
- `fact(x-1, x xx 1)`
- `fact(x-2, x xx (x-1))`
- `fact(... , x xx (x-1) xx (x-2) xx ...)`
- `fact(1, x xx (x-1) xx (x-2) xx ... xx 2)`
-
⚠️ Nécessite une optimisation par le compilateur
tailrec-factorial.kt
// Note: assert(n >= 0)
fun tailRecFactorial(n: Int): Int {
tailrec fun aux(n: Int, acc: Int): Int =
if (n < 1) acc
else aux(n - 1, acc * n)
return aux(n, 1)
}
ByteCode factoriel avec recursivité terminale 1/2
public final class Tailrec_factorialKt {
public static final int tailRecFactorial(int);
Code:
0: getstatic #12 // Field Tailrec_factorialKt$tailRecFactorial$1.INSTANCE:LTailrec_factorialKt$tailRecFactorial$1;
3: astore_1
4: aload_1
5: iload_0
6: iconst_1
7: invokevirtual #16 // Method Tailrec_factorialKt$tailRecFactorial$1.invoke:(II)I
10: ireturn
}
ByteCode factoriel avec recursivité terminale 2/2
Compiled from "tailrec-factorial.kt"
final class Tailrec_factorialKt$tailRecFactorial$1 extends kotlin.jvm.internal.Lambda implements kotlin.jvm.functions.Function2<java.lang.Integer, java.lang.Integer, java.lang.Integer> {
public static final Tailrec_factorialKt$tailRecFactorial$1 INSTANCE;
public java.lang.Object invoke(java.lang.Object, java.lang.Object);
Code:
0: aload_0
1: aload_1
2: checkcast #11 // class java/lang/Number
5: invokevirtual #15 // Method java/lang/Number.intValue:()I
8: aload_2
9: checkcast #11 // class java/lang/Number
12: invokevirtual #15 // Method java/lang/Number.intValue:()I
15: invokevirtual #18 // Method invoke:(II)I
18: invokestatic #24 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
21: areturn
public final int invoke(int, int);
Code:
0: iload_1
1: iconst_1
2: if_icmpge 9
5: iload_2
6: goto 25
9: aload_0
10: checkcast #2 // class Tailrec_factorialKt$tailRecFactorial$1
13: pop
14: iload_1
15: iconst_1
16: isub
17: iload_2
18: iload_1
19: imul
20: istore_2
21: istore_1
22: goto 0
25: ireturn
Tailrec_factorialKt$tailRecFactorial$1();
Code:
0: aload_0
1: iconst_2
2: invokespecial #34 // Method kotlin/jvm/internal/Lambda."<init>":(I)V
5: return
static {};
Code:
0: new #2 // class Tailrec_factorialKt$tailRecFactorial$1
3: dup
4: invokespecial #56 // Method "<init>":()V
7: putstatic #58 // Field INSTANCE:LTailrec_factorialKt$tailRecFactorial$1;
10: return
}
Performances sur 10!
Bilan structures
-
when
peut être utilisé avec -
-
des constantes
-
plusieurs valeurs séparées par
,
-
une expression
-
avec
is
et un type (avec un 'smart cast')
-
-
privilégier les
when
si vous avez plus de 2 cassi vous faites des fonctions récursives, faites les
tailrec
Extensions de fonctions
Extensions de fonctions
extension.kt
val AstronomicalBody.size: Int
get() = name.length
fun AstronomicalBody.display() = "Body $name $size"
fun main(args: Array<String>) {
SolarSystem.bodies
.forEach { println(it.display()) }
}
extension.java
import java.util.Iterator;
import kotlin.Metadata;
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;
@Metadata(
mv = {1, 1, 15},
bv = {1, 0, 3},
k = 2,
d1 = {"\u0000 \n\u0000\n\u0002\u0010\b\n\u0002\u0018\u0002\n\u0002\b\u0003\n\u0002\u0010\u0002\n\u0000\n\u0002\u0010\u0011\n\u0002\u0010\u000e\n\u0002\b\u0003\u001a\u0019\u0010\u0005\u001a\u00020\u00062\f\u0010\u0007\u001a\b\u0012\u0004\u0012\u00020\t0\b¢\u0006\u0002\u0010\n\u001a\n\u0010\u000b\u001a\u00020\t*\u00020\u0002\"\u0015\u0010\u0000\u001a\u00020\u0001*\u00020\u00028F¢\u0006\u0006\u001a\u0004\b\u0003\u0010\u0004¨\u0006\f"},
d2 = {"size", "", "LAstronomicalBody;", "getSize", "(LAstronomicalBody;)I", "main", "", "args", "", "", "([Ljava/lang/String;)V", "display", "kotlinDee"}
)
public final class ExtensionKt {
public static final int getSize(@NotNull AstronomicalBody $this$size) {
Intrinsics.checkParameterIsNotNull($this$size, "$this$size");
return $this$size.getName().length();
}
@NotNull
public static final String display(@NotNull AstronomicalBody $this$display) {
Intrinsics.checkParameterIsNotNull($this$display, "$this$display");
return "Body " + $this$display.getName() + ' ' + getSize($this$display);
}
public static final void main(@NotNull String[] args) {
Intrinsics.checkParameterIsNotNull(args, "args");
Iterable $this$forEach$iv = (Iterable)SolarSystem.INSTANCE.getBodies();
int $i$f$forEach = false;
Iterator var3 = $this$forEach$iv.iterator();
while(var3.hasNext()) {
Object element$iv = var3.next();
AstronomicalBody it = (AstronomicalBody)element$iv;
int var6 = false;
String var7 = display(it);
boolean var8 = false;
System.out.println(var7);
}
}
}
Extension
-
Permet d'enrichir les APIs Java
-
Permet la SoC (Separation of Concerns)
Les collections
Les collections
Collections
Les Maps
api.kt
val s = SolarSystem.bodies
.filterIsInstance<Planet>()
.flatMap { planet -> planet.moons } // 😻
.filterNot { it.name.startsWith("S/") }
.sortedBy { it.name }
// .fold("") { acc, moon ->
// (if (acc == "") "" else "$acc,\n") + moon.name
// }
.joinToString(",\n") { it.name }
println(s)
break-immutable.kt
fun main(args: Array<String>) {
val moons = (1..9).map { Moon("Moon #$it") }.toList()
println(moons.javaClass) // class java.util.ArrayList
moons.javaClass.methods
.find { it.name == "add" && it.parameterCount == 1 }
?.invoke(moons, Moon("XXX"))
println(moons.joinToString("\n"))
// Moon(name=Moon #1)
// Moon(name=Moon #2)
// Moon(name=Moon #3)
// Moon(name=Moon #4)
// Moon(name=Moon #5)
// Moon(name=Moon #6)
// Moon(name=Moon #7)
// Moon(name=Moon #8)
// Moon(name=Moon #9)
// Moon(name=XXX)
}
sequence.kt
val s = SolarSystem.bodies.asSequence()
.filterIsInstance<Planet>()
.flatMap { planet -> planet.moons.asSequence() } // 😻
.filterNot { it.name.startsWith("S/") }
.sortedBy { it.name }
.joinToString(",\n") { it.name }
println(s)
Performance des séquences 1/2
Benchmark | Mode | Cnt | Score | Error | Units |
---|---|---|---|---|---|
ApiClassic | thrpt | 200 | 44535.029 | 3550.944 | ops/s |
ApiSequence | thrpt | 200 | 23652.238 | 1967.535 | ops/s |
sequence2.kt
val s = SolarSystem.bodies.asSequence()
.filterIsInstance<Planet>()
.flatMap { planet -> planet.moons.asSequence() } // 😻
.filterNot { it.name.startsWith("S/") }
.map { it.name }
.first()
println(s)
Performance des séquences 2/2
Benchmark | Mode | Cnt | Score | Error | Units |
---|---|---|---|---|---|
ApiClassicFirst | thrpt | 200 | 241752.062 | 5022.663 | ops/s |
ApiSequenceFirst | thrpt | 200 | 3615451.391 | 454502.198 | ops/s |
Bilan collection
-
💪 Super on a de l'immutabilité, des
map
,flatMap
,fold
,aggregate
,... -
🤨 Mais ça reste des collections Java
-
API standard avec
Range
,Pair
, etTriple
-
📏 Avant d'utiliser les
Sequence
, faites des mesures
Les delegates
Les delegates
delegate.kt
import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KProperty
fun main(args: Array<String>) {
val value: String by MyDelegateClass()
println(value)
}
class MyDelegateClass : ReadOnlyProperty<Nothing?, String> {
override operator fun getValue(thisRef: Nothing?,
property: KProperty<*>) = "Hello RivieraDev"
}
lazy.kt
object DeepThought {
fun answer(): Int {
print("Computing ...")
return 42
}
}
fun main() {
val ultimateQuestionOfLife: Int by lazy {
DeepThought.answer()
}
println("The Ultimate Question of Life, " +
"the Universe and Everything ?")
println("Answer: $ultimateQuestionOfLife" )
}
observable.kt
import kotlin.properties.Delegates
fun main(args: Array<String>) {
var observable: String by Delegates.observable("Initial value") {
_, old, new ->
println("$old -> $new")
}
observable = "new value"
}
lateinit.kt
object Plop {
lateinit var str: String
fun info() {
println(Plop::str.isInitialized)
}
}
fun main() {
Plop.info() // false
Plop.str = "Hello"
Plop.info() // true
println(str) // Hello
}
Delegate
-
Lazy
: utile pour les propriétés qui ne sont pas systématiquement utilisées. -
À manipuler avec précaution dans les activités Android ( avec le cycle de vie, cela peut référencer une ancienne instance)
-
Delegate
: Observable, Not null, ... -
lateinit
: évite les null check pour les propriétés qui ne peuvent être initialisées immédiatement (ex: référence de vues surActivity
,Fragment
). -
Ne peut pas être utilisé avec les types primitifs
inline
inline
inline.kt
object Logger {
var enable: Boolean = false
inline fun log(msg: () -> String) {
if (enable) {
println(msg())
}
}
}
fun main() {
Logger.log { "Hello" }
}
Logger.java
Compiled from "inline-fun.kt"
public final class Inline_funKt {
public static final void main();
Code:
0: getstatic #15 // Field Logger.INSTANCE:LLogger;
3: astore_0
4: iconst_0
5: istore_1
6: aload_0
7: invokevirtual #19 // Method Logger.getEnable:()Z
10: ifeq 27
13: iconst_0
14: istore_2
15: ldc #21 // String Hello
17: astore_2
18: iconst_0
19: istore_3
20: getstatic #27 // Field java/lang/System.out:Ljava/io/PrintStream;
23: aload_2
24: invokevirtual #33 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
27: nop
28: return
public static void main(java.lang.String[]);
Code:
0: invokestatic #9 // Method main:()V
3: return
}
reified.kt
class Pojo {
var name: String? = null
override fun toString() = "Pojo $name"
}
object JavaBeanBuilder {
fun <T> createBean(clazz: Class<T>): T =
clazz.newInstance()
inline fun <reified T> createBean(): T =
createBean(T::class.java)
}
fun main(args: Array<String>) {
val p1 = Pojo()
p1.name = "Plop1"
println(p1)
val p2 = JavaBeanBuilder.createBean<Pojo>()
p2.name = "Plop2"
println(p2)
}
reified.java
import kotlin.Metadata;
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;
@Metadata(
mv = {1, 1, 15},
bv = {1, 0, 3},
k = 2,
d1 = {"\u0000\u0014\n\u0000\n\u0002\u0010\u0002\n\u0000\n\u0002\u0010\u0011\n\u0002\u0010\u000e\n\u0002\b\u0002\u001a\u0019\u0010\u0000\u001a\u00020\u00012\f\u0010\u0002\u001a\b\u0012\u0004\u0012\u00020\u00040\u0003¢\u0006\u0002\u0010\u0005¨\u0006\u0006"},
d2 = {"main", "", "args", "", "", "([Ljava/lang/String;)V", "kotlinDee"}
)
public final class ReifiedKt {
public static final void main(@NotNull String[] args) {
Intrinsics.checkParameterIsNotNull(args, "args");
Pojo p1 = new Pojo();
p1.setName("Plop1");
boolean var2 = false;
System.out.println(p1);
JavaBeanBuilder this_$iv = JavaBeanBuilder.INSTANCE;
int $i$f$createBean = false;
Pojo p2 = (Pojo)this_$iv.createBean(Pojo.class);
p2.setName("Plop2");
boolean var6 = false;
System.out.println(p2);
}
}
geoloc.kt
inline class Latitude(val value: Double)
inline class Longitude(val value: Double)
data class Geoloc(val lat: Latitude, val lng: Longitude) {
infix fun distanceTo(other: Geoloc): Double = TODO()
}
fun main() {
val toulouse = Geoloc(Latitude(43.60426), Longitude(1.44367))
val nice = Geoloc(Latitude(43.70313), Longitude(7.26608))
val travel = toulouse distanceTo nice
println(travel)
}
geoloc bytecode
Compiled from "geoloc.kt"
public final class Geoloc {
public final double distanceTo(Geoloc);
Code:
0: aload_1
1: ldc #9 // String other
3: invokestatic #15 // Method kotlin/jvm/internal/Intrinsics.checkParameterIsNotNull:(Ljava/lang/Object;Ljava/lang/String;)V
6: iconst_0
7: istore_2
8: new #17 // class kotlin/NotImplementedError
11: dup
12: aconst_null
13: iconst_1
14: aconst_null
15: invokespecial #21 // Method kotlin/NotImplementedError."<init>":(Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
18: checkcast #23 // class java/lang/Throwable
21: athrow
public final double getLat();
Code:
0: aload_0
1: getfield #31 // Field lat:D
4: dreturn
public final double getLng();
Code:
0: aload_0
1: getfield #35 // Field lng:D
4: dreturn
public Geoloc(double, double, kotlin.jvm.internal.DefaultConstructorMarker);
Code:
0: aload_0
1: dload_1
2: dload_3
3: invokespecial #42 // Method "<init>":(DD)V
6: return
}
Bilan inline
-
⚠️ les
inline
,reified
, ... sont à manier avec précaution -
⚠️ les
inline class
sont encore expérimentales
Coroutines
Coroutines
Callback hell problem
fun main(param: Int): Int {
val step1Result = step1(param)
return step2(step1Result)
}
Utilisons un callback
-
fun main(param: Int): Int { val step1Result = step1(param) return step2(step1Result) }
- `=>`
-
fun main(param: Int): Int { return step1(param) { step1Result -> step2(step1Result) }
Ajoutons une étape
-
fun main(param: Int): Int { val step1Result = step1(param) val step2Result = step2(step1Result) return step3Result = step3(step2Result) }
- `=>`
-
fun main(param: Int): Int { return step1(param) { step1Result -> step2(step1Result) { step2Result -> step3(step2Result) } }
suspend
suspend fun main(param: Int): Int {
val step1Result = step1(param)
val step2Result = step2(step1Result)
return step3Result = step3(step2Result)
}
Continuation
suspend fun step2(step1Result: Int): Int = TODO()
import kotlin.Metadata;
import kotlin.NotImplementedError;
import kotlin.coroutines.Continuation;
import kotlin.jvm.internal.DefaultConstructorMarker;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@Metadata(
mv = {1, 1, 15},
bv = {1, 0, 3},
k = 2,
d1 = {"\u0000\n\n\u0000\n\u0002\u0010\b\n\u0002\b\u0003\u001a\u0019\u0010\u0000\u001a\u00020\u00012\u0006\u0010\u0002\u001a\u00020\u0001H\u0086@ø\u0001\u0000¢\u0006\u0002\u0010\u0003\u0082\u0002\u0004\n\u0002\b\u0019¨\u0006\u0004"},
d2 = {"step2", "", "step1Result", "(ILkotlin/coroutines/Continuation;)Ljava/lang/Object;", "devoxxfr"}
)
public final class BaseKt {
@Nullable
public static final Object step2(int step1Result, @NotNull Continuation $completion) {
boolean var2 = false;
throw (Throwable)(new NotImplementedError((String)null, 1, (DefaultConstructorMarker)null));
}
}
API Continuation Plus sur les coroutines
-
Channel (expérimental)
-
Context
-
dispatchers
-
Jobs
-
Scope
On atteind les limites du décompilateur
Conclusion
Conclusion
Android
-
Faible surcharge
-
Support officiel par Google
Serveur
Web et Natif
🕸 Web
- Partager du code commun
-
De l'espoir avec dukat
Natif
- Faire des applications sans JVM
- Partager du code avec iOS
- WebAssembly
Bilan
-
💎 JVM
-
😎 Le byte code c'est cool
-
🔮 Généralement, ça ne suffit pas pour prédire les performances
-
📏 Mesurez !
Tendance
Kotlin vs Java
-
C'est déjà mature
-
✊ Code plus expressif, plus sûr, plus simple
-
🤝 Interopérable avec Java
-
👍 Outillage (éditeur, gradle, maven)
-
👍 Ecosystème et communauté
-
🚀 Évolution rapide
-
🐣 Code multiplatform
-
Kotlin réussit une belle alchimie entre pragmatisme, puissance, sûreté, accessibilité.