Deep Dive Kotlin :
du Hello World au ByteCode
Speakers
đș Roadmap
- 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
- Un peu plus sur les fonctions
- Conclusion
ByteCode Java ?
javac
HelloWorld.java
package _00_helloworld;
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello Devoxx");
}
}
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 |........()|
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 Devoxx
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éfix 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étiques 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
- asm
Soyez curieux, regardez comment ça marche avec
javap -c
!
Introduction Kotlin
Historique
-
2011 - 2015
Dévoilé par JetBrains
-
2016
v1.0
Support annoncé par Spring
-
2017
v1.1 : coroutines, JS, ...
Support annoncé par Google
v1.2 : multiplatform
-
2018
Kotlin Native 0.6
v1.3 ?
- ...
Cibles
JVM et Android
JavaScript
Native avec LLVM
HelloWorld.kt
package _00_helloworld
fun main(args: Array<String>) {
println("Hello Devoxx")
}
kotlinc HelloWorld.kt
kotlinc
hexdump
00000000 ca fe ba be 00 00 00 32 00 33 01 00 1b 5f 30 30 |.......2.3..._00|
00000010 5f 68 65 6c 6c 6f 77 6f 72 6c 64 2f 48 65 6c 6c |_helloworld/Hell|
00000020 6f 57 6f 72 6c 64 4b 74 07 00 01 01 00 10 6a 61 |oWorldKt......ja|
00000030 76 61 2f 6c 61 6e 67 2f 4f 62 6a 65 63 74 07 00 |va/lang/Object..|
00000040 03 01 00 04 6d 61 69 6e 01 00 16 28 5b 4c 6a 61 |....main...([Lja|
00000050 76 61 2f 6c 61 6e 67 2f 53 74 72 69 6e 67 3b 29 |va/lang/String;)|
00000060 56 01 00 23 4c 6f 72 67 2f 6a 65 74 62 72 61 69 |V..#Lorg/jetbrai|
00000070 6e 73 2f 61 6e 6e 6f 74 61 74 69 6f 6e 73 2f 4e |ns/annotations/N|
00000080 6f 74 4e 75 6c 6c 3b 01 00 04 61 72 67 73 08 00 |otNull;...args..|
00000090 08 01 00 1e 6b 6f 74 6c 69 6e 2f 6a 76 6d 2f 69 |....kotlin/jvm/i|
000000a0 6e 74 65 72 6e 61 6c 2f 49 6e 74 72 69 6e 73 69 |nternal/Intrinsi|
000000b0 63 73 07 00 0a 01 00 17 63 68 65 63 6b 50 61 72 |cs......checkPar|
000000c0 61 6d 65 74 65 72 49 73 4e 6f 74 4e 75 6c 6c 01 |ameterIsNotNull.|
000000d0 00 27 28 4c 6a 61 76 61 2f 6c 61 6e 67 2f 4f 62 |.'(Ljava/lang/Ob|
000000e0 6a 65 63 74 3b 4c 6a 61 76 61 2f 6c 61 6e 67 2f |ject;Ljava/lang/|
000000f0 53 74 72 69 6e 67 3b 29 56 0c 00 0c 00 0d 0a 00 |String;)V.......|
00000100 0b 00 0e 01 00 0c 48 65 6c 6c 6f 20 44 65 76 6f |......Hello Devo|
00000110 78 78 08 00 10 01 00 10 6a 61 76 61 2f 6c 61 6e |xx......java/lan|
00000120 67 2f 53 79 73 74 65 6d 07 00 12 01 00 03 6f 75 |g/System......ou|
00000130 74 01 00 15 4c 6a 61 76 61 2f 69 6f 2f 50 72 69 |t...Ljava/io/Pri|
00000140 6e 74 53 74 72 65 61 6d 3b 0c 00 14 00 15 09 00 |ntStream;.......|
00000150 13 00 16 01 00 13 6a 61 76 61 2f 69 6f 2f 50 72 |......java/io/Pr|
00000160 69 6e 74 53 74 72 65 61 6d 07 00 18 01 00 07 70 |intStream......p|
00000170 72 69 6e 74 6c 6e 01 00 15 28 4c 6a 61 76 61 2f |rintln...(Ljava/|
00000180 6c 61 6e 67 2f 4f 62 6a 65 63 74 3b 29 56 0c 00 |lang/Object;)V..|
00000190 1a 00 1b 0a 00 19 00 1c 01 00 13 5b 4c 6a 61 76 |...........[Ljav|
000001a0 61 2f 6c 61 6e 67 2f 53 74 72 69 6e 67 3b 01 00 |a/lang/String;..|
000001b0 11 4c 6b 6f 74 6c 69 6e 2f 4d 65 74 61 64 61 74 |.Lkotlin/Metadat|
000001c0 61 3b 01 00 02 6d 76 03 00 00 00 01 03 00 00 00 |a;...mv.........|
000001d0 09 01 00 02 62 76 03 00 00 00 00 03 00 00 00 02 |....bv..........|
000001e0 01 00 01 6b 01 00 02 64 31 01 00 35 c0 80 12 0a |...k...d1..5....|
000001f0 c0 80 0a 02 10 02 0a c0 80 0a 02 10 11 0a 02 10 |................|
00000200 0e 0a c0 80 1a 19 10 c0 80 1a 02 30 01 32 0c 10 |...........0.2..|
00000210 02 1a 08 12 04 12 02 30 04 30 03 c2 a2 06 02 10 |.......0.0......|
00000220 05 01 00 02 64 32 01 00 00 01 00 0d 48 65 6c 6c |....d2......Hell|
00000230 6f 57 6f 72 6c 64 2e 6b 74 01 00 04 43 6f 64 65 |oWorld.kt...Code|
00000240 01 00 12 4c 6f 63 61 6c 56 61 72 69 61 62 6c 65 |...LocalVariable|
00000250 54 61 62 6c 65 01 00 0f 4c 69 6e 65 4e 75 6d 62 |Table...LineNumb|
00000260 65 72 54 61 62 6c 65 01 00 24 52 75 6e 74 69 6d |erTable..$Runtim|
00000270 65 49 6e 76 69 73 69 62 6c 65 50 61 72 61 6d 65 |eInvisibleParame|
00000280 74 65 72 41 6e 6e 6f 74 61 74 69 6f 6e 73 01 00 |terAnnotations..|
00000290 0a 53 6f 75 72 63 65 46 69 6c 65 01 00 14 53 6f |.SourceFile...So|
000002a0 75 72 63 65 44 65 62 75 67 45 78 74 65 6e 73 69 |urceDebugExtensi|
000002b0 6f 6e 01 00 19 52 75 6e 74 69 6d 65 56 69 73 69 |on...RuntimeVisi|
000002c0 62 6c 65 41 6e 6e 6f 74 61 74 69 6f 6e 73 00 31 |bleAnnotations.1|
000002d0 00 02 00 04 00 00 00 00 00 01 00 19 00 05 00 06 |................|
000002e0 00 02 00 2c 00 00 00 3f 00 02 00 02 00 00 00 11 |...,...?........|
000002f0 2a 12 09 b8 00 0f 12 11 4c b2 00 17 2b b6 00 1d |*.......L...+...|
00000300 b1 00 00 00 02 00 2d 00 00 00 0c 00 01 00 00 00 |......-.........|
00000310 11 00 08 00 1e 00 00 00 2e 00 00 00 0a 00 02 00 |................|
00000320 06 00 04 00 10 00 05 00 2f 00 00 00 07 01 00 01 |......../.......|
00000330 00 07 00 00 00 03 00 30 00 00 00 02 00 2b 00 31 |.......0.....+.1|
00000340 00 00 00 63 53 4d 41 50 0a 48 65 6c 6c 6f 57 6f |...cSMAP.HelloWo|
00000350 72 6c 64 2e 6b 74 0a 4b 6f 74 6c 69 6e 0a 2a 53 |rld.kt.Kotlin.*S|
00000360 20 4b 6f 74 6c 69 6e 0a 2a 46 0a 2b 20 31 20 48 | Kotlin.*F.+ 1 H|
00000370 65 6c 6c 6f 57 6f 72 6c 64 2e 6b 74 0a 5f 30 30 |elloWorld.kt._00|
00000380 5f 68 65 6c 6c 6f 77 6f 72 6c 64 2f 48 65 6c 6c |_helloworld/Hell|
00000390 6f 57 6f 72 6c 64 4b 74 0a 2a 4c 0a 31 23 31 2c |oWorldKt.*L.1#1,|
000003a0 35 3a 31 0a 2a 45 0a 00 32 00 00 00 46 00 01 00 |5:1.*E..2...F...|
000003b0 1f 00 05 00 20 5b 00 03 49 00 21 49 00 21 49 00 |.... [..I.!I.!I.|
000003c0 22 00 23 5b 00 03 49 00 21 49 00 24 49 00 25 00 |".#[..I.!I.$I.%.|
000003d0 26 49 00 25 00 27 5b 00 01 73 00 28 00 29 5b 00 |&I.%.'[..s.(.)[.|
000003e0 06 73 00 05 73 00 2a 73 00 08 73 00 2a 73 00 2a |.s..s.*s..s.*s.*|
000003f0 73 00 06 |s..|
000003f3
Java ByteCode
Compiled from "HelloWorld.kt"
public final class _00_helloworld.HelloWorldKt {
public static final void main(java.lang.String[]);
Code:
0: aload_0
1: ldc #9 // String args
3: invokestatic #15 // Method kotlin/jvm/internal/Intrinsics.checkParameterIsNotNull:(Ljava/lang/Object;Ljava/lang/String;)V
6: ldc #17 // String Hello Devoxx
8: astore_1
9: getstatic #23 // Field java/lang/System.out:Ljava/io/PrintStream;
12: aload_1
13: invokevirtual #29 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
16: return
}
HelloWorld-java
package _00_helloworld;
import kotlin.Metadata;
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;
@Metadata(
mv = {1, 1, 9},
bv = {1, 0, 2},
k = 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\f\u0010\u0002\u001a\b\u0012\u0004\u0012\u00020\u00040\u0003Âą\u0006\u0002\u0010\u0005"},
d2 = {"main", "", "args", "", "", "([Ljava/lang/String;)V"}
)
public final class HelloWorldKt {
public static final void main(@NotNull String[] args) {
Intrinsics.checkParameterIsNotNull(args, "args");
String var1 = "Hello Devoxx";
System.out.println(var1);
}
}
Bilan HelloWorld.kt
- đźââïž Kotlin ajoute des contrĂŽles
- du coup on a besoin de JARs en plus
jar | taille |
---|---|
kotlin-stdlib-1.2.31.jar | 919K |
kotlin-stdlib-jdk7-1.2.31.jar | 3.1K |
kotlin-stdlib-jdk8-1.2.31.jar | 13K |
kotlin-reflect-1.2.31.jar | 2.5M |
guava-18.0.jar | 2.2M |
lombok-1.16.18.jar | 1.4M |
spring-core-5.0.5.RELEASE.jar | 1.2M |
jackson-databind-2.9.5.jar | 1.3M |
- đ Performances ?
Performance HelloWorld.kt
Ne croyez pas les benchmarks, faites les vous-mĂȘme !
Benchmark | Mode | Cnt | Score | Error | Units |
---|---|---|---|---|---|
testJava | thrpt | 200 | 66490.271 | ± 879.996 | ops/s |
testKotlin | thrpt | 200 | 72393.914 | ± 935.962 | ops/s |
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}!")
}
string-template.java
package _01_basic;
import kotlin.Metadata;
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;
@Metadata(
mv = {1, 1, 9},
bv = {1, 0, 2},
k = 2,
d1 = {"\u0000\f\n\u0000\n\u0002\u0010\u0002\n\u0000\n\u0002\u0018\u0002\u001a\u000e\u0010\u0000\u001a\u00020\u00012\u0006\u0010\u0002\u001a\u00020\u0003"},
d2 = {"greeting", "", "who", "L_01_basic/Someone;"}
)
public final class String_templatesKt {
public static final void greeting(@NotNull Someone who) {
Intrinsics.checkParameterIsNotNull(who, "who");
String var1 = "Hello " + who + '!';
System.out.println(var1);
var1 = "Hello " + who.getFirstName() + ' ' + who.getLastName() + '!';
System.out.println(var1);
}
}
ByteCode de string-template
Compiled from "string-templates.kt"
public final class _01_basic.String_templatesKt {
public static final void greeting(_01_basic.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: getstatic #43 // Field java/lang/System.out:Ljava/io/PrintStream;
34: aload_1
35: invokevirtual #49 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
38: new #17 // class java/lang/StringBuilder
41: dup
42: invokespecial #21 // Method java/lang/StringBuilder."<init>":()V
45: ldc #23 // String Hello
47: invokevirtual #27 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
50: aload_0
51: invokevirtual #54 // Method _01_basic/Someone.getFirstName:()Ljava/lang/String;
54: invokevirtual #27 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
57: bipush 32
59: invokevirtual #33 // Method java/lang/StringBuilder.append:(C)Ljava/lang/StringBuilder;
62: aload_0
63: invokevirtual #57 // Method _01_basic/Someone.getLastName:()Ljava/lang/String;
66: invokevirtual #27 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
69: bipush 33
71: invokevirtual #33 // Method java/lang/StringBuilder.append:(C)Ljava/lang/StringBuilder;
74: invokevirtual #37 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
77: astore_1
78: getstatic #43 // Field java/lang/System.out:Ljava/io/PrintStream;
81: aload_1
82: invokevirtual #49 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
85: return
}
numeric.kt
val anInt = 42 // type inference: Int
val aLong = 42L // type inference: Long
var aDouble: Double? = null
numeric.java
package _01_basic;
import kotlin.Metadata;
@Metadata(
mv = {1, 1, 9},
bv = {1, 0, 2},
k = 2,
d1 = {"\u0000\u0006\n\u0000\n\u0002\u0010\u0002\u001a\u0006\u0010\u0000\u001a\u00020\u0001"},
d2 = {"tryNumeric", ""}
)
public final class NumericKt {
public static final void tryNumeric() {
int anInt = true;
long aLong = 42L;
Double aDouble = (Double)null;
}
}
ByteCode de numeric
Compiled from "numeric.kt"
public final class _01_basic.NumericKt {
public static final void tryNumeric();
Code:
0: bipush 42
2: istore_0
3: ldc2_w #7 // long 42l
6: lstore_1
7: aconst_null
8: checkcast #10 // class java/lang/Double
11: astore_3
12: 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
billion-dollar mistake
Null References: The Billion Dollar MistakeI call it my billion-dollar mistake. It was the invention of the
null
reference in 1965. At that time, I was designing the first comprehensive type system for references in an object oriented language (ALGOL W). My goal was to ensure that all use of references should be absolutely safe, with checking performed automatically by the compiler. But I couldn't resist the temptation to put in anull
reference, simply because it was so easy to implement. 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(args: Array<String>) {
val somethingNotNull: String = "aString"
// somethingNotNull: String = null => compilation error
var length = somethingNotNull.length
var something: String? = null
length = something?.length ?: 0
length = something()?.length ?: 0
// length = something()!!.length // throw kotlin.KotlinNullPointerException
// SmartCast
something = "aString"
length = something.length
}
fun something(): String? = null
null-safety.java
package _02_null_safety;
import kotlin.Metadata;
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@Metadata(
mv = {1, 1, 9},
bv = {1, 0, 2},
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\u001a\b\u0010\u0006\u001a\u0004\u0018\u00010\u0004"},
d2 = {"main", "", "args", "", "", "([Ljava/lang/String;)V", "something"}
)
public final class NullSafetyKt {
public static final void main(@NotNull String[] args) {
Intrinsics.checkParameterIsNotNull(args, "args");
String somethingNotNull = "aString";
int length = somethingNotNull.length();
String something = (String)null;
int length = false;
String var10000 = something();
length = var10000 != null ? var10000.length() : 0;
var10000 = something();
if (var10000 == null) {
Intrinsics.throwNpe();
}
length = var10000.length();
something = "aString";
length = something.length();
}
@Nullable
public static final String something() {
return null;
}
}
Bilan null-safety
- đž Elvis operator:
?:
- đ plus de
NullPointerException
- â ïž quand on appel du Java
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`()}")
}
Hierarchie des types
- đ€ le
TODO()
est l'ami du TDD
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 = "Devoxx", prefix = "Hello")
named-params.java
package _03_fun;
import kotlin.Metadata;
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;
@Metadata(
mv = {1, 1, 9},
bv = {1, 0, 2},
k = 2,
d1 = {"\u0000\u0010\n\u0000\n\u0002\u0010\u000e\n\u0002\b\u0003\n\u0002\u0010\u000b\n\u0000\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"},
d2 = {"buildString", "", "prefix", "who", "enhanced", "", "greetings"}
)
public final class NamedKt {
@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 = "Devoxx";
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 = "Devoxx")
default-value.java
package _03_fun;
import kotlin.Metadata;
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;
@Metadata(
mv = {1, 1, 9},
bv = {1, 0, 2},
k = 2,
d1 = {"\u0000\u0010\n\u0000\n\u0002\u0010\u000e\n\u0002\b\u0003\n\u0002\u0010\u000b\n\u0000\u001a\"\u0010\u0000\u001a\u00020\u00012\b\b\u0002\u0010\u0002\u001a\u00020\u00012\u0006\u0010\u0003\u001a\u00020\u00012\b\b\u0002\u0010\u0004\u001a\u00020\u0005\u001a\u0006\u0010\u0006\u001a\u00020\u0001"},
d2 = {"buildString2", "", "prefix", "who", "enhanced", "", "greetings2"}
)
public final class Default_valueKt {
@NotNull
public static final String buildString2(@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 greetings2() {
return buildString2$default((String)null, "Devoxx", false, 5, (Object)null);
}
}
ByteCode de default-value
Compiled from "default-value.kt"
public final class _03_fun.Default_valueKt {
public static final java.lang.String buildString2(java.lang.String, java.lang.String, boolean);
Code:
0: aload_0
1: ldc #9 // String prefix
3: invokestatic #15 // Method kotlin/jvm/internal/Intrinsics.checkParameterIsNotNull:(Ljava/lang/Object;Ljava/lang/String;)V
6: aload_1
7: ldc #17 // String who
9: invokestatic #15 // Method kotlin/jvm/internal/Intrinsics.checkParameterIsNotNull:(Ljava/lang/Object;Ljava/lang/String;)V
12: new #19 // class java/lang/StringBuilder
15: dup
16: invokespecial #23 // Method java/lang/StringBuilder."<init>":()V
19: ldc #25 // String
21: invokevirtual #29 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
24: aload_0
25: invokevirtual #29 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
28: bipush 32
30: invokevirtual #32 // Method java/lang/StringBuilder.append:(C)Ljava/lang/StringBuilder;
33: aload_1
34: invokevirtual #29 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
37: invokevirtual #36 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
40: astore_3
41: iload_2
42: ifeq 66
45: aload_3
46: new #19 // class java/lang/StringBuilder
49: dup
50: invokespecial #23 // Method java/lang/StringBuilder."<init>":()V
53: swap
54: invokevirtual #29 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
57: bipush 33
59: invokevirtual #32 // Method java/lang/StringBuilder.append:(C)Ljava/lang/StringBuilder;
62: invokevirtual #36 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
65: astore_3
66: aload_3
67: areturn
public static java.lang.String buildString2$default(java.lang.String, java.lang.String, boolean, int, java.lang.Object);
Code:
0: iload_3
1: iconst_1
2: iand
3: ifeq 9
6: ldc #46 // String Hello
8: astore_0
9: iload_3
10: iconst_4
11: iand
12: ifeq 17
15: iconst_1
16: istore_2
17: aload_0
18: aload_1
19: iload_2
20: invokestatic #48 // Method buildString2:(Ljava/lang/String;Ljava/lang/String;Z)Ljava/lang/String;
23: areturn
public static final java.lang.String greetings2();
Code:
0: aconst_null
1: ldc #51 // String Devoxx
3: iconst_0
4: iconst_5
5: aconst_null
6: invokestatic #53 // Method buildString2$default:(Ljava/lang/String;Ljava/lang/String;ZILjava/lang/Object;)Ljava/lang/String;
9: areturn
}
C'est fun
!
âš Conseils
- Toujours typer le retour de vos fonctions
(sauf si c'est Ă©vident et une surcharge comme le
toString
) - Kotlin est plus expressif 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
đ Notes
- Le passage des arguments par nom, ne marche pas sur les appels de code Java
Les lambdas
function.kt
// Declare apply function with function as parameter
fun apply(x: Int, y: Int, operation: (Int, Int) -> Int): Int =
operation(x, y)
// Declare function
fun sumf(x: Int, y: Int) : Int =
x + y
// call apply with function reference
val sum5 = apply(2,3, ::sumf)
// store function reference
val sumLam = ::sumf
// call apply with the function reference
val sum6 = apply(1,5, sumLam)
function.java
package _04_lamda;
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, 9},
bv = {1, 0, 2},
k = 2,
d1 = {"\u0000\u001c\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\u0000\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"},
d2 = {"sum5", "", "getSum5", "()I", "sum6", "getSum6", "sumLam", "Lkotlin/reflect/KFunction2;", "Lkotlin/ParameterName;", "name", "x", "y", "getSumLam", "()Lkotlin/reflect/KFunction;", "apply", "operation", "Lkotlin/Function2;", "sumf"}
)
public final class FunctionKt {
private static final int sum5;
@NotNull
private static final KFunction sumLam;
private static final int sum6;
public static final int apply(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 = apply(2, 3, (Function2)null.INSTANCE);
sumLam = null.INSTANCE;
sum6 = apply(1, 5, (Function2)sumLam);
}
}
lambda.kt
// Declare lambda
val suml: (Int, Int) -> Int = { x: Int, y: Int -> x + y }
// call apply with suml lambda
val sum3 = apply(1, 2, suml)
// call apply with lamda
val sum4 = apply(1, 3) { x, y -> x + y }
lambda.java
package _04_lamda;
import kotlin.Metadata;
import kotlin.jvm.functions.Function2;
import org.jetbrains.annotations.NotNull;
@Metadata(
mv = {1, 1, 9},
bv = {1, 0, 2},
k = 2,
d1 = {"\u0000\u0012\n\u0000\n\u0002\u0010\b\n\u0002\b\u0005\n\u0002\u0018\u0002\n\u0002\b\u0002\"\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"},
d2 = {"sum3", "", "getSum3", "()I", "sum4", "getSum4", "suml", "Lkotlin/Function2;", "getSuml", "()Lkotlin/jvm/functions/Function2;"}
)
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.apply(1, 2, suml);
sum4 = FunctionKt.apply(1, 3, (Function2)null.INSTANCE);
}
}
let.kt
val other = sumf(1,2)
.let { it + 1 }
val nullable = maybeAnInt()
?.let { it + 1 }
let.java
package _04_lamda;
import kotlin.Metadata;
import kotlin.NotImplementedError;
import kotlin.jvm.internal.DefaultConstructorMarker;
import org.jetbrains.annotations.Nullable;
@Metadata(
mv = {1, 1, 9},
bv = {1, 0, 2},
k = 2,
d1 = {"\u0000\n\n\u0000\n\u0002\u0010\b\n\u0002\b\u0007\u001a\r\u0010\b\u001a\u0004\u0018\u00010\u0001Âą\u0006\u0002\u0010\u0003\"\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"},
d2 = {"nullable", "", "getNullable", "()Ljava/lang/Integer;", "Ljava/lang/Integer;", "other", "getOther", "()I", "maybeAnInt"}
)
public final class LetKt {
private static final int other;
@Nullable
private static final Integer nullable;
@Nullable
public static final Integer maybeAnInt() {
throw (Throwable)(new NotImplementedError((String)null, 1, (DefaultConstructorMarker)null));
}
public static final int getOther() {
return other;
}
@Nullable
public static final Integer getNullable() {
return nullable;
}
static {
int var0 = FunctionKt.sumf(1, 2);
other = var0 + 1;
Integer var10000 = maybeAnInt();
if (var10000 != null) {
Integer var3 = var10000;
int it = ((Number)var3).intValue();
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
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 = kotlin.collections.listOf(moon))
}
}
data class Moon(override val name: String) : AstronomicalBody
object SolarSystem {
val earth = Planet(name = "Earth")
val moon = Moon(name = "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
package _05_class_1;
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;
@Metadata(
mv = {1, 1, 9},
bv = {1, 0, 2},
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\u0003\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"},
d2 = {"L_05_class_1/Planet;", "L_05_class_1/AstronomicalBody;", "name", "", "moons", "", "L_05_class_1/Moon;", "(Ljava/lang/String;Ljava/util/List;)V", "getMoons", "()Ljava/util/List;", "getName", "()Ljava/lang/String;", "component1", "component2", "copy", "equals", "", "other", "", "hashCode", "", "plus", "moon", "toString"}
)
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.listOf(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 var5 = var3.length() > 0;
if (!var5) {
String var4 = "Failed requirement.";
throw (Throwable)(new IllegalArgumentException(var4.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);
}
public String toString() {
return "Planet(name=" + this.getName() + ", moons=" + this.moons + ")";
}
public int hashCode() {
String var10000 = this.getName();
return (var10000 != null ? var10000.hashCode() : 0) * 31 + (this.moons != null ? this.moons.hashCode() : 0);
}
public boolean equals(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
}
data class Comet(val name: String) : 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 fait qu'au moment de la compilation
- Covariant:
out
, en java? extends T
- Contravariant:
in
, en java? super T
Borne supérieure
fun <T : Comparable<T>> sort(list: List<T>): List<T>
Les détails: https://kotlinlang.org/docs/reference/generics.html
Projection *
interface Function<in T, out U>
Function<*, String> // correspond Ă Function<in Nothing, String>
Function<Int, *> // correspond Ă Function<Int, out Any?>
Function<*, *> // correspond Ă Function<in Nothing, out Any?>
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>
// fun getAllEntities(): Map<Pair<String, Int>, List<Entity>> = emptyMap()
fun getAllEntities(): Map<EntityKey, List<Entity>> = emptyMap()
ByteCode d'alias
Compiled from "typealias.kt"
public final class _06_class_2.TypealiasKt {
public static final java.util.Map<kotlin.Pair<java.lang.String, java.lang.Integer>, java.util.List<_06_class_2.Entity>> getAllEntities();
Code:
0: invokestatic #12 // Method kotlin/collections/MapsKt.emptyMap:()Ljava/util/Map;
3: areturn
}
Classe, le bilan
- đ€©
data class
- đ€ Mais pourquoi on n'a pas ça en Java ?
- Une seule classe par fichier n'est pas utile
- đ€
sealed
permet de faire des types algébriques de données (Algebraic Data Type)
Pause
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 Devoxx" // 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 Devoxx"
.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
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)
}
}
for.java
package _09_structures;
import astronomy.AstronomicalBody;
import astronomy.SolarSystem;
import java.util.Iterator;
import kotlin.Metadata;
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;
@Metadata(
mv = {1, 1, 9},
bv = {1, 0, 2},
k = 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\f\u0010\u0002\u001a\b\u0012\u0004\u0012\u00020\u00040\u0003Âą\u0006\u0002\u0010\u0005"},
d2 = {"main", "", "args", "", "", "([Ljava/lang/String;)V"}
)
public final class ForKt {
public static final void main(@NotNull String[] args) {
Intrinsics.checkParameterIsNotNull(args, "args");
Iterator var2 = SolarSystem.INSTANCE.getBodies().iterator();
while(var2.hasNext()) {
AstronomicalBody body = (AstronomicalBody)var2.next();
System.out.print(body);
}
}
}
ByteCode du for
Compiled from "for.kt"
public final class _09_structures.ForKt {
public static final void main(java.lang.String[]);
Code:
0: aload_0
1: ldc #9 // String args
3: invokestatic #15 // Method kotlin/jvm/internal/Intrinsics.checkParameterIsNotNull:(Ljava/lang/Object;Ljava/lang/String;)V
6: getstatic #21 // Field astronomy/SolarSystem.INSTANCE:Lastronomy/SolarSystem;
9: invokevirtual #25 // Method astronomy/SolarSystem.getBodies:()Ljava/util/Collection;
12: invokeinterface #31, 1 // InterfaceMethod java/util/Collection.iterator:()Ljava/util/Iterator;
17: astore_2
18: aload_2
19: invokeinterface #37, 1 // InterfaceMethod java/util/Iterator.hasNext:()Z
24: ifeq 47
27: aload_2
28: invokeinterface #41, 1 // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
33: checkcast #43 // class astronomy/AstronomicalBody
36: astore_1
37: getstatic #49 // Field java/lang/System.out:Ljava/io/PrintStream;
40: aload_1
41: invokevirtual #55 // Method java/io/PrintStream.print:(Ljava/lang/Object;)V
44: goto 18
47: return
}
while-do.kt
while (x > 0) {
x--
}
do {
val y = retrieveData()
} while (y != null) // y is visible here!
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 _09_structures.recusion.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 recursivité
Compiled from "rec-factorial.kt"
public final class _09_structures.recusion.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
}
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é terminal 1/2
Compiled from "tailrec-factorial.kt"
public final class _09_structures.recusion.Tailrec_factorialKt {
public static final int tailRecFactorial(int);
Code:
0: getstatic #12 // Field _09_structures/recusion/Tailrec_factorialKt$tailRecFactorial$1.INSTANCE:L_09_structures/recusion/Tailrec_factorialKt$tailRecFactorial$1;
3: astore_1
4: aload_1
5: iload_0
6: iconst_1
7: invokevirtual #16 // Method _09_structures/recusion/Tailrec_factorialKt$tailRecFactorial$1.invoke:(II)I
10: ireturn
}
ByteCode factoriel avec recursivité terminal 2/2
Compiled from "tailrec-factorial.kt"
final class _09_structures.recusion.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 _09_structures.recusion.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: iconst_1
6: goto 25
9: aload_0
10: checkcast #2 // class _09_structures/recusion/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
_09_structures.recusion.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 _09_structures/recusion/Tailrec_factorialKt$tailRecFactorial$1
3: dup
4: invokespecial #57 // Method "<init>":()V
7: putstatic #59 // Field INSTANCE:L_09_structures/recusion/Tailrec_factorialKt$tailRecFactorial$1;
10: return
}
Performances sur 10!
1/2
Ne croyez pas les benchmarks, faites les vous-mĂȘme !
https://github.com/MonkeyPatchIo/kotlin-perf
Benchmark | Mode | Cnt | Score | Error | Units |
---|---|---|---|---|---|
factorialJavaFor | thrpt | 200 | 433372258.508 | ± 1218796.228 | ops/s |
factorialKotlinFor | thrpt | 200 | 374900724.013 | ± 1836466.839 | ops/s |
factorialJavaRec | thrpt | 200 | 71945600.003 | ± 1621282.609 | ops/s |
factorialKotlinRec | thrpt | 200 | 75889169.327 | ± 803516.130 | ops/s |
factorialJavaTailRec | thrpt | 200 | 74708348.540 | ± 385285.112 | ops/s |
factorialKotlinTailRec | thrpt | 200 | 432005903.950 | ± 2558012.821 | ops/s |
factorialJavaReduce | thrpt | 200 | 21560855.907 | ± 586144.742 | ops/s |
factorialKotlinReduce | thrpt | 200 | 99169022.775 | ± 2711794.007 | ops/s |
Performances sur 10!
2/2
Bilan structures
- Il y a aussi des
break
etcontinue
, label pour les boucles when
peut ĂȘtre utiliser avec- des constantes,
- plusieurs valeurs séparées par
,
- une expression
- avec
is
et un type (avec un 'smart cast')
âš Tips
- privilégier les
when
si vous avez plus de 2 cas - si vous faites des fonctions récursives, faites les
tailrec
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
package _08_extension;
import astronomy.AstronomicalBody;
import astronomy.SolarSystem;
import java.util.Iterator;
import kotlin.Metadata;
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;
@Metadata(
mv = {1, 1, 9},
bv = {1, 0, 2},
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\u0002\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"},
d2 = {"size", "", "Lastronomy/AstronomicalBody;", "getSize", "(Lastronomy/AstronomicalBody;)I", "main", "", "args", "", "", "([Ljava/lang/String;)V", "display"}
)
public final class ExtensionKt {
public static final int getSize(@NotNull AstronomicalBody $receiver) {
Intrinsics.checkParameterIsNotNull($receiver, "$receiver");
return $receiver.getName().length();
}
@NotNull
public static final String display(@NotNull AstronomicalBody $receiver) {
Intrinsics.checkParameterIsNotNull($receiver, "$receiver");
return "Body " + $receiver.getName() + ' ' + getSize($receiver);
}
public static final void main(@NotNull String[] args) {
Intrinsics.checkParameterIsNotNull(args, "args");
Iterable $receiver$iv = (Iterable)SolarSystem.INSTANCE.getBodies();
Iterator var2 = $receiver$iv.iterator();
while(var2.hasNext()) {
Object element$iv = var2.next();
AstronomicalBody it = (AstronomicalBody)element$iv;
String var5 = display(it);
System.out.println(var5);
}
}
}
Extension
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)
immutable-mutable.kt
fun main(args: Array<String>) {
val earthMoon = listOf(Moon("moon"))
val add = earthMoon + Moon("moon 2")
println("earthMoon: $earthMoon") // earthMoon: [Moon(name=moon)]
println("add: $add") // add: [Moon(name=moon), Moon(name=moon 2)]
println("reference equality: ${earthMoon === add}") //reference equality: false
println("\n")
val earthMoon2 = mutableListOf(Moon("moon"))
val add2 = earthMoon2.add(Moon("moon 2"))
println("earthMoon2: $earthMoon2") // earthMoon2: [Moon(name=moon), Moon(name=moon 2)]
println("add2: $add2") // add2: true
}
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 sequences 1/2
Ne croyez pas les benchmarks, faites les vous-mĂȘme !
https://github.com/MonkeyPatchIo/kotlin-perf
Benchmark | Mode | Cnt | Score | Error | Units |
---|---|---|---|---|---|
collectionApiClassic | thrpt | 200 | 44535.029 | ± 3550.944 | ops/s |
collectionApiSequence | 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 sequences 2/2
Ne croyez pas les benchmarks, faites les vous-mĂȘme !
https://github.com/MonkeyPatchIo/kotlin-perf
Benchmark | Mode | Cnt | Score | Error | Units |
---|---|---|---|---|---|
collectionApiClassicFirst | thrpt | 200 | 241752.062 | ± 5022.663 | ops/s |
collectionApiSequenceFirst | thrpt | 200 | 3615451.391 | ± 454502.198 | ops/s |
timed-sequence.kt
fun <T> timed(block: () -> T) {
val startTime = System.currentTimeMillis()
val result = block()
val endTime = System.currentTimeMillis()
val duration = endTime - startTime
val readable = String.format("%d min %02d seconds", duration / 60000, (duration % 60000) / 1000)
println("$result in $readable")
}
fun main(args: Array<String>) {
fun Long.toMB(): String =
"${this / 1048576}MB"
fun Runtime.usedMemory(): String =
(totalMemory() - freeMemory()).toMB()
fun Runtime.getMemoryInfo(): String =
"used: ${usedMemory()}, total: ${totalMemory().toMB()}"
timed {
(0..1_000_000)
.asSequence()
.onEach {
if (it % 10_000 == 0) {
println(Runtime.getRuntime().getMemoryInfo())
}
println(it)
}
.map { Moon(it.toString()) }
.first()
}
}
ranges.kt
for (i in 1..3) print(i) // prints 123
for (i in 3 downTo 1) print(i) // prints 321
for (i in 1..5 step 2) print(i) // prints 135
ranges.java
package _11_collections_2;
import kotlin.Metadata;
import kotlin.jvm.internal.Intrinsics;
import kotlin.ranges.IntProgression;
import kotlin.ranges.IntRange;
import org.jetbrains.annotations.NotNull;
@Metadata(
mv = {1, 1, 9},
bv = {1, 0, 2},
k = 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\f\u0010\u0002\u001a\b\u0012\u0004\u0012\u00020\u00040\u0003Âą\u0006\u0002\u0010\u0005"},
d2 = {"main", "", "args", "", "", "([Ljava/lang/String;)V"}
)
public final class RangesKt {
public static final void main(@NotNull String[] args) {
Intrinsics.checkParameterIsNotNull(args, "args");
int i = 1;
byte var2;
for(var2 = 3; i <= var2; ++i) {
System.out.print(i);
}
i = 3;
for(var2 = 1; i >= var2; --i) {
System.out.print(i);
}
byte var4 = 1;
IntProgression var10000 = kotlin.ranges.RangesKt.step((IntProgression)(new IntRange(var4, 5)), 2);
i = var10000.getFirst();
int var5 = var10000.getLast();
int var3 = var10000.getStep();
if (var3 > 0) {
if (i > var5) {
return;
}
} else if (i < var5) {
return;
}
while(true) {
System.out.print(i);
if (i == var5) {
return;
}
i += var3;
}
}
}
tuples.kt
fun main(args: Array<String>) {
val aPair = "Earth" to "Moon" // ~ Pair("Earth", "Moon")
val (planet, moon) = aPair
val aTriple = Triple("Voyager 1", 1977, listOf("Jupiter", "Saturn"))
val (probeNane, launchYear, flyOver) = aTriple
}
tuples.java
package _11_collections_2;
import java.util.List;
import kotlin.Metadata;
import kotlin.Pair;
import kotlin.Triple;
import kotlin.collections.CollectionsKt;
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;
@Metadata(
mv = {1, 1, 9},
bv = {1, 0, 2},
k = 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\f\u0010\u0002\u001a\b\u0012\u0004\u0012\u00020\u00040\u0003Âą\u0006\u0002\u0010\u0005"},
d2 = {"main", "", "args", "", "", "([Ljava/lang/String;)V"}
)
public final class TuplesKt {
public static final void main(@NotNull String[] args) {
Intrinsics.checkParameterIsNotNull(args, "args");
Pair aPair = kotlin.TuplesKt.to("Earth", "Moon");
String var2 = (String)aPair.component1();
String moon = (String)aPair.component2();
Triple aTriple = new Triple("Voyager 1", 1977, CollectionsKt.listOf(new String[]{"Jupiter", "Saturn"}));
String var5 = (String)aTriple.component1();
int var6 = ((Number)aTriple.component2()).intValue();
List flyOver = (List)aTriple.component3();
}
}
Bilan collection
- đȘ Super on a de l'immutabilitĂ©, des
map
,flatMap
,fold
,aggregate
,... - đ€š Mais ça reste des collections Java
- âïž Avant d'utiliser les
Sequence
, faites des mesures
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 Devoxx"
}
lazy.kt
object DeepThought {
fun answer(): Int {
print("Computing ...")
return 42
}
}
fun main(args: Array<String>) {
val ultimateQuestionOfLife: Int by lazy {
DeepThought.answer()
}
println("The Ultimate Question of Life, " +
"the Universe and Everything ?")
print("Answer: ")
println(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
lateinit var str: String
fun main(args: Array<String>) {
// println(str) kotlin.UninitializedPropertyAccessException
str = "Hello Devoxx"
println(str)
}
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 sur
Activity
,Fragment
).- Ne peut pas ĂȘtre utilisĂ© avec les types primitifs
Un peu plus sur les fonctions
inline.kt
import java.time.Instant
class Logger(private val name: String) {
private enum class Level { TRACE, DEBUG, INFO, WARN, ERROR, FATAL }
private val level = Level.INFO
fun info(message: () -> String) {
log(Level.INFO, message)
}
private inline fun log(lvl: Level, message: () -> String) { // inline
if (level >= lvl) {
println("[${level.name}] $name - ${message()}")
}
}
}
fun main(args: Array<String>) {
val logger = Logger("Main")
logger.info { "Time: ${Instant.now()}" }
}
Logger.java
package _13_advanced_function;
import kotlin.Metadata;
import kotlin.jvm.functions.Function0;
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;
@Metadata(
mv = {1, 1, 9},
bv = {1, 0, 2},
k = 1,
d1 = {"\u0000&\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0000\n\u0002\u0010\u000e\n\u0002\b\u0002\n\u0002\u0018\u0002\n\u0000\n\u0002\u0010\u0002\n\u0000\n\u0002\u0018\u0002\n\u0002\b\u0003\u0018\u00002\u00020\u0001:\u0001\rB\r\u0012\u0006\u0010\u0002\u001a\u00020\u0003Âą\u0006\u0002\u0010\u0004J\u0014\u0010\u0007\u001a\u00020\b2\f\u0010\t\u001a\b\u0012\u0004\u0012\u00020\u00030\nJ\u001f\u0010\u000b\u001a\u00020\b2\u0006\u0010\f\u001a\u00020\u00062\f\u0010\t\u001a\b\u0012\u0004\u0012\u00020\u00030\nH\u0082\bR\u000e\u0010\u0005\u001a\u00020\u0006X\u0082\u0004Âą\u0006\u0002\n\u0000R\u000e\u0010\u0002\u001a\u00020\u0003X\u0082\u0004Âą\u0006\u0002\n\u0000"},
d2 = {"L_13_advanced_function/Logger;", "", "name", "", "(Ljava/lang/String;)V", "level", "L_13_advanced_function/Logger$Level;", "info", "", "message", "Lkotlin/Function0;", "log", "lvl", "Level"}
)
public final class Logger {
private final Logger.Level level;
private final String name;
public final void info(@NotNull Function0 message) {
Intrinsics.checkParameterIsNotNull(message, "message");
Logger.Level lvl$iv = Logger.Level.INFO;
if (access$getLevel$p(this).compareTo((Enum)lvl$iv) >= 0) {
String var4 = '[' + access$getLevel$p(this).name() + "] " + access$getName$p(this) + " - " + (String)message.invoke();
System.out.println(var4);
}
}
private final void log(Logger.Level lvl, Function0 message) {
if (access$getLevel$p(this).compareTo((Enum)lvl) >= 0) {
String var4 = '[' + access$getLevel$p(this).name() + "] " + access$getName$p(this) + " - " + (String)message.invoke();
System.out.println(var4);
}
}
public Logger(@NotNull String name) {
Intrinsics.checkParameterIsNotNull(name, "name");
super();
this.name = name;
this.level = Logger.Level.INFO;
}
// $FF: synthetic method
@NotNull
public static final Logger.Level access$getLevel$p(Logger $this) {
return $this.level;
}
// $FF: synthetic method
@NotNull
public static final String access$getName$p(Logger $this) {
return $this.name;
}
@Metadata(
mv = {1, 1, 9},
bv = {1, 0, 2},
k = 1,
d1 = {"\u0000\f\n\u0002\u0018\u0002\n\u0002\u0010\u0010\n\u0002\b\u0007\b\u0082\u0001\u0018\u00002\b\u0012\u0004\u0012\u00020\u00000\u0001B\u0007\b\u0002Âą\u0006\u0002\u0010\u0002j\u0002\b\u0003j\u0002\b\u0004j\u0002\b\u0005j\u0002\b\u0006j\u0002\b\u0007j\u0002\b\b"},
d2 = {"L_13_advanced_function/Logger$Level;", "", "(Ljava/lang/String;I)V", "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL"}
)
private static enum Level {
TRACE,
DEBUG,
INFO,
WARN,
ERROR,
FATAL;
protected Level() {
}
}
}
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
package _13_advanced_function;
import kotlin.Metadata;
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;
@Metadata(
mv = {1, 1, 9},
bv = {1, 0, 2},
k = 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\f\u0010\u0002\u001a\b\u0012\u0004\u0012\u00020\u00040\u0003Âą\u0006\u0002\u0010\u0005"},
d2 = {"main", "", "args", "", "", "([Ljava/lang/String;)V"}
)
public final class ReifiedKt {
public static final void main(@NotNull String[] args) {
Intrinsics.checkParameterIsNotNull(args, "args");
Pojo p1 = new Pojo();
p1.setName("Plop1");
System.out.println(p1);
JavaBeanBuilder this_$iv = JavaBeanBuilder.INSTANCE;
Pojo p2 = (Pojo)this_$iv.createBean(Pojo.class);
p2.setName("Plop2");
System.out.println(p2);
}
}
Plus sur les fonctions
Cas d'utilisation du reified
- Pour créer des extensions Kotlin des fonctions Java qui utilisent des
Class<T>
Cas d'utilisation des inline
, noinline
, crossinline
- Quand on utilise
reified
- Quand on sait se qu'on fait, https://kotlinlang.org/docs/reference/inline-functions.html
Conclusion
Android
- Faible surchage
- Support officiel par Google
- Using Project Kotlin for Android
- Kotlin Guide
- android-ktx
- Kotlin Android Extensions
Serveur
Web et Natif
đž Web
- Partager du code commun
- Use Kotlin with npm, webpack and react
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 (editeur, gradle, maven)
- đ EcosystĂšme et communautĂ©
- đ Ăvolution rapide
- đŁ Code multiplatform
- DSL
Kotlin réussit une belle alchimie entre pragmatisme, puissance, sûreté, accessibilité.
Liens
Liens presentation
- Slides en HTML: http://bit.ly/KotlinDevoxxFR
- Slides en PDF: http://bit.ly/KotlinDevoxxFRpdf
- kotlin-perf
- Kotlin by example
- catnip
BibliothĂšques
Merci
Questions ?
Pensez au votes et aux retours