Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Kotlin: forse è la volta buona (Trento)

181 views

Published on

Il codice di esempio e disponibile qui: https://github.com/jesty/kotlin-fossavotabona
La variazione col DAO al posto del repository è disponibile qui:
https://github.com/jesty/kotlin-fossavotabona/tree/dao-companion-object

Published in: Software
  • Be the first to comment

  • Be the first to like this

Kotlin: forse è la volta buona (Trento)

  1. 1. Kotlin: forse è la volta buona Jug Day - Trento 19/05/2018
  2. 2. Davide Cerbo 10+ years of experience Full-stack DevDay co-founder I write code, I see people Chi sono
  3. 3. Disclaimer Here we have a lot of println, and some jokes. My wife said that they aren’t funny.
  4. 4. C’era una volta OAK It was 1992 and in Italy there was a big scandal: Tangentopoli.
  5. 5. C’era una volta OAK Java Borns in 1995 and now can drink beers.
  6. 6. Il grande problema Backward compatibility (The art of killing your app because the environment evolves while you can’t) JDK 1.0 (21 January 1996) JDK 1.1 (19 February 1997) J2SE 1.2 (8 December 1998) J2SE 1.3 (8 May 2000) J2SE 1.4 (6 February 2002) J2SE 5.0 (30 September 2004) Java SE 6 (11 December 2006) Java SE 7 (28 July 2011) Java SE 8 (18 March 2014) Java SE 9 (26 September 2017) Java Se 10 (20 March 2018)
  7. 7. JVM != Java JAVA JVM
  8. 8. Machine code is not enought? Assembly languages Machine code Logic languages (Prolog) Functional languages (Haskell) Procedural languages (C / Pascal) Object-oriented languages (Java) The Case for Kotlin and Ceylon by Russel Winder https://www.youtube.com/watch?v=cFL_DDXBkJQ
  9. 9. Why Kotlin?
  10. 10. So, why not Scala? Kotlin is a better Java while Scala is more powerful than Java, and probably than Kotlin. But, Kotlin borns in the industry for the industry and it evolves with the industry in mind, while Scala borns at the university and it is adapted to the industry. Unfortunately, I work for the industry. https://agilewombat.com/2016/02/01/scala-vs-kotlin/ https://superkotlin.com/kotlin-vs-scala/
  11. 11. So, why not, another one time, Scala? Scala can interact with Java at the library level, meaning that Java programs can use Scala libraries (objects and functions) and Scala libraries can use Java libraries (objects and methods). But Scala and Java programs must be built as separate projects, with distinct build chains. Kotlin is different because it integrates with Java programs at the source level. You can mix Java and Kotlin source files in the same projects with a single build chain. (The joy of Kotlin - Pierre Yves Saumont)
  12. 12. Java Kotlin
  13. 13. Kotlin is a statically-typed programming language that runs on the Java Virtual Machine and also can be compiled to JavaScript source code or uses the LLVM compiler infrastructure.
  14. 14. https://dzone.com/articles/why-learn-kotlin-infographic Predicatability not performance:https://www.youtube.com/watch?v=ExkNNsDn6Vg Since 2010 (2012): KOTLIN! 100% interoperable with Java ☕ ~40% less lines of code than Java Easy to learn, if you know Java JetBrains It’s safe Apache 2 ⛺ PerformancePredictability
  15. 15. 04 January 2017 Introducing Kotlin support in Spring Framework 5.0 https://spring.io/blog/2017/01/04/introducing-kotlin-support-in-spring-framework-5-0 https://github.com/sdeleuze/spring-kotlin-deepdive
  16. 16. 17 May 2017 Kotlin on Android. Now official https://blog.jetbrains.com/kotlin/2017/05/kotlin-on-android-now-official/ http://nilhcem.com/swift-is-like-kotlin/
  17. 17. https://blog.jetbrains.com/kotlin/category/native/ https://github.com/JetBrains/kotlin-native 31 March 2017 Kotlin / Native borns!
  18. 18. 5 June 2017 kotlin-react borns! https://github.com/JetBrains/kotlin-wrappers/commits/master/kotlin-react https://github.com/JetBrains/create-react-kotlin-app
  19. 19. May 2018 ThoughtWorks suggests to adopt Kotlin in its Technlogy Radar https://www.thoughtworks.com/radar/languages-and-frameworks/kotlin May 2017 Nov 2017 May 2018 TrialAsses Adopt
  20. 20. Var o Val var serie = "B" var a = "Salernitana will win Serie $serie" val b = "Salernitana will win Serie $serie" IMMUTABLE
  21. 21. Fun fun main(args: Array<String>){ hello("Davide", "Salerno") } fun hello(name: String, city: String){ println("Hello $name from $city") }
  22. 22. JVM != Java class Hello { fun sayHello(): String { return "hello!" } } public final class Hello { // access flags 0x11 public final sayHello()Ljava/lang/String; @Lorg/jetbrains/annotations/NotNull;() // invisible L0 LINENUMBER 8 L0 LDC "hello!" ARETURN L1 LOCALVARIABLE this Ltotest/Hello; L0 L1 0 MAXSTACK = 1 MAXLOCALS = 1 // access flags 0x1 public <init>()V L0 LINENUMBER 6 L0 ALOAD 0 INVOKESPECIAL java/lang/Object.<init> ()V RETURN L1 LOCALVARIABLE this L/Hello; L0 L1 0 MAXSTACK = 1 MAXLOCALS = 1 @Lkotlin/Metadata;(mv={1, 1, 1}, bv={1, 0, 2}, k=1, d1={"u0000u0012nu0002u0018u0002nu0002u0010u0000nu0002 u0008u0002nu0002u0010u000enu0000u0018u00002u00020u00 01Bu0005u00a2u0006u0002u0010u0002Ju0006u0010u0003u001 au00020u0004u00a8u0006u0005", d2={"L/Hello;", "", "()V", "sayHello", "", "production sources for module coroutine_main"}) // compiled from: Hello.kt } @Metadata( mv = {1, 1, 7}, bv = {1, 0, 2}, k = 1, d1 = {"u0000u0012nu0002u0018u0002nu0002 u0005¢u0006u0002u0010u0002Ju0006u00 d2 = {"Ltotest/Hello;", "", "()V", "sayHello", "", " ) public final class Hello { @NotNull public final String sayHello() { return "hello!"; } } Compile Decompile Tools > Kotlin > Show Kotlin Bytecode > Decompile
  23. 23. Fun fun functions fun hello(name: String, city: String = "Salerno") = println("Hello $name from $city") hello("Davide", "Salerno") hello(name = "Davide") hello(city = "Salerno", name = "Valentina") fun Int.multilpy(x: Int): Int = this * x // 5.multilpy(10) infix fun Int.multilpy(x: Int): Int = this * x // 5 multilpy 10 Also helps with refactoring!
  24. 24. E gli operatori? data class Point(val x: Int, val y: Int) { operator fun plus(a: Point) = Point(x + a.x, y + a.y) } operator fun Point.unaryMinus() = Point(-x, -y) val point = Point(10, 20) println(point + point + point) //Point(x=30, y=60) println(-point) // Point(x=-10, y=-20)
  25. 25. Tailrec ● Recursion, in some language, can cause: StackOverflow! ● Reduce stack execution. ● Tailrec will resolve this issue only if the recursive call is the last one. ● It transforms your code in imperative code. Less readable, but more fast. ● Performance improvement fun factorial(n: Long): Long = if (n <= 1L) n else n * factorial(n - 1) tailrec fun factorial(n: Long, accumulator: Long = 1): Long = if (n <= 1L) accumulator else factorial(n - 1, accumulator * n) Tailrec cannot applicable “If” will return the verified condition value
  26. 26. Tailrec decompiled public static final long factorial(long n, long accumulator) { while(n > 1L) { long var10000 = n - 1L; accumulator *= n; n = var10000; } return accumulator; } public static long factorial$default(long var0, long var2, int var4, Object var5) { if((var4 & 2) != 0) { var2 = 1L; } return factorial(var0, var2); } } public static final long factorial(long n, long accumulator) { return n <= 1L?accumulator:factorial(n - 1L, accumulator * n); } public static long factorial$default(long var0, long var2, int var4, Object var5) { if((var4 & 2) != 0) { var2 = 1L; } return factorial(var0, var2); } With Tailrec Without Tailrec StackOverflow Tools > Kotlin > Show Kotlin Bytecode > Decompile
  27. 27. “If” is an expression, not a construct, i.e. it returns a value.
  28. 28. Class open class Person(val name: String) { init { println("init…") } open fun speak() { println("Hi $name!") } infix fun and(o: Person) = "Hi ${o.name} & ${this.name}" } fun main(args: Array<String>) { Person("Davide") and Person("Valentina") val p = Person("Jack") p.speak() }
  29. 29. Class class Customer(name: String) : Person(name) { override fun speak() { println("Welcome $name!") } } class CustomerDavide : Person("Davide") { override fun speak() { println("Welcome $name!") } }
  30. 30. Equals, hashCode, toString e copy, nevermore! data class User(val name: String, val age: Int) val davide = User("Davide", 35) val davideJunior = davide.copy(age=0) fun main(args: Array<String>) { val (name, age) = davide println("$name $age years old") } deconstructing
  31. 31. Nothing is equal as appear data class Point(val x: Int, val y: Int) val a = Point(1, 2) val b = Point(1, 2) val c = a println(a === b) // false println(a == b) // true println(a === c) // true println(a == c) // true Check the reference .equals(...)
  32. 32. Lambda fun main(args: Array<String>) { arrayOf("Valentina", "Davide").forEach { println("Hello $it!") } val ints =(1..3) val logger = { msg: Any -> println("log $msg") } ints.map { value -> value * 2 }.map { v -> logger(v) } ints.map { it * 2 }.map { logger(it) } }
  33. 33. Lambda class Customer(val name: String) { fun forEach(action: (char: Char) -> Unit) = name.forEach(action) fun upperCaseAndConcat(callback: () -> String) = "${callback()} $name".toUpperCase() } fun main(args: Array<String>) { val customer = Customer("Davide") customer.forEach { println(it.toInt()) } //68 97 118 105 100 101 println(customer.upperCaseAndConcat { "Cerbo" }) //CERBO DAVIDE } The type with only one value: the Unit object. This type corresponds to the void type in Java.
  34. 34. Lambda Java -> Java 8 -> Kotlin public class MapsTest { private Map<String, Integer> scores = new HashMap<String, Integer>() { { put("Jack", 12); put("Jill", 15); put("Tom", 11); put("Darla", 15); put("TOM", 11); put("Nick", 15); put("Nancy", 11); } }; @Test void maxNumberOfLetters() { assertAll( () -> assertEquals(4, (int) MapsK.maxNumberOfLetters(scores).get(12)) , () -> assertEquals(5, (int) MapsK.maxNumberOfLetters(scores).get(15)) , () -> assertEquals(5, (int) MapsK.maxNumberOfLetters(scores).get(11)) ); } } 12: Jack 15: Jill. Darla, Nick 11: Tom, Tom, Nancy 12: 4 15: 5 11: 5
  35. 35. Lambda Java -> Java 8 -> Kotlin public static Map<Integer, Integer> maxNumberOfLetters(Map<String, Integer> scores) { Map<Integer, Integer> byScores = new HashMap<>(); for (String name : scores.keySet()) { int score = scores.get(name); int maxLength = 0; if (byScores.containsKey(score)) maxLength = byScores.get(score); maxLength = maxLength < name.length() ? name.length() : maxLength; byScores.put(score, maxLength); } return byScores; }
  36. 36. Lambda Java -> Java 8 -> Kotlin public static Map<Integer, Integer> maxNumberOfLetters(Map<String, Integer> scores) { return scores.keySet().stream() .collect(groupingBy(scores::get, collectingAndThen(maxBy(comparing(String::length)), name -> name.orElse("").length()) )); }
  37. 37. Lambda Java -> Java 8 -> Kotlin fun maxNumberOfLetters(scores: Map<String, Int>): Map<Int?, Int?> { return scores .keys .groupBy(scores::get) .mapValues { it.value .map(String::length) .max() } } https://medium.com/@davidecerbo/kotlin-vs-java-maps-6dcb6f4f21cd
  38. 38. Lambda & Function Label fun forEachTest() { val numbers = 1..100 numbers.forEach { if (it == 25) { return } println("index $it") } println("Hello") } fun forEachTest() { val numbers = 1..100 numbers.forEach { if (it == 25) { return@forEach } println("index $it") } println("Hello") } Vs.
  39. 39. Tell me when, when? fun describe(obj: Any): String = when (obj) { 1 -> "One" "Hello" -> "Greeting" is Long -> "Long" !is String -> "Not a string" else -> "Unknown" } describe(Person("davide"))
  40. 40. Null is safe! var testA:String = "ciao" var testB:String? = "ciao" testB = null println("a0 ${testA.length}") println("b0 ${testB.length}") // ^ Not safe! Compile time error! ^ println("b1 ${testB?.length}") println("b2 ${testB!!.length}") // ^ KotlinNullPointerException ^ // NPE Lovers
  41. 41. Null is safe! val nullableList: List<Int?> = listOf(1, 2, null, 4) val intList: List<Int> = nullableList.filterNotNull() // [1, 2, 4] val aInt: Int? = b as? Int // If b is null, normally we will have a NullPointerException, while if the type is different we will have a ClassCastExeption. Using “as?” we haven’t an exception, we will have a null value assigned to the aInt value.
  42. 42. Null is safe! data class Person(val name: String, val age: Int?) val person:Person? = Person("Jack", 1) if (person?.age != null) { println("The person is aged ${person?.age}") } //oppure person?.age?.let { println("The person is aged $it") }
  43. 43. ?: Elvis operatorIt is the replacement to “Optional.getOrElse” in Java val davide = Person(testA) val elvis = Person(testB ?: "Elvis") println(jack.name)
  44. 44. Kotlin forces you to handle it or to take full responsibility.
  45. 45. Companion object ● No static members. ● Has access to private level method and properties of the main object. ● Companion objects can implements interfaces. interface Factory<T> { fun create(): T } class MyClass { companion object : Factory<MyClass> { @JvmStatic //converts to real static method override fun create(): MyClass = MyClass() } }
  46. 46. Visibility Modifiers private - means visible inside this class only (including all its members); protected — same as private + visible in subclasses too; Override protected method are still protected. internal — any client inside this module who sees the declaring class sees its internal members. A module is a set of Kotlin files compiled together; public — any client who sees the declaring class sees its public members. (Default)
  47. 47. Exception Kotlin does not have checked exceptions throw is an expression val s = person.name ?: throw IllegalArgumentException("Name required")
  48. 48. Property: Get & Set class Strange(var value: Long) { var strangeValue: Long get() = value * 2 set(value){ if(value > 5) this.value = value } } fun main(args: Array<String>) { val customer = Strange(10) println(customer.strangeValue) //20 customer.strangeValue = 3 println(customer.strangeValue) //20 customer.strangeValue = 6 println(customer.strangeValue) //12 }
  49. 49. Delegated properties: why me? class Delegate { operator fun getValue(thisRef: Any?, property: KProperty<*>): String { return "$thisRef, thank you for delegating '${property.name}' to me!" } operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) { println("$value has been assigned to '${property.name} in $thisRef.'") } } class Example { var p: String by Delegate() }
  50. 50. Delegated properties: the lazy & the observable val lazyValue: String by lazy { println("computed!") "Hello" } fun main(args: Array<String>) { println(lazyValue) println(lazyValue) } class User { var n: String by Delegates.observable("empty") { prop, old, new -> println("$old -> $new") } } fun main(args: Array<String>) { val user = User() user.n = "first" user.n = "second" }
  51. 51. Coroutine Coroutine ⋍ light-weight thread ● They are like threads, they run in parallel, wait for each other and they communicate. ● They are cheap, we can create many of those without having performance issues. ● They are executed in a thread pool. ● A thread can handle more than one coroutine. ● Thread became free until a coroutine is in waiting state. When the coroutine will return active, it doesn’t get the old thread, but it will use a free thread in the pool. https://github.com/Kotlin/kotlinx.coroutines/blob/master/coroutines-guide.md https://proandroiddev.com/approaching-kotlin-coroutines-an-extensive-feature-concurrent-programming-in-kotlin-eaaa19b003d2
  52. 52. Coroutine is humble fun main(args: Array<String>) = runBlocking { val jobs = List(100_000) { launch { delay(1000L) print(".") } } jobs.forEach { it.join() } } fun main(args: Array<String>) { val jobs = List(100_000) { thread(start = true) { Thread.sleep(1000L) print(".") } } jobs.forEach { it.join() } } OUT OF MEMORY!!!
  53. 53. Coroutine: suspend, async / await fun main(args: Array<String>) = runBlocking<Unit> { val time = measureTimeMillis { val one = doSomethingUsefulOne() val two = doSomethingUsefulTwo() println("The answer is ${one + two}") } println("Completed in $time ms") } suspend fun doSomethingUsefulOne(): Int { delay(1000L) return 13 } suspend fun doSomethingUsefulTwo(): Int { delay(1000L) return 29 } fun main(args: Array<String>) = runBlocking<Unit> { val time = measureTimeMillis { val one = async { doSomethingUsefulOne() } val two = async { doSomethingUsefulTwo() } println("The answer is ${one.await() + two.await()}") } println("Completed in $time ms") } suspend fun doSomethingUsefulOne(): Int { delay(1000L) return 13 } suspend fun doSomethingUsefulTwo(): Int { delay(1000L) return 29 } ~2 sec. ~1 sec.
  54. 54. Coroutine is the basement Coroutine Actors Communication Sequence Process ?
  55. 55. Now is the time to remember that Kotlin is good because the trade-off between synthesis and readable code is really good.
  56. 56. Automatic restart
  57. 57. Webapp: Gradle buildscript { ... dependencies { ... classpath "org.jetbrains.kotlin:kotlin-noarg:$kotlinVersion" } } ... apply plugin: "kotlin-jpa" group = 'it.devday' version = '0.0.1-SNAPSHOT' ... } JPA need an empty constructor in some entities, and Kotlin objects don’t have. To solve this issue we can use this plugin that will create an empty constructor in any object, without any change to our codebase.
  58. 58. Webapp: Domain & Repository import it.devday.kotlincodemotion.domain.Contact import org.springframework.data....JpaRepository interface ItemRepository: JpaRepository<Item, Long> import javax.persistence.Entity import javax.persistence.GeneratedValue import javax.persistence.Id @Entity data class Item( @Id @GeneratedValue val id: Long, val description: String, val vat: Double, val price: Double, val quantity: Double)
  59. 59. Webapp: Domain & Repository @Embeddable data class Price(val amount: Double) { operator fun plus(a: Price) = a.amount + this.amount operator fun rem(a: ValueAddedTax) = this.amount * (100 + a.percentage) / 100 } @Embeddable data class Quantity(val value: Double) @Embeddable data class ValueAddedTax(val percentage: Double) @Entity data class Item( @Id @GeneratedValue val id: Long, val description: String, @Embedded val vat: ValueAddedTax, @Embedded val price: Price, @Embedded val quantity: Quantity) { val grossPrice: Double get() = this.price % this.vat val total: Double get() = this.grossPrice * quantity.value }
  60. 60. Webapp: Resource 1/2 @RestController @RequestMapping("/items") class ItemResource(val repository: ItemRepository) { @GetMapping //curl -XGET http://localhost:8080/items fun getAll() = repository.findAll() @GetMapping("/{id}") //curl -XGET http://localhost:8080/items/1 fun getAll(@PathVariable id: Long) = repository.findById(id)
  61. 61. Webapp: Resource 2/2 @PostMapping //curl -XPOST http://localhost:8080/items -H 'Content-Type: application/json' -d '{"description":"Kotlin in action", "vat":{"percentage":10}, "price":{"amount":1.5}, "quantity":{"value":"10"}}' fun insert(@RequestBody item: Item) = repository.save(item) @DeleteMapping("/{id}") //curl -XDELETE http://localhost:8080/items/1 fun delete(@PathVariable id: Long) { val item = repository.findById(id).unwrap() item?.let { repository.delete(item) } } } wait...unwrap() doesn’t exist on Optional class
  62. 62. Webapp: Application @SpringBootApplication class KotlinApplication fun <T> Optional<T>.unwrap(): T? = orElse(null) fun main(args: Array<String>) { runApplication<KotlinApplication>(*args) } unwrap()! array is passed element by element, it is used with vararg arguments public inline fun <reified T : kotlin.Any> runApplication(vararg args: kotlin.String) The generic type will be available in the method. Wow!
  63. 63. Webapp: Where is my Repository? @RestController @RequestMapping("/items") class ItemResource() { @GetMapping //curl -XGET http://localhost:8080/items fun getAll() = Item.findAll() @GetMapping("/{id}") //curl -XGET http://localhost:8080/items/1 fun getAll(@PathVariable id: Long) = Item.findById(id) …...
  64. 64. Webapp: Domain & Repository Dao @Entity data class Item(….) { …. companion object : Dao<Item, Long> } Why this approach? http://mavi.logdown.com/posts/5771422
  65. 65. interface Dao<T, K> inline fun <reified T : Any, K> Dao<T, K>.findById(id: K): T = Db.exec { em -> em.find(T::class.java, id) } as T inline fun <reified T : Any, K> Dao<T, K>.save(item: T): Unit = Db.exec { em -> tx(em) { em.persist(item) } } as Unit ... …. fun tx(em: EntityManager, c: () -> Any): Any { try { em.transaction.begin() val result = c() em.transaction.commit() return result } finally { em.close() } } Webapp: Domain & Repository Dao
  66. 66. @Component object Db : ApplicationContextAware { var ac: ApplicationContext? = null override fun setApplicationContext(applicationContext: ApplicationContext) { ac = applicationContext!! } fun exec(callback: (em: EntityManager) -> Any): Any { return callback(ac!!.getBean(EntityManagerFactory::class.java).createEntityManager()) } } Webapp: Domain & Repository Dao
  67. 67. ? ? ? @davide_cerbo @devdayit http://slack.devday.it http://medium.com/@davidecerbo
  68. 68. Everything is here: https://github.com/jesty/kotlin-fossavotabona
  69. 69. Books!
  70. 70. Useful resources https://kotlinlang.org/docs/reference/ https://spring.io/blog/2017/01/04/introducing-kotlin-support-in-spring-framework-5-0 https://blog.jetbrains.com/kotlin/2017/05/kotlin-on-android-now-official/ https://dev.to/lovis/gang-of-four-patterns-in-kotlin https://github.com/volodymyrprokopyuk/kotlin-sdp https://github.com/gradle/gradle-script-kotlin https://speakerdeck.com/sdeleuze/functional-web-applications-with-spring-and-kotlin https://kotlinlang.org/docs/tutorials/httpservlets.html http://thetechnocafe.com/more-about-functions-in-kotlin/ https://nklmish.wordpress.com/2017/10/22/deprecated-in-kotlin/ https://kotlinlang.org/docs/tutorials/command-line.html https://agilewombat.com/2016/02/01/scala-vs-kotlin/ https://superkotlin.com/kotlin-vs-scala/ https://kotlinlang.org/docs/reference/type-safe-builders.html

×