8000000 10000000 12000000 2010 2012 2013 2014 2015 2016 2017 2018 Kotlin is born Release 1.0 Gradle Spring Official Android Release 1.1 Dedicated Kotlin support for Spring 5.0 LOC
Programming Language Coding Conventions • Types start with Uppercase • Methods and Properties in lower camelCase • Semicolons are (almost) optional • Packages follow the reverse notation • be.kotlin.training.basics • Package does not have to match the folder name.
and expressions Kotlin if is an expression as most other control structures, except for the loops. Java all control structures are statements Expression vs Statement has a value can be used as a part of another expression has no value always top level element
Mutable and Immutable variables var => variable “mutable” val => value “immutable” Can’t be reassigned final in Java Can be reassigned regular (non-final) Java variable
and loops rangeTo val range = 1 .. 4 val start = 1 val end = 4 val otherRange = start .. end downTo val range = 4 downTo 1 val start = 4 val end = 1 val otherRange = start downTo end
Modifier Class member Top-level declaration public (default) Visible everywhere Visible everywhere internal Visible in a module Visible in a module protected Visible in subclasses - private Visible in a class Visible in a file
/* Java */ public class Person { private final String name; public Person(String name) { this.name = name; } public String getName() { return name; } }
• Classes /* Java */ public class Person { private final String name; public Person(String name) { this.name = name; } public String getName() { return name; } }
class Person( val name: String, var isMarried: Boolean ) Writeable property: generates a field, a getter and a setter Read-only property: generates a field and a trivial getter
//custom getters and setters class Person(val id: Int, var name: String, val yearOfBirth: Int){ val age: Int get() = Calendar.getInstance().get(Calendar.YEAR) - yearOfBirth var socialSecurityNumber: String = "" set(value) { if(!value.startsWith("SN")){ throw IllegalArgumentException("Social security number should start with SN") } field = value } //function in a class fun personAsString(){ println("Id: $id - Name: $name - Birthdate: $yearOfBirth ") } }
//custom getters and setters class Person(val id: Int, var name: String, val yearOfBirth: Int){ val age: Int get() = Calendar.getInstance().get(Calendar.YEAR) - yearOfBirth var socialSecurityNumber: String = "" set(value) { if(!value.startsWith("SN")){ throw IllegalArgumentException("Social security number should start with SN") } field = value } //function in a class fun personAsString(){ println("Id: $id - Name: $name - Birthdate: $yearOfBirth ") } }
//custom getters and setters class Person(val id: Int, var name: String, val yearOfBirth: Int){ val age: Int get() = Calendar.getInstance().get(Calendar.YEAR) - yearOfBirth var socialSecurityNumber: String = "" set(value) { if(!value.startsWith("SN")){ throw IllegalArgumentException("Social security number should start with SN") } field = value } //function in a class fun personAsString(){ println("Id: $id - Name: $name - Birthdate: $yearOfBirth ") } }
//custom getters and setters class Person(val id: Int, var name: String, val yearOfBirth: Int){ val age: Int get() = Calendar.getInstance().get(Calendar.YEAR) - yearOfBirth var socialSecurityNumber: String = "" set(value) { if(!value.startsWith("SN")){ throw IllegalArgumentException("Social security number should start with SN") } field = value } //function in a class fun personAsString(){ println("Id: $id - Name: $name - Birthdate: $yearOfBirth ") } } //field (reserved word) is the backing field of the property
• First class citizens in Kotlin → objects first • Provide expected functionality such as properties and functions • There are no fields, only properties • We have access to properties if required in custom getters / setters • Data classes provide functionality to reduce boiler-plate code • Each enum is an instance and allows behaviour
• Same as in Java with a few twists • Allows to have default implementations (same as Java 8) • Is different from an abstract class because: • it cannot hold a state • a class can implement multiple interfaces when it cannot inherit from multiple abstract classes
and map data class Person(val age: Int, val name: String) val people = listOf(Person( 29, "Alice"), Person( 31, "Bob")) println(people.filter { it.age > 30 }) // output [Person(name=Bob, age=31)]
flow when (x) { 0, 1 -> print("x == 0 or 1") else -> print("neither 0 nor 1") } val validNumbers = 1..19 when (x) { in 1..10 -> print("x is in the range") in validNumbers -> print("x is valid") !in 10..20 -> print("x is outside the range") else -> print("none of the above") }
fun String.capStuff(): String { return this.toUpperCase() } fun String.prefixStuff(prefix: String): String { return "$prefix $this" } fun main(args: Array<String>) { println(“Batman".capStuff()) // Prints out “BATMAN” println("Robin".prefixStuff("Hey").capStuff()) // Prints out “HEY ROBIN” }
• Navigate between Java and Kotlin source files. • Debug mixed language projects and step between code written in different languages. • Refactor your Java methods and have their use in Kotlin code correctly updated, and vice versa.
fun main(args: Array<String>) { val customer = CustomerJava() customer.email = "[email protected]" customer.prettyPrint() /* * Runnable is a Java interface. Through lambdas we are directly passing the println method. * */ val runnable = Runnable {println("Invoking runnable")} }
fun main(args: Array<String>) { val customer = CustomerJava() customer.email = "[email protected]" customer.prettyPrint() /* * Runnable is a Java interface. Through lambdas we are directly passing the println method. * */ val runnable = Runnable {println("Invoking runnable")} }
fun main(args: Array<String>) { val kr = KotlinRepo() val customerJava = kr.getById(10) customerJava.id } //inherit from Java class PersonKotlin: PersonJava(){ } class KotlinRepo: CustomerRepository{ override fun getById(id: Int): CustomerJava { TODO("not implemented") //To change body of created functions use File | Settings | File Templates. } override fun getAll(): MutableList<CustomerJava> { TODO("not implemented") //To change body of created functions use File | Settings | File Templates. } }
fun main(args: Array<String>) { val kr = KotlinRepo() val customerJava = kr.getById(10) customerJava.id } //inherit from Java class PersonKotlin: PersonJava(){ } class KotlinRepo: CustomerRepository{ override fun getById(id: Int): CustomerJava { TODO("not implemented") //To change body of created functions use File | Settings | File Templates. } override fun getAll(): MutableList<CustomerJava> { TODO("not implemented") //To change body of created functions use File | Settings | File Templates. } }
safety class KotlinRepo: CustomerRepository{ override fun getById(id: Int): CustomerJava? { TODO("not implemented") //To change body of created functions use File | Settings | File Templates. } override fun getAll(): MutableList<CustomerJava>? { TODO("not implemented") //To change body of created functions use File | Settings | File Templates. } }
safety class KotlinRepo: CustomerRepository{ override fun getById(id: Int): CustomerJava? { TODO("not implemented") //To change body of created functions use File | Settings | File Templates. } override fun getAll(): MutableList<CustomerJava>? { TODO("not implemented") //To change body of created functions use File | Settings | File Templates. } }
public static void main(String[] args) { CustomerKotlin customerKotlin = new CustomerKotlin(1, "Guy", "[email protected]"); customerKotlin.setEmail(“[email protected]”); String value = customerKotlin.someField; customerKotlin.changeStatus(Status.Current); //check the default parameter customerKotlin.changeStatus(); //Annotation set name for Java. customerKotlin.Preferential(); try { customerKotlin.loadStatistics("filename"); } catch (IOException e) { e.printStackTrace(); } //Invoke Top Level Function //Like Kotlin created a static class with a static method. //TopLevelFunctionsKt.prefix("some", "value"); UtilityClass.prefix("some", "value"); UtilityClass.getCopyrightYear(); //Talking to the extension function it requires an instance of the class "customerKotlin" CustomerKotlinKt.extensions(customerKotlin, "Test"); } data class CustomerKotlin (var id: Int, var name: String, var email: String){ @JvmField val someField = "Value" override fun toString():String{ return "{\"id\": \"$name\", \"name\": \"$name\"}" } @JvmOverloads fun changeStatus(status: Status = Status.Current){ } @JvmName("Preferential") fun makePrefered(){ } @Throws(IOException::class) fun loadStatistics(filename: String){ if(filename == ""){ throw IOException("Filename can not be empty") } } }