SlideShare a Scribd company logo
1 of 42
Kotlin for Java Developers
Agenda (non-linear)
• Basic language concepts
• Examples of the Kotlin Standard Library
• Coroutines
• Language performance characteristics
• Goal of this talk: to introduce Kotlin, not to teach it
What is Kotlin?
• Introduced in 2011 by JetBrains (the Intellij folks)
• Goal was to offer a “better Java”, not unlike Scala, but without Scala’s
slow compilation times
• Compiles to JVM bytecode, as well as JavaScript and native binaries
for various operating systems, including Android and iOS
• Kotlin can call Java libraries, and Java can call Kotlin libraries (with
limitations)
• https://kotlinfoundation.org/ - Backed by JetBrains, Google, Gradle
and more.
Why Kotlin?
• Whereas Scala adds “everything”, Kotlin adds “just enough”
• Well thought out “syntactic sugar”makes for a much more expressive
language, without becoming inaccessible
• While still evolving, backwards compatibility is prioritized
• Excellent Intellij support, but also a good Eclipse plugin
• Intellij can convert your Java code to Kotlin for you!
• The language of choice for Android development, and the the default
DSL for new Gradle builds
HelloWorld.kt
fun main() {
println("Hello, World")
}
public final class HelloWorldKt {
public static final void main() {
System.out.println("Hello, World");
}
public static void main(String[] var0) {
main();
}
}
Semicolon
inference
HelloWorld2.kt
class HelloWorld2 {
companion object {
@JvmStatic
fun main(args:
Array<String>) {
println("Hello, World")
}
}
}
How Kotlin
does static
public final class HelloWorld2 {
public static final Companion Companion =
new Companion();
public static final void main(String[] args) {
Companion.main(args);
}
public static final class Companion {
public final void main(String[] args) {
System.out.println("Hello, World");
}
private Companion() {
// object in Kotlin is a singleton
}
}
}
Functions
fun double(n: Int): Int {
return n * 2
}
Type follows name
Single expression function
Type inference
Equivalent to : Unit
fun quadruple(n: Int) = n * 4
fun say(text: String): Unit {
println(text)
}
fun shout(text: String) {
println(text.toUpperCase())
}
fun triple(n: Int): Int = n * 3
Default and named parameters
fun log(message: String, level: String = "INFO", logger: String = "DEFAULT") =
println("$logger [$level] $message")
fun main() {
log("all is well")
log("uh oh", "WARN")
log(logger = "THERMAL", level = "FATAL", message = "Fire!")
}
• Convenient way to do method overloading
• Named arguments in constructors largely eliminate the need for the Builder
Pattern
DEFAULT [INFO] all is well
DEFAULT [WARN] uh oh
THERMAL [FATAL] Fire!
class Person(val name: String, var age: Int, heightInInches: Int) {
private val heightInCm: Int = (heightInInches * 2.54).toInt()
val heightInMeters: Double
get() = heightInCm / 100.0
fun failHeightInMeters(): Double = heightInInches * 0.0254
// ❌Unresolved reference: heightInInches
}
fun main() {
val founder = Person("Jeff", 58, 67)
val name = founder.name
// time marches on
founder.age = 59
}
Classes
public static final void main() {
Person founder = new Person(”Jeff", 58, 67);
String name = founder.getName(); // not field reference!
// time marches on
founder.setAge(55); // not field reference!
}
Final
property
Mutable
property
No “new”
Just a constructor
parameter, not a property
Data Classes
data class RgbColor(val red: Int, val blue: Int, val green: Int)
Class body optional
fun main() {
val yellow = RgbColor(255, 255, 0)
println(yellow) // prints "RgbColor(red=255, blue=255, green=0)"
if (yellow == RgbColor(255, 255, 0)) { // auto-generated equals
println("matches")
}
val magenta = yellow.copy(blue = 0, green = 255)
val (r, g, b) = yellow // destructuring
}
.equals(…)
Null Safety – Optional as a language feature
class Contact(val name: String, val phone: String?)
fun produce() {
val noPhone = Contact("Bob", null) // OK
val noName = Contact(null, "867-5309") // ❌Null can not be a value of a non-null type String
}
fun consume(contact: Contact) {
val nameLength: String = contact.name.length // OK
val phoneLength = contact.phone.length
// ❌ Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type String?
val nullablePhoneLength = contact.phone?.length // type: Int?
val jenny = Contact("Jenny", "867-5309")
val phone: String = jenny.phone!! // could throw NPE
}
Nullable
Non-nullable
Branching
fun salutations(arriving: Boolean) {
if(arriving) {
println("hello")
}
else {
println("goodbye")
}
}
fun salutations2(arriving: Boolean): String = if(arriving) "hello" else "goodbye" //ternary
fun size(item: Any): Int = when(item) {
"meaning of life" -> 42
is String -> item.length
is Collection<*> -> item.size
is Number -> item.toInt()
else -> throw IllegalArgumentException("cannot determine size of $item")
}
item is “smart cast”
String template
Looping
fun repeatGreet(times: Int) {
for (i in 1..times) {
println("hello $i")
}
}
fun repeatGreetExpanded(times: Int) {
val range = IntRange(1, times)
for (i in range) {
println("hello $i")
}
}
public void repeatGreet(int times) {
for (int i = 1; i <= times; i++) {
System.out.println("hello");
}
}
public void repeatGreetExpanded(int times) {
IntRange range = new IntRange(1, times);
int var1 = range.getLast();
for (int i = 1; i <= var1; i++) {
System.out.println("hello");
}
}
Extension methods
fun Int.double() = this * 2
fun Int?.add(summand: Int) = (this ?: 0) + summand
fun main() {
println(5.double()) // 10
println(5.add(3)) // 8
println(null.add(3)) // 3
}
• Syntactic Sugar for static methods whose first argument is the
receiver type
• Extension methods must be imported to be used
• Many StdLib extension methods are auto-imported.
Can apply to null
Functional Parameters / Lambdas
functional
signature
fun transform(n: Int, transformer: (Int) -> Int) {
println("$n maps to ${transformer(n)}")
}
fun main() {
transform(3, {i -> i * 2})
transform(4) {i -> i * 3}
transform(5) { it * 4 }
fun square(n: Int) = n * n
transform(6, ::square)
}
function
invocation
3 maps to 6
4 maps to 12
5 maps to 20
6 maps to 36
last param lambda syntax
“it” for single parameter
method reference
Inline Functions
inline fun <T> maxBy(a: T, b: T, ranker: (T) -> Int) =
if (ranker(a) > ranker(b)) a else b
• If possible, invocations will be replaced with function body
• Especially useful for megamorphic call sites in loops.
• Used extensively in the Kotlin Collections API and other Standard Library
functions (as appropriate)
• Allows for clean syntax without performance penalties
• ⚠️ Changes require recompilation of client code
arrayOf("a", "b", "c", "d").forEach(::println) // traditional for loop
Value Classes – type safety, for free
public final class CustomerId {
private final long id;
private CustomerId(long id) { this.id = id; }
public final long getId() { return this.id; }
public static long constructor_impl (long id) {
return id; }
}
public static final void delete_cos_Kmc(long
custId) {
System.out.println("Hasta la vista, " + custId);
}
public static final void main() {
long customerId =
CustomerId.constructor_impl(123L);
delete_cos_Kmc(customerId);
@JvmInline
value class CustomerId(val id:
Long)
fun delete(custId: CustomerId) {
println("Hasta la vista,
${custId.id}")
}
fun main() {
val customerId =
CustomerId(123)
delete(customerId);
}
Infix Functions
public infix fun Int.downTo(to: Int): IntProgression {
return IntProgression.fromClosedRange(this, to, -1)
}
for (i in 5 downTo 1) { println(i) }
Invokes IntProgression.iterator()
public infix fun <A, B> A.to(that: B): Pair<A, B> = Pair(this, that)
mapOf(1 to "one", 2 to "two")
Scope Functions
• Extension methods applied to all types
• Act like language features, but are just library functions
• Provide for useful idioms
Scope Functions - let
public inline fun <T, R> T.let(block: (T) -> R): R {
return block(this)
}
• Particularly useful for working only on non-null objects
someMap.get(key)?.let { println("$key maps to $it") }
Scope Functions - apply
public inline fun <T> T.apply(block: T.() -> Unit): T {
block()
return this
}
• Useful for configuring objects without creating a temp var
class Order { // as if it came from a Java library
var productName: String? = null
var quantity: Int? = null
}
fun makeOrder() = Order().apply { // "this" refers to Order
this.productName = "BeDazzler"
quantity = 2 // this. not actually needed
}
Function type with receiver
Scope Functions - with
public inline fun <T, R> with(receiver: T, block: T.() -> R): R {
return receiver.block()
}
• Useful for referencing an object repeatedly
fun describe(order: Order) = with(order) {
"order for $quantity of $productName"
}
Scope Functions - use
public inline fun <T : Closeable?, R> T.use(block: (T) -> R): R {
try {
return block(this)
} finally {
this?.close()
}
}
• Like Java’s try-with-resources
FileOutputStream("foo").use { it.write("Hello".toByteArray()) }
Kotlin Collections API
• Built on top of Java’s Collections API
• Collections have mutable and immutable variants, but only at API
level (“immutable” collections can be cast to mutable ones and
mutated)
• Lots of transformation APIs, implemented as extension methods
• Sequences are similar to java Streams, but are reusable.
• Familiar methods: map, flatMap, filter, groupBy, etc.
• Also: associate, takeWhile, filterNotNull, etc.
• Factory methods: listOf, mutableListOf, mapOf, mutableMapOf, setOf,
etc.
Kotlin Collections API
• Built on top of Java’s Collections API
• Lots of additional methods added as extension methods
• “Immutable” versions of collections
• Tranformation methods available without using Streams
• Sequences for stream-like laziness
Kotlin Collections Basics
val names: List<String> = listOf("Gosling", "Block", "Goetz")
println(names[2]) // operator overload for names.get(2)
val capitols: Map<String, String> = mapOf(
"Utah" to "Salt Lake City",
"Idaho" to "Boise")
println(capitols["Utah"]) // capitols.get("Utah")
val nums: List<Int> = (1 .. 4).toList()
val evens: List<Int> = nums.filter { it % 2 == 0}
val evensAndOdds: Pair<List<Int>, List<Int>> = nums.partition { it %
2 == 0 }
val mod3: Map<Int, List<Int>> = nums.groupBy { it % 3 }
val squares: Map<Int, Int> = nums.associate { it to it * it }
val cubes: Map<Int, Int> = nums.associateWith { it * it * it }
Goetz
Salt Lake City
[1, 2, 3, 4]
[2, 4]
([2, 4], [1, 3])
{1=[1, 4], 2=[2], 0=[3]}
{1=1, 2=4, 3=9, 4=16}
{1=1, 2=8, 3=27, 4=64}
Kotlin Sequences – like Java Streams
fun negate(n:Int): Int {
println("negating $n")
return -n;
}
fun main() {
val seq = (1..1000).asSequence()
seq.map(::negate).take(2).forEach(::println)
println("Unlike Streams, Sequences are
reusable")
seq.map(::negate).take(2).forEach(::println)
}
negating 1
-1
negating 2
-2
Unlike Streams, Sequences are reusable
negating 1
-1
negating 2
-2
Kotlin Collections: Mutablility
val numbers: List<Int> = (1..10).toList()
numbers.add(11) // compiler error: no such method
val mutableNumbers: MutableList<Int> =
numbers.toMutableList()
mutableNumbers.add(11)
ListProcessor.process(numbers)
println(numbers)
println(numbers.javaClass.name)
public class ListProcessor { // java class
public static void process(List<?> list) {
list.remove(0);
}
}
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
[2, 3, 4, 5, 6, 7, 8, 9, 10]
java.util.ArrayList
Coroutines
• Similar to project Loom, but without JVM support
• Special compiler logic to generate reentrant methods
• Support for deferred evaluation
• Support for reactive-type idioms
• Support for actors
Concurrency Example – single thread
fun main() = runBlocking { // run a top-level coroutine
launch { // launch a new coroutine and continue
delay(1000L) // non-blocking delay for 1 second
log("World!")
}
log("Hello")
}
main [320] - Hello
main [1335] - World!
Helper method –
Prints thread name,
elapsed time and message
Concurrency Example – multiple threads
fun main() = runBlocking(Dispatchers.IO) {
for (i in 1..2) {
launch {
log("$i before yield")
yield()
log("$i after yield")
}
}
log("Hello")
}
DefaultDispatcher-worker-2 [309] - 2 before yield
DefaultDispatcher-worker-3 [310] - 1 before yield
DefaultDispatcher-worker-1 [310] - Hello
DefaultDispatcher-worker-3 [314] - 2 after yield
DefaultDispatcher-worker-2 [314] - 1 after yield
Uses elastic thread pool
Different thread
after delay
Under the hood
• Coroutine method is compiled to a class
• Class has a label attribute that determines where to pick up
execution
• Local variables are stored in class fields.
• Essentially, coroutine compilation shifts the burden of the stack onto
the heap.
Under the hood
{
delay(1000L)
log("World!")
}
public final class BasicCoroutine extends SuspendLambda {
private int label = 0;
@Nullable
public final Object invokeSuspend() {
switch (this.label) {
case 0:
DelayKt.delay(1000L, this);
this.label = 1;
return Intrinsics.COROUTINE_SUSPENDED;
case 1:
LoggingKt.log("World!");
return Unit.INSTANCE;
}
}
}
Suspendable functions
fun main() = runBlocking {
launch {
delay(1000L)
log("World!")
}
log("Hello")
}
fun main() = runBlocking {
launch {
world()
}
log("Hello")
}
private suspend fun world() {
delay(1000L)
log("World!")
}
Cannot be called without
suspend modifier
Deferred results with async {…}
private suspend fun fetchQuote(provider: String): Int {
delay(1000) // simulate network delay
log("quote fetched for $provider")
return provider.length
}
fun main() {
runBlocking {
val quote1: Deferred<Int> = async { fetchQuote("StateFarm") }
val quote2: Deferred<Int> = async { fetchQuote("AllState") }
log("awaiting quotes")
val lowestQuote = Math.min(quote1.await(), quote2.await())
log("min quote: $lowestQuote")
}
} main [385] - awaiting quotes
main [1393] - quote fetched for StateFarm
main [1396] - quote fetched for AllState
main [1397] - min quote: 8
Channels
• A Channel<T> supports
• send(value: T)
• receive(): T
• close()
• isClosedForReceive(): Boolean
• A channel has a capacity:
• > 0 – can hold this many elements, then sending blocked
• 0 – a rendezvous channel
• CONFLATED – receive() just returns the most recent sent value; older
values dropped
Channels – example
fun main() {
val channel = Channel<Int>(CONFLATED)
runBlocking {
launch {
for (i in 1..6) {
delay(400)
channel.send(i)
}
channel.close()
}
while (!channel.isClosedForReceive) {
log("received ${channel.receive()}")
delay(1000)
}
}
}
main [718] - received 1
main [1719] - received 3
main [2721] - received 6
Actors
• Actor – a coroutine with state
• Other coroutines communicate with it by sending messages to a
dedicate channel
• An actor is guaranteed to process messages serially, useful for
managing mutable state
Actor Example: Counter
sealed interface CounterMessage
object Increment: CounterMessage
class GetCount(val response: CompletableDeferred<Int>): CounterMessage
fun CoroutineScope.counterActor() = actor<CounterMessage> {
var counter: Int = 0
for (message in channel) {
when(message) {
is Increment -> counter++
is GetCount -> message.response.complete(counter)
}
}
}
Method on CoroutineScope
Actor Example: Counter (continued)
fun main() {
runBlocking(Dispatchers.Default) { // this: CoroutineScope
val actor = counterActor()
val incrementJobs: List<Job> = (1..20).map {
launch {repeat(10000) { actor.send(Increment) } }
}
while(incrementJobs.any(Job::isActive)) {
delay(100)
val response = CompletableDeferred<Int>()
actor.send(GetCount(response))
log("count: ${response.await()}")
}
actor.close() // allow Coroutine to finish
}
}
DefaultDispatcher-worker-8 [454] - count: 10840
DefaultDispatcher-worker-7 [557] - count: 69607
DefaultDispatcher-worker-4 [658] - count: 117329
DefaultDispatcher-worker-11 [761] - count: 166297
DefaultDispatcher-worker-2 [863] - count: 200000
Adopting Kotlin
• https://kotlinlang.org/ is an excellent source.
• Get buy-in from team members first! Brown-bags can help
• Try starting with unit tests
• Use IntelliJ to auto-convert some code; some hand-tuning may be
required.
• Lombok can work with Kotlin, but really isn’t needed.
• Not all classes need to be converted from Java.
• But you may find yourself temped after a bit!
Questions
interface Question {}
interface Audience {
fun questions(): Sequence<Question>
}
fun answerQuestions(audience: Audience) {
for(question in audience.questions()) {
answer(question)
}
}
fun answer(question: Question) {
println("Let me get back to you")
}

More Related Content

Similar to KotlinForJavaDevelopers-UJUG.pptx

Denis Lebedev, Swift
Denis  Lebedev, SwiftDenis  Lebedev, Swift
Denis Lebedev, Swift
Yandex
 

Similar to KotlinForJavaDevelopers-UJUG.pptx (20)

Coding for Android on steroids with Kotlin
Coding for Android on steroids with KotlinCoding for Android on steroids with Kotlin
Coding for Android on steroids with Kotlin
 
Denis Lebedev, Swift
Denis  Lebedev, SwiftDenis  Lebedev, Swift
Denis Lebedev, Swift
 
Kotlin - The Swiss army knife of programming languages - Visma Mobile Meet-up...
Kotlin - The Swiss army knife of programming languages - Visma Mobile Meet-up...Kotlin - The Swiss army knife of programming languages - Visma Mobile Meet-up...
Kotlin - The Swiss army knife of programming languages - Visma Mobile Meet-up...
 
ECSE 221 - Introduction to Computer Engineering - Tutorial 1 - Muhammad Ehtas...
ECSE 221 - Introduction to Computer Engineering - Tutorial 1 - Muhammad Ehtas...ECSE 221 - Introduction to Computer Engineering - Tutorial 1 - Muhammad Ehtas...
ECSE 221 - Introduction to Computer Engineering - Tutorial 1 - Muhammad Ehtas...
 
Kotlin, smarter development for the jvm
Kotlin, smarter development for the jvmKotlin, smarter development for the jvm
Kotlin, smarter development for the jvm
 
Lezione03
Lezione03Lezione03
Lezione03
 
Lezione03
Lezione03Lezione03
Lezione03
 
Kotlin / Android Update
Kotlin / Android UpdateKotlin / Android Update
Kotlin / Android Update
 
Davide Cerbo - Kotlin: forse è la volta buona - Codemotion Milan 2017
Davide Cerbo - Kotlin: forse è la volta buona - Codemotion Milan 2017 Davide Cerbo - Kotlin: forse è la volta buona - Codemotion Milan 2017
Davide Cerbo - Kotlin: forse è la volta buona - Codemotion Milan 2017
 
Mastering Kotlin Standard Library
Mastering Kotlin Standard LibraryMastering Kotlin Standard Library
Mastering Kotlin Standard Library
 
Android Application Development (1).pptx
Android Application Development (1).pptxAndroid Application Development (1).pptx
Android Application Development (1).pptx
 
Meetup di GDG Italia - Leonardo Pirro - Codemotion Rome 2018
Meetup di GDG Italia - Leonardo Pirro -  Codemotion Rome 2018 Meetup di GDG Italia - Leonardo Pirro -  Codemotion Rome 2018
Meetup di GDG Italia - Leonardo Pirro - Codemotion Rome 2018
 
Summer of Tech 2017 - Kotlin/Android bootcamp
Summer of Tech 2017 - Kotlin/Android bootcampSummer of Tech 2017 - Kotlin/Android bootcamp
Summer of Tech 2017 - Kotlin/Android bootcamp
 
Introduction to kotlin
Introduction to kotlinIntroduction to kotlin
Introduction to kotlin
 
Introduction to Kotlin.pptx
Introduction to Kotlin.pptxIntroduction to Kotlin.pptx
Introduction to Kotlin.pptx
 
01 Introduction to Kotlin - Programming in Kotlin.pptx
01 Introduction to Kotlin - Programming in Kotlin.pptx01 Introduction to Kotlin - Programming in Kotlin.pptx
01 Introduction to Kotlin - Programming in Kotlin.pptx
 
devLink - What's New in C# 4?
devLink - What's New in C# 4?devLink - What's New in C# 4?
devLink - What's New in C# 4?
 
Kotlin cheat sheet by ekito
Kotlin cheat sheet by ekitoKotlin cheat sheet by ekito
Kotlin cheat sheet by ekito
 
Android 101 - Building a simple app with Kotlin in 90 minutes
Android 101 - Building a simple app with Kotlin in 90 minutesAndroid 101 - Building a simple app with Kotlin in 90 minutes
Android 101 - Building a simple app with Kotlin in 90 minutes
 
IntroToCSharpcode.ppt
IntroToCSharpcode.pptIntroToCSharpcode.ppt
IntroToCSharpcode.ppt
 

Recently uploaded

Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
panagenda
 

Recently uploaded (20)

"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ..."I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
 
Navi Mumbai Call Girls 🥰 8617370543 Service Offer VIP Hot Model
Navi Mumbai Call Girls 🥰 8617370543 Service Offer VIP Hot ModelNavi Mumbai Call Girls 🥰 8617370543 Service Offer VIP Hot Model
Navi Mumbai Call Girls 🥰 8617370543 Service Offer VIP Hot Model
 
FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
Apidays Singapore 2024 - Modernizing Securities Finance by Madhu Subbu
Apidays Singapore 2024 - Modernizing Securities Finance by Madhu SubbuApidays Singapore 2024 - Modernizing Securities Finance by Madhu Subbu
Apidays Singapore 2024 - Modernizing Securities Finance by Madhu Subbu
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
Corporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptxCorporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptx
 
AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CV
 
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWEREMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
Ransomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdfRansomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdf
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 
A Beginners Guide to Building a RAG App Using Open Source Milvus
A Beginners Guide to Building a RAG App Using Open Source MilvusA Beginners Guide to Building a RAG App Using Open Source Milvus
A Beginners Guide to Building a RAG App Using Open Source Milvus
 

KotlinForJavaDevelopers-UJUG.pptx

  • 1. Kotlin for Java Developers
  • 2. Agenda (non-linear) • Basic language concepts • Examples of the Kotlin Standard Library • Coroutines • Language performance characteristics • Goal of this talk: to introduce Kotlin, not to teach it
  • 3. What is Kotlin? • Introduced in 2011 by JetBrains (the Intellij folks) • Goal was to offer a “better Java”, not unlike Scala, but without Scala’s slow compilation times • Compiles to JVM bytecode, as well as JavaScript and native binaries for various operating systems, including Android and iOS • Kotlin can call Java libraries, and Java can call Kotlin libraries (with limitations) • https://kotlinfoundation.org/ - Backed by JetBrains, Google, Gradle and more.
  • 4. Why Kotlin? • Whereas Scala adds “everything”, Kotlin adds “just enough” • Well thought out “syntactic sugar”makes for a much more expressive language, without becoming inaccessible • While still evolving, backwards compatibility is prioritized • Excellent Intellij support, but also a good Eclipse plugin • Intellij can convert your Java code to Kotlin for you! • The language of choice for Android development, and the the default DSL for new Gradle builds
  • 5. HelloWorld.kt fun main() { println("Hello, World") } public final class HelloWorldKt { public static final void main() { System.out.println("Hello, World"); } public static void main(String[] var0) { main(); } } Semicolon inference
  • 6. HelloWorld2.kt class HelloWorld2 { companion object { @JvmStatic fun main(args: Array<String>) { println("Hello, World") } } } How Kotlin does static public final class HelloWorld2 { public static final Companion Companion = new Companion(); public static final void main(String[] args) { Companion.main(args); } public static final class Companion { public final void main(String[] args) { System.out.println("Hello, World"); } private Companion() { // object in Kotlin is a singleton } } }
  • 7. Functions fun double(n: Int): Int { return n * 2 } Type follows name Single expression function Type inference Equivalent to : Unit fun quadruple(n: Int) = n * 4 fun say(text: String): Unit { println(text) } fun shout(text: String) { println(text.toUpperCase()) } fun triple(n: Int): Int = n * 3
  • 8. Default and named parameters fun log(message: String, level: String = "INFO", logger: String = "DEFAULT") = println("$logger [$level] $message") fun main() { log("all is well") log("uh oh", "WARN") log(logger = "THERMAL", level = "FATAL", message = "Fire!") } • Convenient way to do method overloading • Named arguments in constructors largely eliminate the need for the Builder Pattern DEFAULT [INFO] all is well DEFAULT [WARN] uh oh THERMAL [FATAL] Fire!
  • 9. class Person(val name: String, var age: Int, heightInInches: Int) { private val heightInCm: Int = (heightInInches * 2.54).toInt() val heightInMeters: Double get() = heightInCm / 100.0 fun failHeightInMeters(): Double = heightInInches * 0.0254 // ❌Unresolved reference: heightInInches } fun main() { val founder = Person("Jeff", 58, 67) val name = founder.name // time marches on founder.age = 59 } Classes public static final void main() { Person founder = new Person(”Jeff", 58, 67); String name = founder.getName(); // not field reference! // time marches on founder.setAge(55); // not field reference! } Final property Mutable property No “new” Just a constructor parameter, not a property
  • 10. Data Classes data class RgbColor(val red: Int, val blue: Int, val green: Int) Class body optional fun main() { val yellow = RgbColor(255, 255, 0) println(yellow) // prints "RgbColor(red=255, blue=255, green=0)" if (yellow == RgbColor(255, 255, 0)) { // auto-generated equals println("matches") } val magenta = yellow.copy(blue = 0, green = 255) val (r, g, b) = yellow // destructuring } .equals(…)
  • 11. Null Safety – Optional as a language feature class Contact(val name: String, val phone: String?) fun produce() { val noPhone = Contact("Bob", null) // OK val noName = Contact(null, "867-5309") // ❌Null can not be a value of a non-null type String } fun consume(contact: Contact) { val nameLength: String = contact.name.length // OK val phoneLength = contact.phone.length // ❌ Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type String? val nullablePhoneLength = contact.phone?.length // type: Int? val jenny = Contact("Jenny", "867-5309") val phone: String = jenny.phone!! // could throw NPE } Nullable Non-nullable
  • 12. Branching fun salutations(arriving: Boolean) { if(arriving) { println("hello") } else { println("goodbye") } } fun salutations2(arriving: Boolean): String = if(arriving) "hello" else "goodbye" //ternary fun size(item: Any): Int = when(item) { "meaning of life" -> 42 is String -> item.length is Collection<*> -> item.size is Number -> item.toInt() else -> throw IllegalArgumentException("cannot determine size of $item") } item is “smart cast” String template
  • 13. Looping fun repeatGreet(times: Int) { for (i in 1..times) { println("hello $i") } } fun repeatGreetExpanded(times: Int) { val range = IntRange(1, times) for (i in range) { println("hello $i") } } public void repeatGreet(int times) { for (int i = 1; i <= times; i++) { System.out.println("hello"); } } public void repeatGreetExpanded(int times) { IntRange range = new IntRange(1, times); int var1 = range.getLast(); for (int i = 1; i <= var1; i++) { System.out.println("hello"); } }
  • 14. Extension methods fun Int.double() = this * 2 fun Int?.add(summand: Int) = (this ?: 0) + summand fun main() { println(5.double()) // 10 println(5.add(3)) // 8 println(null.add(3)) // 3 } • Syntactic Sugar for static methods whose first argument is the receiver type • Extension methods must be imported to be used • Many StdLib extension methods are auto-imported. Can apply to null
  • 15. Functional Parameters / Lambdas functional signature fun transform(n: Int, transformer: (Int) -> Int) { println("$n maps to ${transformer(n)}") } fun main() { transform(3, {i -> i * 2}) transform(4) {i -> i * 3} transform(5) { it * 4 } fun square(n: Int) = n * n transform(6, ::square) } function invocation 3 maps to 6 4 maps to 12 5 maps to 20 6 maps to 36 last param lambda syntax “it” for single parameter method reference
  • 16. Inline Functions inline fun <T> maxBy(a: T, b: T, ranker: (T) -> Int) = if (ranker(a) > ranker(b)) a else b • If possible, invocations will be replaced with function body • Especially useful for megamorphic call sites in loops. • Used extensively in the Kotlin Collections API and other Standard Library functions (as appropriate) • Allows for clean syntax without performance penalties • ⚠️ Changes require recompilation of client code arrayOf("a", "b", "c", "d").forEach(::println) // traditional for loop
  • 17. Value Classes – type safety, for free public final class CustomerId { private final long id; private CustomerId(long id) { this.id = id; } public final long getId() { return this.id; } public static long constructor_impl (long id) { return id; } } public static final void delete_cos_Kmc(long custId) { System.out.println("Hasta la vista, " + custId); } public static final void main() { long customerId = CustomerId.constructor_impl(123L); delete_cos_Kmc(customerId); @JvmInline value class CustomerId(val id: Long) fun delete(custId: CustomerId) { println("Hasta la vista, ${custId.id}") } fun main() { val customerId = CustomerId(123) delete(customerId); }
  • 18. Infix Functions public infix fun Int.downTo(to: Int): IntProgression { return IntProgression.fromClosedRange(this, to, -1) } for (i in 5 downTo 1) { println(i) } Invokes IntProgression.iterator() public infix fun <A, B> A.to(that: B): Pair<A, B> = Pair(this, that) mapOf(1 to "one", 2 to "two")
  • 19. Scope Functions • Extension methods applied to all types • Act like language features, but are just library functions • Provide for useful idioms
  • 20. Scope Functions - let public inline fun <T, R> T.let(block: (T) -> R): R { return block(this) } • Particularly useful for working only on non-null objects someMap.get(key)?.let { println("$key maps to $it") }
  • 21. Scope Functions - apply public inline fun <T> T.apply(block: T.() -> Unit): T { block() return this } • Useful for configuring objects without creating a temp var class Order { // as if it came from a Java library var productName: String? = null var quantity: Int? = null } fun makeOrder() = Order().apply { // "this" refers to Order this.productName = "BeDazzler" quantity = 2 // this. not actually needed } Function type with receiver
  • 22. Scope Functions - with public inline fun <T, R> with(receiver: T, block: T.() -> R): R { return receiver.block() } • Useful for referencing an object repeatedly fun describe(order: Order) = with(order) { "order for $quantity of $productName" }
  • 23. Scope Functions - use public inline fun <T : Closeable?, R> T.use(block: (T) -> R): R { try { return block(this) } finally { this?.close() } } • Like Java’s try-with-resources FileOutputStream("foo").use { it.write("Hello".toByteArray()) }
  • 24. Kotlin Collections API • Built on top of Java’s Collections API • Collections have mutable and immutable variants, but only at API level (“immutable” collections can be cast to mutable ones and mutated) • Lots of transformation APIs, implemented as extension methods • Sequences are similar to java Streams, but are reusable. • Familiar methods: map, flatMap, filter, groupBy, etc. • Also: associate, takeWhile, filterNotNull, etc. • Factory methods: listOf, mutableListOf, mapOf, mutableMapOf, setOf, etc.
  • 25. Kotlin Collections API • Built on top of Java’s Collections API • Lots of additional methods added as extension methods • “Immutable” versions of collections • Tranformation methods available without using Streams • Sequences for stream-like laziness
  • 26. Kotlin Collections Basics val names: List<String> = listOf("Gosling", "Block", "Goetz") println(names[2]) // operator overload for names.get(2) val capitols: Map<String, String> = mapOf( "Utah" to "Salt Lake City", "Idaho" to "Boise") println(capitols["Utah"]) // capitols.get("Utah") val nums: List<Int> = (1 .. 4).toList() val evens: List<Int> = nums.filter { it % 2 == 0} val evensAndOdds: Pair<List<Int>, List<Int>> = nums.partition { it % 2 == 0 } val mod3: Map<Int, List<Int>> = nums.groupBy { it % 3 } val squares: Map<Int, Int> = nums.associate { it to it * it } val cubes: Map<Int, Int> = nums.associateWith { it * it * it } Goetz Salt Lake City [1, 2, 3, 4] [2, 4] ([2, 4], [1, 3]) {1=[1, 4], 2=[2], 0=[3]} {1=1, 2=4, 3=9, 4=16} {1=1, 2=8, 3=27, 4=64}
  • 27. Kotlin Sequences – like Java Streams fun negate(n:Int): Int { println("negating $n") return -n; } fun main() { val seq = (1..1000).asSequence() seq.map(::negate).take(2).forEach(::println) println("Unlike Streams, Sequences are reusable") seq.map(::negate).take(2).forEach(::println) } negating 1 -1 negating 2 -2 Unlike Streams, Sequences are reusable negating 1 -1 negating 2 -2
  • 28. Kotlin Collections: Mutablility val numbers: List<Int> = (1..10).toList() numbers.add(11) // compiler error: no such method val mutableNumbers: MutableList<Int> = numbers.toMutableList() mutableNumbers.add(11) ListProcessor.process(numbers) println(numbers) println(numbers.javaClass.name) public class ListProcessor { // java class public static void process(List<?> list) { list.remove(0); } } [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] [2, 3, 4, 5, 6, 7, 8, 9, 10] java.util.ArrayList
  • 29. Coroutines • Similar to project Loom, but without JVM support • Special compiler logic to generate reentrant methods • Support for deferred evaluation • Support for reactive-type idioms • Support for actors
  • 30. Concurrency Example – single thread fun main() = runBlocking { // run a top-level coroutine launch { // launch a new coroutine and continue delay(1000L) // non-blocking delay for 1 second log("World!") } log("Hello") } main [320] - Hello main [1335] - World! Helper method – Prints thread name, elapsed time and message
  • 31. Concurrency Example – multiple threads fun main() = runBlocking(Dispatchers.IO) { for (i in 1..2) { launch { log("$i before yield") yield() log("$i after yield") } } log("Hello") } DefaultDispatcher-worker-2 [309] - 2 before yield DefaultDispatcher-worker-3 [310] - 1 before yield DefaultDispatcher-worker-1 [310] - Hello DefaultDispatcher-worker-3 [314] - 2 after yield DefaultDispatcher-worker-2 [314] - 1 after yield Uses elastic thread pool Different thread after delay
  • 32. Under the hood • Coroutine method is compiled to a class • Class has a label attribute that determines where to pick up execution • Local variables are stored in class fields. • Essentially, coroutine compilation shifts the burden of the stack onto the heap.
  • 33. Under the hood { delay(1000L) log("World!") } public final class BasicCoroutine extends SuspendLambda { private int label = 0; @Nullable public final Object invokeSuspend() { switch (this.label) { case 0: DelayKt.delay(1000L, this); this.label = 1; return Intrinsics.COROUTINE_SUSPENDED; case 1: LoggingKt.log("World!"); return Unit.INSTANCE; } } }
  • 34. Suspendable functions fun main() = runBlocking { launch { delay(1000L) log("World!") } log("Hello") } fun main() = runBlocking { launch { world() } log("Hello") } private suspend fun world() { delay(1000L) log("World!") } Cannot be called without suspend modifier
  • 35. Deferred results with async {…} private suspend fun fetchQuote(provider: String): Int { delay(1000) // simulate network delay log("quote fetched for $provider") return provider.length } fun main() { runBlocking { val quote1: Deferred<Int> = async { fetchQuote("StateFarm") } val quote2: Deferred<Int> = async { fetchQuote("AllState") } log("awaiting quotes") val lowestQuote = Math.min(quote1.await(), quote2.await()) log("min quote: $lowestQuote") } } main [385] - awaiting quotes main [1393] - quote fetched for StateFarm main [1396] - quote fetched for AllState main [1397] - min quote: 8
  • 36. Channels • A Channel<T> supports • send(value: T) • receive(): T • close() • isClosedForReceive(): Boolean • A channel has a capacity: • > 0 – can hold this many elements, then sending blocked • 0 – a rendezvous channel • CONFLATED – receive() just returns the most recent sent value; older values dropped
  • 37. Channels – example fun main() { val channel = Channel<Int>(CONFLATED) runBlocking { launch { for (i in 1..6) { delay(400) channel.send(i) } channel.close() } while (!channel.isClosedForReceive) { log("received ${channel.receive()}") delay(1000) } } } main [718] - received 1 main [1719] - received 3 main [2721] - received 6
  • 38. Actors • Actor – a coroutine with state • Other coroutines communicate with it by sending messages to a dedicate channel • An actor is guaranteed to process messages serially, useful for managing mutable state
  • 39. Actor Example: Counter sealed interface CounterMessage object Increment: CounterMessage class GetCount(val response: CompletableDeferred<Int>): CounterMessage fun CoroutineScope.counterActor() = actor<CounterMessage> { var counter: Int = 0 for (message in channel) { when(message) { is Increment -> counter++ is GetCount -> message.response.complete(counter) } } } Method on CoroutineScope
  • 40. Actor Example: Counter (continued) fun main() { runBlocking(Dispatchers.Default) { // this: CoroutineScope val actor = counterActor() val incrementJobs: List<Job> = (1..20).map { launch {repeat(10000) { actor.send(Increment) } } } while(incrementJobs.any(Job::isActive)) { delay(100) val response = CompletableDeferred<Int>() actor.send(GetCount(response)) log("count: ${response.await()}") } actor.close() // allow Coroutine to finish } } DefaultDispatcher-worker-8 [454] - count: 10840 DefaultDispatcher-worker-7 [557] - count: 69607 DefaultDispatcher-worker-4 [658] - count: 117329 DefaultDispatcher-worker-11 [761] - count: 166297 DefaultDispatcher-worker-2 [863] - count: 200000
  • 41. Adopting Kotlin • https://kotlinlang.org/ is an excellent source. • Get buy-in from team members first! Brown-bags can help • Try starting with unit tests • Use IntelliJ to auto-convert some code; some hand-tuning may be required. • Lombok can work with Kotlin, but really isn’t needed. • Not all classes need to be converted from Java. • But you may find yourself temped after a bit!
  • 42. Questions interface Question {} interface Audience { fun questions(): Sequence<Question> } fun answerQuestions(audience: Audience) { for(question in audience.questions()) { answer(question) } } fun answer(question: Question) { println("Let me get back to you") }