Conventions • Types in 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.
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
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
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
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
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 ") } }
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 ") } }
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
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
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
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
{ 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") }
{ 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” }
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.
{ 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")} }
{ 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")} }
{ 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. } }
{ 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. } }
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. } }
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. } }
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") } } }
SubClass)?.subclassMethod1() if (b != null) { x.subclassMethod2() // x is smart cast to SubClass } } var x: String? = null if (flag) x = "Yahoo!" run { if (x != null) { println(x.length) // x is smart cast to String } }
Multiplatform projects • Array literals in annotations • Lateinit improvements • Bound callable reference improvements • Type inference improvements • Warning as errors • Smart cast improvements • Nested classes in Enums • kotlin.math is a new package in the Standard Library.