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 - Boost Your
Productivity
By Nklmish
@nklmish
Jetbrains
• Develops tools dedicated for
software developers.

• Large code base written in
Java (IDE and server side
tool...
Back in 2010, Jetbrains were
looking for a language…
Java Interoperability
Can use existing Java code base & eco system
Re...
Why not X language ?
• “Most languages did not have the features we were
looking for, with the exception of Scala” - Dmitr...
Kotlin
• Open source programming language.

• Targets : Server side, client side web, mobile and
native.

• First commit -...
Why Kotlin ?
Java Interoperability
We can use existing Java code & libraries as well

As call Java code from Kotlin and vi...
Let’s Get Started!
@nklmish
Hello
fun main(args: Array<String>) {
println("Hello")
}
@nklmish
Hello - source code level
fun main(args: Array<String>) {
println("Hello")
}
kotlin.Array
@nklmish
Hello - source code level
fun main(args: Array<String>) {
println("Hello")
}
kotlin.String
@nklmish
Hello - source code level
fun main(args: Array<String>) {
println("Hello")
}
kotlin.io.println
@nklmish
Hello- bytecode level
public final class com/nklmish/presentation/demo/s/_00Kt {
// access flags 0x19
public final static ...
But how?
Let’s understand build process
@nklmish
Variable
@nklmish
List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3));
val list: List<Int> = listOf(1, 2, 3)
Java...
Variable
@nklmish
List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3));
val list: List<Int> = listOf(1, 2, 3)
Java...
Variable
@nklmish
List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3));
val list = listOf(1, 2, 3)
Java Kotlin
Typ...
Variable
@nklmish
List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3));
val list = listOf(1, 2, 3)
Java Kotlin
Int...
Function
@nklmish
Function
fun calculateBonus(base : Int, factor : Double) : Double {
return base * factor
}
@nklmish
Function
fun calculateBonus(base : Int, factor : Double) : Double {
return base * factor
}
Single Expression ?
@nklmish
Function
fun calculateBonus(base : Int, factor : Double) : Double {
return base * factor
}
Single Expression ?
Can be omit...
Function
fun calculateBonus(base : Int, factor : Double) : Double = base * factor
@nklmish
Function
fun calculateBonus(base : Int, factor : Double) : Double = base * factor
Type Inference
@nklmish
Function
fun calculateBonus(base : Int, factor : Double) = base * factor
@nklmish
Useful ?
Function
fun calculateBonus(base : Int, factor : Double) = base * factor
@nklmish
Concise +
refactor
Infix function == function
prefixed with “infix”
Must be a member/

extension function
@nklmish
Must take only one parameter
...
Infix function - real life
@nklmish
"should assign a default state for a newly launched game" {
game.states.count() shouldB...
Extension functions ==
replace utility classes
@nklmish
fun LocalDateTime.toDate(): Date = Date.from(this.toInstant(Offset...
Higher order function
@nklmish
fun calculateTotal(amount : Double, exchange: (Double) -> Double) : Double {
val convertedA...
Higher order function
@nklmish
fun calculateTotal(amount : Double, exchange: (Double) -> Double) : Double {
val convertedA...
Higher order function
fun calculateTotal(amount : Double, exchange: (Double) -> Double) : Double {
val convertedAmount = e...
Inline function == avoid
runtime overhead
@nklmish
inline fun calculateTotal(amount : Double, exchange: (Double) -> Double...
Inline function == avoid
runtime overhead
@nklmish
inline fun calculateTotal(amount : Double, exchange: (Double) -> Double...
Inline function lambda
bytecode
@nklmish
inline fun calculateTotal(amount : Double, exchange: (Double) -> Double) : Double...
Inline function - time
measurement
@nklmish
val elapsedTime = measureTimeMillis { //execute the given code & returns elaps...
Inline + reified == access
generic type info
@nklmish
@Suppress("UNCHECKED_CAST")
fun <T> Node.parent(clazz: Class<T>): T? ...
Function literal with
receiver == recipe for DSL
@nklmish
class Delivery {
fun person(function: Person.() -> Unit) : Perso...
Function literal with
receiver == recipe for DSL
@nklmish
class Delivery {
fun person(function: Person.() -> Unit) : Perso...
Function literal with
receiver == recipe for DSL
@nklmish
delivery({ })
Syntactic sugar (if lambda is last argument)
deliv...
Function literal with
receiver == recipe for DSL
@nklmish
Function literal with
receiver == recipe for DSL
@nklmish
class Delivery {
fun person(function: Person.() -> Unit) : Perso...
Function literal with
receiver == recipe for DSL
@nklmish
delivery {
person {
name = "Bob"
surname = "Smith"
}
address {
c...
Real life DSL - Anko
verticalLayout {
val name = editText()
button("Say Hello") {
onClick { toast("Hello, ${name.text}!") ...
Real life DSL - GradleKotlinDSL
https://github.com/gradle/kotlin-dsl @nklmish
Overloading - Java
@nklmish
Overloading - Java
Which argument is which ?
@nklmish
Overloading - Kotlin
fun print(firstName : String, middleName: String = "", lastName : String = "") = { println("$firstNam...
Overloading - Kotlin
fun print(firstName : String, middleName: String = "", lastName : String = "") = println("$firstName ...
Classes
@nklmish
Class - Java
public class Schedule {
private final LocalDateTime start;
private final LocalDateTime end;
private String no...
Class - Kotlin
class Schedule(val start: LocalDateTime, val end: LocalDateTime, var note : String)
@nklmish
Class - Kotlin
class Schedule(val start: LocalDateTime, val end: LocalDateTime, var note : String)
Default: public and fina...
Class - Kotlin
class Schedule(val start: LocalDateTime, val end: LocalDateTime, var note : String)
Properties
@nklmish
Class - Kotlin
class Schedule(val start: LocalDateTime, val end: LocalDateTime, var note : String)
Immutable Immutable
@nk...
Class - Kotlin
class Schedule(val start: LocalDateTime, val end: LocalDateTime, var note : String)
Mutable
@nklmish
Data class == data holders
data class Schedule(val start : LocalDateTime, val end : LocalDateTime)
@nklmish
Data class
data class Schedule(val start : LocalDateTime, val end : LocalDateTime)
Autogenerate: meaningful toString(), co...
Data class - copy()
val schedule = Schedule(LocalDateTime.now(), LocalDateTime.now().plusSeconds(1))
val copy = schedule.c...
Data class - validation
data class Schedule(val start : LocalDateTime, val end : LocalDateTime) {
init {
if (end.isBefore(...
Sealed class ~ extension of
enum classes
sealed class Bonus {
data class Yearly(val amount : BigDecimal) : Bonus()
data cl...
Sealed class ~ extension of
enum classes
sealed class Bonus {
data class Yearly(val amount : BigDecimal) : Bonus()
data cl...
Delegation
@nklmish
Delegation
class NetworkChaosSimulator{
private ChaosSwitch chaosSwitch = new DefaultSwitch();
public void enableActivatio...
Delegated properties
• Wrap objects with custom behaviour.
@nklmish
Lazy
• Create a new instance only when an object get accessed
for the very first time.
@nklmish
Lazy
class GameRound(val player : String) {
val bets by lazy { fetchBets(this) }
private fun fetchBets(gameRound: GameRoun...
Lazy - thread safety ?
class GameRound(val player : String) {
val bets by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {...
Lazy - thread safety ?
class GameRound(val player : String) {
val bets by lazy(mode = LazyThreadSafetyMode.PUBLICATION) { ...
Lazy - thread safety ?
class GameRound(val player : String) {
val bets by lazy(mode = LazyThreadSafetyMode.NONE) { fetchBe...
Lambda
@nklmish
players.filter({p -> p.score > 70})
@nklmish
players.filter({p -> p.score > 70})
players.filter() {p -> p.score > 70}
players.filter {p -> p.score > 70}
players.filter...
• Allows to invoke methods of different object (w/o any
qualifiers) inside there body.
@nklmish@nklmish
with receiver
@nklmi...
@nklmish@nklmish@nklmish
public String toCSVFormat(List<Integer> list) {
StringBuilder sb = new StringBuilder("[");
for (I...
@nklmish@nklmish@nklmish
public String toCSVFormat(List<Integer> list) {
StringBuilder sb = new StringBuilder("[");
for (I...
Safety
@nklmish
Null safety - baked into type
system
@nklmish
var message : String = "hello"
message = null // compile time error
var mess...
Null safety - using Java API
from Kotlin?
• Annotate Java code with nullability annotations.

• Kotlin can understand anno...
Misc
@nklmish
For loop - Java
for (int i = 0; i < 10; i++) {
System.out.println(i);
}
@nklmish
For loop - Kotlin
Progressions - to rescue
for (i in 0..9) println(i)
@nklmish
Progressions - to rescue
for (i in 0..9) println(i)
Lots of useful methods : downTo(), stepTo(), until…
@nklmish
Collection
• No Kotlin specific collections.

• Kotlin Collection == Java collection classes + enrichment.
@nklmish
Collection
Immutable
Mutable
@nklmish
Typealias
• Synonyms for pre-existing types
Typealias - without
fun main(args: Array<String>) {
val map : Map<String,String> = mapOf("Bob" to "North Avenue")
}
@nklmi...
Typealias - with
typealias FirstName = String
typealias Street = String
fun main(args: Array<String>) {
val map : Map<Firs...
Casting - Java
Object obj = "Any"
if (obj instanceof String) {
String str = (String) obj;
str.toUpperCase();
}
@nklmish
Casting - Kotlin (smartcast)
val obj:Any = "Any"
if (obj is String) {
obj.toUpperCase() // compiler smartness, auto cast t...
Deprecation
@Deprecated(level = DeprecationLevel.WARNING,
message = "we are going to replace with StringUtils",
replaceWit...
Deprecation
@Deprecated(level = DeprecationLevel.WARNING,
message = "we are going to replace with StringUtils",
replaceWit...
Deprecation
@Deprecated(level = DeprecationLevel.WARNING,
message = "we are going to replace with StringUtils",
replaceWit...
Deprecation
@Deprecated(level = DeprecationLevel.WARNING,
message = "we are going to replace with StringUtils",
replaceWit...
Deprecation - final result
@nklmish
when == powerful switch
fun playerPrivileges(rank : Int) = when(rank) {
in 1..3 -> "VIP"
in 4..50 -> "Elevated"
in 51..100...
when == powerful switch
fun playerPrivileges(rank : Int) = when(rank) {
in 1..3 -> "VIP"
in 4..50 -> "Elevated"
in 51..100...
when == powerful switch
fun playerPrivileges(rank : Int) = when(rank) {
in 1..3 -> "VIP"
in 4..50 -> "Elevated"
in 51..100...
Operator overloading -
Java?public class Wallet {
public Wallet(Integer amount) {
this.amount = amount;
}
private final In...
Operator overloading -
Kotlin
data class Wallet(val amount : Int) {
operator fun plus(w : Wallet) = Wallet(amount.plus(w.a...
Operator overloading -
Kotlin
Naming Convention Syntax
plus walletA + walletB
unaryPlus +walletA
minus walletA - walletB
u...
Co-routines == asyn
programming made simple
@nklmish
val jobs = List(1_000_000) {
async(CommonPool) {
delay(10L)
1.0
}
}
r...
Co-routines == asyn
programming made simple
@nklmish
val jobs = List(1_000_000) {
async(CommonPool) {
delay(10L)
1.0
}
}
r...
TODO
@nklmish
Kotlin + Spring
@nklmish
Kotlin + Spring
@nklmish
Kotlin + Spring -
build.gradle
@nklmish
dependencies {
classpath("org.jetbrains.kotlin:kotlin-allopen:$kotlinVersion")
}
Kotlin + Spring -
build.gradle
@nklmish
dependencies {
classpath("org.jetbrains.kotlin:kotlin-allopen:$kotlinVersion")
}
B...
Kotlin + Spring -
build.gradle
@nklmish
dependencies {
classpath("org.jetbrains.kotlin:kotlin-allopen:$kotlinVersion")
}
@...
Kotlin + Spring - controller
@nklmish
Kotlin + Spring - controller
@nklmish
Constructor injection(no @Autowired required)
Kotlin + Spring - controller
@nklmish
Type Inference
Kotlin + Spring - 

null safety?
@nklmish
@GetMapping("/schedule")
fun getSchedule(@RequestParam id: Long): Mono<ScheduleD...
Kotlin + Spring - null safety
@nklmish
Kotlin + Spring
@nklmish
@GetMapping(path = arrayOf("/schedules"), produces = arrayOf(TEXT_EVENT_STREAM_VALUE))
fun getSch...
Who uses Kotlin…
• Amazon

• Uber

• Netflix

• Foursquare

• Expedia

• HSBC

• Goldman Sachs

• Trello

• Casumo

• …
@nk...
Useful links
• http://slack.kotlinlang.org/

• https://kotlin.link/
@nklmish
Questions?
https://tinyurl.com/y9lgkpc8
@nklmish
Review
Upcoming SlideShare
Loading in …5
×

Kotlin boost yourproductivity

2,702 views

Published on

Slides from my presentation on Kotlin

Published in: Technology
  • Be the first to comment

Kotlin boost yourproductivity

  1. 1. Kotlin - Boost Your Productivity By Nklmish @nklmish
  2. 2. Jetbrains • Develops tools dedicated for software developers. • Large code base written in Java (IDE and server side tools). • E.g. IntelliJ-Community edition, 3M+ lines of Java code. @nklmish
  3. 3. Back in 2010, Jetbrains were looking for a language… Java Interoperability Can use existing Java code base & eco system Reduce boilerplate code Concise Expressive Easy tooling Should be easy to prepare tooling for the language Pragmatic Solve real world problem @nklmish
  4. 4. Why not X language ? • “Most languages did not have the features we were looking for, with the exception of Scala” - Dmitry Jemerov • So why not Scala? • Slow compilation time • Tooling @nklmish
  5. 5. Kotlin • Open source programming language. • Targets : Server side, client side web, mobile and native. • First commit - 8 Nov 2010, First release - 15 Feb 2016 • Gaining momentum - 20K+ repos and millions of lines of code • Google officially support it for android development. @nklmish
  6. 6. Why Kotlin ? Java Interoperability We can use existing Java code & libraries as well As call Java code from Kotlin and vice-versa Null safety baked into type system Safe Statically Typed Easy tooling Pragmatic Reduce boilerplate code Concise Expressive Small Learning Curve Java developers can leverage there existing knowledge Support Both
  7. 7. Let’s Get Started! @nklmish
  8. 8. Hello fun main(args: Array<String>) { println("Hello") } @nklmish
  9. 9. Hello - source code level fun main(args: Array<String>) { println("Hello") } kotlin.Array @nklmish
  10. 10. Hello - source code level fun main(args: Array<String>) { println("Hello") } kotlin.String @nklmish
  11. 11. Hello - source code level fun main(args: Array<String>) { println("Hello") } kotlin.io.println @nklmish
  12. 12. Hello- bytecode level public final class com/nklmish/presentation/demo/s/_00Kt { // access flags 0x19 public final static main([Ljava/lang/String;)V @Lorg/jetbrains/annotations/NotNull;() // invisible, parameter 0 L0 ALOAD 0 LDC "args" INVOKESTATIC kotlin/jvm/internal/Intrinsics.checkParameterIsNotNull (Ljava/lang/Object;Ljava/lang/String;)V L1 LINENUMBER 7 L1 LDC "Hello" ASTORE 1 L2 GETSTATIC java/lang/System.out : Ljava/io/PrintStream; ALOAD 1 INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)V L3 L4 LINENUMBER 8 L4 RETURN L5 LOCALVARIABLE args [Ljava/lang/String; L0 L5 0 MAXSTACK = 2 MAXLOCALS = 2 @Lkotlin/Metadata;(mv={1, 1, 7}, bv={1, 0, 2}, k=2, d1={"u0000u0014nu0000nu0002u0010u0002nu0000nu0002u0010u0011nu0002u0010u000enu0002u0008u0002u001au0019u0010u0000u0 01au00020u00012u000cu0010u0002u001au0008u0012u0004u0012u00020u00040u0003u00a2u0006u0002u0010u0005u00a8u0006u0006"}, d2={"main", "", "args", "", "", "([Ljava/lang/String;)V", "production sources for module kotlin-presentation_main"}) // compiled from: 00.kt // debug info: SMAP 00.kt Kotlin *S Kotlin *F + 1 00.kt com/nklmish/presentation/demo/s/_00Kt *L 1#1,8:1 *E} @nklmish
  13. 13. But how?
  14. 14. Let’s understand build process @nklmish
  15. 15. Variable @nklmish List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3)); val list: List<Int> = listOf(1, 2, 3) Java Kotlin
  16. 16. Variable @nklmish List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3)); val list: List<Int> = listOf(1, 2, 3) Java Kotlin Why Opposite ?
  17. 17. Variable @nklmish List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3)); val list = listOf(1, 2, 3) Java Kotlin Type inference
  18. 18. Variable @nklmish List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3)); val list = listOf(1, 2, 3) Java Kotlin IntelliJ view!
  19. 19. Function @nklmish
  20. 20. Function fun calculateBonus(base : Int, factor : Double) : Double { return base * factor } @nklmish
  21. 21. Function fun calculateBonus(base : Int, factor : Double) : Double { return base * factor } Single Expression ? @nklmish
  22. 22. Function fun calculateBonus(base : Int, factor : Double) : Double { return base * factor } Single Expression ? Can be omitted @nklmish
  23. 23. Function fun calculateBonus(base : Int, factor : Double) : Double = base * factor @nklmish
  24. 24. Function fun calculateBonus(base : Int, factor : Double) : Double = base * factor Type Inference @nklmish
  25. 25. Function fun calculateBonus(base : Int, factor : Double) = base * factor @nklmish Useful ?
  26. 26. Function fun calculateBonus(base : Int, factor : Double) = base * factor @nklmish Concise + refactor
  27. 27. Infix function == function prefixed with “infix” Must be a member/
 extension function @nklmish Must take only one parameter class Stack { infix fun push(num : Int) { // } } fun main(args: Array<String>) { val stack = Stack() stack push 1 } class Stack { fun push(num : Int) { // } } fun main(args: Array<String>) { val stack = Stack() stack.push(1) }
  28. 28. Infix function - real life @nklmish "should assign a default state for a newly launched game" { game.states.count() shouldBe 1 } val map = mapOf("Bob" to "123 North Avenue") kotlintest Kotlin
  29. 29. Extension functions == replace utility classes @nklmish fun LocalDateTime.toDate(): Date = Date.from(this.toInstant(OffsetDateTime.now().offset))
  30. 30. Higher order function @nklmish fun calculateTotal(amount : Double, exchange: (Double) -> Double) : Double { val convertedAmount = exchange(amount) return convertedAmount + (convertedAmount * 0.23) }
  31. 31. Higher order function @nklmish fun calculateTotal(amount : Double, exchange: (Double) -> Double) : Double { val convertedAmount = exchange(amount) return convertedAmount + (convertedAmount * 0.23) } calculateTotal(100.00) { amount -> amount * 4.5 } calculateTotal(100.00) { amount -> amount * 3.7 } Invocation
  32. 32. Higher order function fun calculateTotal(amount : Double, exchange: (Double) -> Double) : Double { val convertedAmount = exchange(amount) return convertedAmount + (convertedAmount * 0.23) } calculateTotal(100.00) { amount -> amount * 4.5 } calculateTotal(100.00) { amount -> amount * 3.7 } Lambda, extra cost (Wrapper Function), worried about runtime overhead ? @nklmish
  33. 33. Inline function == avoid runtime overhead @nklmish inline fun calculateTotal(amount : Double, exchange: (Double) -> Double) : Double { val convertedAmount = exchange(amount) return convertedAmount + (convertedAmount * 0.23) }
  34. 34. Inline function == avoid runtime overhead @nklmish inline fun calculateTotal(amount : Double, exchange: (Double) -> Double) : Double { val convertedAmount = exchange(amount) return convertedAmount + (convertedAmount * 0.23) } Compiler will replace this call with inline (copy and paste) code
  35. 35. Inline function lambda bytecode @nklmish inline fun calculateTotal(amount : Double, exchange: (Double) -> Double) : Double { val convertedAmount = exchange(amount) return convertedAmount + (convertedAmount * 0.23) } calculateTotal(100.00) { amount -> amount * 4.5 } calculateTotal(100.00) { amount -> amount * 3.7 }
  36. 36. Inline function - time measurement @nklmish val elapsedTime = measureTimeMillis { //execute the given code & returns elapsed time in ms. calculateTotal(100.00) { amount -> amount * 4.5 } } val elapsedTime = measureNanoTime { //execute the given block & returns elapsed time in ns. ... } Inline functions
  37. 37. Inline + reified == access generic type info @nklmish @Suppress("UNCHECKED_CAST") fun <T> Node.parent(clazz: Class<T>): T? { var tmp = parent while (tmp != null && !clazz.isInstance(tmp)) tmp = tmp.parent return tmp as T? } //invocation node.parent(Node::class.java) Without reified inline fun <reified T> Node.parent(): T? { var tmp = parent while (p != null && p !is T) tmp = tmp.parent return p as T? } //invocation node.parent<Node>() Reified
  38. 38. Function literal with receiver == recipe for DSL @nklmish class Delivery { fun person(function: Person.() -> Unit) : Person { ... } fun address(function: Address.() -> Unit) : Address { ... } } fun delivery(function: Delivery.() -> Unit): Delivery { ... } Extension fun on Delivery
  39. 39. Function literal with receiver == recipe for DSL @nklmish class Delivery { fun person(function: Person.() -> Unit) : Person { ... } fun address(function: Address.() -> Unit) : Address { ... } } fun delivery(function: Delivery.() -> Unit): Delivery { ... } Extension fun on Delivery => we can access
  40. 40. Function literal with receiver == recipe for DSL @nklmish delivery({ }) Syntactic sugar (if lambda is last argument) delivery() { }== delivery { }== Calling function “delivery” passing lambda as argument
  41. 41. Function literal with receiver == recipe for DSL @nklmish
  42. 42. Function literal with receiver == recipe for DSL @nklmish class Delivery { fun person(function: Person.() -> Unit) : Person { ... } fun address(function: Address.() -> Unit) : Address { ... } } fun delivery(function: Delivery.() -> Unit): Delivery { ... } fun onTransit(function: () -> Unit) : TransitInfo { … } fun sendSMS(message: String) { ... } Extension fun on Delivery Extension fun on Address Extension fun on Person Higher Order Function
  43. 43. Function literal with receiver == recipe for DSL @nklmish delivery { person { name = "Bob" surname = "Smith" } address { city = “paris" street = "abc street" postalCode = "12345" onTransit { sendSMS("...") } } } Final Result
  44. 44. Real life DSL - Anko verticalLayout { val name = editText() button("Say Hello") { onClick { toast("Hello, ${name.text}!") } } } https://github.com/Kotlin/anko @nklmish
  45. 45. Real life DSL - GradleKotlinDSL https://github.com/gradle/kotlin-dsl @nklmish
  46. 46. Overloading - Java @nklmish
  47. 47. Overloading - Java Which argument is which ? @nklmish
  48. 48. Overloading - Kotlin fun print(firstName : String, middleName: String = "", lastName : String = "") = { println("$firstName $middleName $lastName”) } fun main(args: Array<String>) { print(firstName = "john") print(firstName = "john", lastName = "smith") print(firstName = "john", middleName = "mac", lastName = "smith") } Default value Default value @nklmish
  49. 49. Overloading - Kotlin fun print(firstName : String, middleName: String = "", lastName : String = "") = println("$firstName $middleName $lastName") fun main(args: Array<String>) { print(firstName = "john") print(firstName = "john", lastName = "smith") print(firstName = "john", middleName = "mac", lastName = "smith") } Named arguments can further improve readability
  50. 50. Classes @nklmish
  51. 51. Class - Java public class Schedule { private final LocalDateTime start; private final LocalDateTime end; private String notes; public Schedule(LocalDateTime start, LocalDateTime end) { this.start = start; this.end = end; } public LocalDateTime getStart() { return start; } public LocalDateTime getEnd() { return end; } public String getNotes() { return notes; } public void setNotes(String notes) { this.notes = notes; } } @nklmish
  52. 52. Class - Kotlin class Schedule(val start: LocalDateTime, val end: LocalDateTime, var note : String) @nklmish
  53. 53. Class - Kotlin class Schedule(val start: LocalDateTime, val end: LocalDateTime, var note : String) Default: public and final @nklmish
  54. 54. Class - Kotlin class Schedule(val start: LocalDateTime, val end: LocalDateTime, var note : String) Properties @nklmish
  55. 55. Class - Kotlin class Schedule(val start: LocalDateTime, val end: LocalDateTime, var note : String) Immutable Immutable @nklmish
  56. 56. Class - Kotlin class Schedule(val start: LocalDateTime, val end: LocalDateTime, var note : String) Mutable @nklmish
  57. 57. Data class == data holders data class Schedule(val start : LocalDateTime, val end : LocalDateTime) @nklmish
  58. 58. Data class data class Schedule(val start : LocalDateTime, val end : LocalDateTime) Autogenerate: meaningful toString(), copy(), equals(), hashcode() @nklmish
  59. 59. Data class - copy() val schedule = Schedule(LocalDateTime.now(), LocalDateTime.now().plusSeconds(1)) val copy = schedule.copy() val copyWithModifiedEndDate = schedule.copy(end = schedule.end.plusSeconds(1)) // we can change specific fields during copy, comes handy during unit testing @nklmish
  60. 60. Data class - validation data class Schedule(val start : LocalDateTime, val end : LocalDateTime) { init { if (end.isBefore(start)) throw IllegalArgumentException("end $end should be after start $start") } } @nklmish String interpolation Note: String interpolation comes handy when dealing with JSON strings. e.g. private val expectedServerContent = """ {"name":"$canonicalName","json":"{"id":"$expectedGameProviderId"}","data":{"@foo":".bar","number":"123"},"policy":"","password":""} """.trimIndent()
  61. 61. Sealed class ~ extension of enum classes sealed class Bonus { data class Yearly(val amount : BigDecimal) : Bonus() data class Monthly(val amount : BigDecimal, val factor : BigDecimal) : Bonus() } @nklmish Each enum constant exists only as 
 a single instance Enum Subclass of a sealed class can have multiple instances which can contain state Sealed class
  62. 62. Sealed class ~ extension of enum classes sealed class Bonus { data class Yearly(val amount : BigDecimal) : Bonus() data class Monthly(val amount : BigDecimal, val factor : BigDecimal) : Bonus() } fun evaluate(bonus: Bonus) = when(bonus) { is Yearly -> bonus.amount is Monthly -> bonus.amount.multiply(bonus.factor) } Abstract class @nklmish
  63. 63. Delegation @nklmish
  64. 64. Delegation class NetworkChaosSimulator{ private ChaosSwitch chaosSwitch = new DefaultSwitch(); public void enableActivationChaos() { chaosSwitch.enableActivationChaos(); } public void disableActivationChaos() { chaosSwitch.disableActivationChaos(); } public void enableDeactivationChaos() { chaosSwitch.enableDeactivationChaos(); } public void disableDeactivationChaos() { chaosSwitch.disableDeactivationChaos(); } public boolean isActivationChaosEnabled() { return chaosSwitch.isActivationChaosEnabled(); } public boolean isDeactivationChaosEnabled() { return chaosSwitch.isDeactivationChaosEnabled(); } } @nklmish class NetworkChaosSimulator(switch: ChaosSwitch = DefaultSwitch()) : ChaosSwitch by switch Java Kotlin
  65. 65. Delegated properties • Wrap objects with custom behaviour. @nklmish
  66. 66. Lazy • Create a new instance only when an object get accessed for the very first time. @nklmish
  67. 67. Lazy class GameRound(val player : String) { val bets by lazy { fetchBets(this) } private fun fetchBets(gameRound: GameRound): Int { ... } } @nklmish
  68. 68. Lazy - thread safety ? class GameRound(val player : String) { val bets by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { fetchBets(this) } private fun fetchBets(gameRound: GameRound): Int { ... } } Only a single thread can initialise the Lazy instance. @nklmish
  69. 69. Lazy - thread safety ? class GameRound(val player : String) { val bets by lazy(mode = LazyThreadSafetyMode.PUBLICATION) { fetchBets(this) } private fun fetchBets(gameRound: GameRound): Int { ... } } Concurrent access permissible but only first returned value will be used. @nklmish
  70. 70. Lazy - thread safety ? class GameRound(val player : String) { val bets by lazy(mode = LazyThreadSafetyMode.NONE) { fetchBets(this) } private fun fetchBets(gameRound: GameRound): Int { ... } } multiple threads == undefined behaviour @nklmish There are more builtin delegated properties like notNull, observable, etc. We can also create our own.
  71. 71. Lambda @nklmish
  72. 72. players.filter({p -> p.score > 70}) @nklmish
  73. 73. players.filter({p -> p.score > 70}) players.filter() {p -> p.score > 70} players.filter {p -> p.score > 70} players.filter {it.score > 70} syntactic sugar Implicit name for a single parameter @nklmish
  74. 74. • Allows to invoke methods of different object (w/o any qualifiers) inside there body. @nklmish@nklmish with receiver @nklmish
  75. 75. @nklmish@nklmish@nklmish public String toCSVFormat(List<Integer> list) { StringBuilder sb = new StringBuilder("["); for (Integer integer : list) { sb.append(integer).append(“;"); } sb.deleteCharAt(sb.length() - 1); sb.append("]"); return sb.toString(); } Java Kotlin : with (returns result of last call) fun toCSVFormat(list: List<Int>) = with(StringBuilder()) { append("[") for (i in list) { append(i).append(";") } deleteCharAt(length - 1) append("]") toString() } with receiver - with
  76. 76. @nklmish@nklmish@nklmish public String toCSVFormat(List<Integer> list) { StringBuilder sb = new StringBuilder("["); for (Integer integer : list) { sb.append(integer).append(“;"); } sb.deleteCharAt(sb.length() - 1); sb.append("]"); return sb.toString(); } Java Kotlin : apply (returns the receiver) fun toCSVFormat(list: List<Int>) = StringBuilder().apply { append("[") for (i in list) { append(i).append(";") } deleteCharAt(length - 1) append("]") }.toString() with receiver - apply
  77. 77. Safety @nklmish
  78. 78. Null safety - baked into type system @nklmish var message : String = "hello" message = null // compile time error var message : String? = "hello" message = null // ok println(message?.length) //safe operator, if not null then invoke length Java message?.let { process(it) } Kotlin if (message != null) { process(message); }
  79. 79. Null safety - using Java API from Kotlin? • Annotate Java code with nullability annotations. • Kotlin can understand annotations from: • Jetbrains (org.jetbrains.annotations) • JSR-305 (javax.annotation) • Android (android.support.annotation) @nklmish
  80. 80. Misc @nklmish
  81. 81. For loop - Java for (int i = 0; i < 10; i++) { System.out.println(i); } @nklmish
  82. 82. For loop - Kotlin
  83. 83. Progressions - to rescue for (i in 0..9) println(i) @nklmish
  84. 84. Progressions - to rescue for (i in 0..9) println(i) Lots of useful methods : downTo(), stepTo(), until… @nklmish
  85. 85. Collection • No Kotlin specific collections. • Kotlin Collection == Java collection classes + enrichment. @nklmish
  86. 86. Collection Immutable Mutable @nklmish
  87. 87. Typealias • Synonyms for pre-existing types
  88. 88. Typealias - without fun main(args: Array<String>) { val map : Map<String,String> = mapOf("Bob" to "North Avenue") } @nklmish Less semantics
  89. 89. Typealias - with typealias FirstName = String typealias Street = String fun main(args: Array<String>) { val map : Map<FirstName, Street> = mapOf("Bob" to "North Avenue") } @nklmish Better Semantics
  90. 90. Casting - Java Object obj = "Any" if (obj instanceof String) { String str = (String) obj; str.toUpperCase(); } @nklmish
  91. 91. Casting - Kotlin (smartcast) val obj:Any = "Any" if (obj is String) { obj.toUpperCase() // compiler smartness, auto cast to String // Works only, if obj is immutable or 
 // haven’t changed after check } @nklmish
  92. 92. Deprecation @Deprecated(level = DeprecationLevel.WARNING, message = "we are going to replace with StringUtils", replaceWith = @ReplaceWith( expression = "StringUtils.isEmpty(input)", imports = {"org.apache.commons.lang3.StringUtils"}) ) public static boolean isEmpty(String input) { ... } @nklmish
  93. 93. Deprecation @Deprecated(level = DeprecationLevel.WARNING, message = "we are going to replace with StringUtils", replaceWith = @ReplaceWith( expression = "StringUtils.isEmpty(input)", imports = {"org.apache.commons.lang3.StringUtils"}) ) public static boolean isEmpty(String input) { ... } level: Warning, Error, Hidden @nklmish
  94. 94. Deprecation @Deprecated(level = DeprecationLevel.WARNING, message = "we are going to replace with StringUtils", replaceWith = @ReplaceWith( expression = "StringUtils.isEmpty(input)", imports = {"org.apache.commons.lang3.StringUtils"}) ) public static boolean isEmpty(String input) { ... } Method to replace with @nklmish
  95. 95. Deprecation @Deprecated(level = DeprecationLevel.WARNING, message = "we are going to replace with StringUtils", replaceWith = @ReplaceWith( expression = "StringUtils.isEmpty(input)", imports = {"org.apache.commons.lang3.StringUtils"}) ) public static boolean isEmpty(String input) { ... } Which class to import @nklmish
  96. 96. Deprecation - final result @nklmish
  97. 97. when == powerful switch fun playerPrivileges(rank : Int) = when(rank) { in 1..3 -> "VIP" in 4..50 -> "Elevated" in 51..1000 -> "Classic" else -> "Regular" } @nklmish
  98. 98. when == powerful switch fun playerPrivileges(rank : Int) = when(rank) { in 1..3 -> "VIP" in 4..50 -> "Elevated" in 51..1000 -> "Classic" else -> "Regular" } Can be any type, no limitations @nklmish
  99. 99. when == powerful switch fun playerPrivileges(rank : Int) = when(rank) { in 1..3 -> "VIP" in 4..50 -> "Elevated" in 51..1000 -> "Classic" else -> "Regular" } No need to type break @nklmish
  100. 100. Operator overloading - Java?public class Wallet { public Wallet(Integer amount) { this.amount = amount; } private final Integer amount; public Wallet plus(Wallet w) { return new Wallet(this.amount + w.amount); } public Wallet minus(Wallet w) { return new Wallet(this.amount - w.amount); } public Wallet multiply(Wallet w) { return new Wallet(this.amount * w.amount); } } Wallet walletA = new Wallet(100); Wallet walletB = new Wallet(200); walletA.plus(walletB); walletA.subtract(walletB); walletA.multiply(walletB); @nklmish
  101. 101. Operator overloading - Kotlin data class Wallet(val amount : Int) { operator fun plus(w : Wallet) = Wallet(amount.plus(w.amount)) operator fun minus(w : Wallet) = Wallet(amount.minus(w.amount)) operator fun times(w : Wallet) = Wallet(amount.minus(w.amount)) } val walletA = Wallet(100) val walletB = Wallet(200) walletA + walletB walletA - walletB walletA * walletB @nklmish
  102. 102. Operator overloading - Kotlin Naming Convention Syntax plus walletA + walletB unaryPlus +walletA minus walletA - walletB unaryMinus -walletA inc ++walletA dec — walletA times walletA * walletB div walletA / walletB mod walletA % walletB not !walletA @nklmish
  103. 103. Co-routines == asyn programming made simple @nklmish val jobs = List(1_000_000) { async(CommonPool) { delay(10L) 1.0 } } runBlocking { println(jobs.sumByDouble { it.await() }) }
  104. 104. Co-routines == asyn programming made simple @nklmish val jobs = List(1_000_000) { async(CommonPool) { delay(10L) 1.0 } } runBlocking { println(jobs.sumByDouble { it.await() }) } Lightweight
  105. 105. TODO @nklmish
  106. 106. Kotlin + Spring @nklmish
  107. 107. Kotlin + Spring @nklmish
  108. 108. Kotlin + Spring - build.gradle @nklmish dependencies { classpath("org.jetbrains.kotlin:kotlin-allopen:$kotlinVersion") }
  109. 109. Kotlin + Spring - build.gradle @nklmish dependencies { classpath("org.jetbrains.kotlin:kotlin-allopen:$kotlinVersion") } Before plugin After Plugin @SpringBootApplication open class PhoneBookApplication { @Bean open fun passwordEncoder(): PasswordEncoder { return BCryptPasswordEncoder() } } @SpringBootApplication class PhoneBookApplication { @Bean fun passwordEncoder(): PasswordEncoder { return BCryptPasswordEncoder() } }
  110. 110. Kotlin + Spring - build.gradle @nklmish dependencies { classpath("org.jetbrains.kotlin:kotlin-allopen:$kotlinVersion") } @Document data class Contact(@Id val id: String = UUID.randomUUID().toString(), val firstName: String, var lastName: String, val phones: List<String> = emptyList() )
  111. 111. Kotlin + Spring - controller @nklmish
  112. 112. Kotlin + Spring - controller @nklmish Constructor injection(no @Autowired required)
  113. 113. Kotlin + Spring - controller @nklmish Type Inference
  114. 114. Kotlin + Spring - 
 null safety? @nklmish @GetMapping("/schedule") fun getSchedule(@RequestParam id: Long): Mono<ScheduleDto> = scheduleService.findOne(id).map { it.get().dto() } @GetMapping("/schedule") fun getSchedule(@RequestParam id: Long?): Mono<ScheduleDto> = scheduleService.findOne(id).map { it.get().dto() }
  115. 115. Kotlin + Spring - null safety @nklmish
  116. 116. Kotlin + Spring @nklmish @GetMapping(path = arrayOf("/schedules"), produces = arrayOf(TEXT_EVENT_STREAM_VALUE)) fun getSchedules(): Flux<ScheduleDto> = scheduleService.findAll().map { it.dto() } route( path(“/schedules”).and(accept(TEXT_EVENT_STREAM_VALUE)), ) Same thing expressed in Kotlin
  117. 117. Who uses Kotlin… • Amazon • Uber • Netflix • Foursquare • Expedia • HSBC • Goldman Sachs • Trello • Casumo • … @nklmish
  118. 118. Useful links • http://slack.kotlinlang.org/ • https://kotlin.link/ @nklmish
  119. 119. Questions? https://tinyurl.com/y9lgkpc8 @nklmish Review

×