Now Kotlin is officially announced for Android, I thought of getting started and below is my learnings, as an iOS developer, I am writing a comparison also whereever required.
- Features
- Variables
- Pairs
- Triple
- Null
- Conditions
- Type Check and Casting
- Arrays
- ArrayList
- For & While
- Functions
- Class
- SealedClass
- Abstract
- Interface
- Extension Fuctions
- Set
- Map
- Start An Activity
-
Leaner code, expressive
-
Kotlin is a statically typed programming language from JetBrains. (Type of a variable is known at compile time.)
-
Safe: Exceptions are caught at compile time. Type interpretation is also present for some types. Kotlin is null safe. (In Kotlin, the type system distinguishes between references that can hold null and those that cannot.)
-
Interoperable : Interoperable with Java and Android libs
-
REPL : Similar to Swift REPL, Kotlin also have an REPL where in which we can try out expressions.
-
Supports functional programming ( eg:Lambda functions)
var
for variable, which is mutable and can be re-assigned. Similar in Swift also.
var text = "hello"
// Here Kotlin finds out text is of String type.
We can explictly do this by giving the type name
var text:String = "hello"
var number = 5.45
// Interpreted as Double
var number:float = 5.45
// Gives error
as by default decimals are interpretted as double. To fix it you need to append "f"
var number:float = 5.45f
val
for constants, immutable. We use let
in Swift.
const val
constants which are assigned at compile time. Usually used when you need Constants
object Constants {
const val BASE_URL = "http://myApi/"
}
Pairs
is a data type in kotlin where we can have a generic pair of values. It is similar to Tuples
in Swift
val weapn = "Gun" to "Fire"
print(weapn.first)
print(weapn.second)
val (weaponName, use) = weapn
print(weaponName)
print(use)
You can return more than one value from a function
fun giveMeAWeapon():Pair<String, String>{
val weapn = "Gun" to "Fire"
return weapn
}
Pairs can be converted to string and toList.
Triples
hold or return three values.
fun getStudentFullDetails():Triple<String, String, Int>{
return Triple(firstName, lastName, age)
}
Missing value, null safety. We cannot assign null to any basic data type
var str:String = null
= error
If you still want to create nullable you need to add ?
to the type.
var str:String? = null
This is similar to optionals
in swift
If a variable is nullable
you wont be able to call methods on it ie str.length
will return error
, we need to use ?
here again
str?.length
will work fine here, if there is value in str
it will return the length else it will return null
If we are sure that the variable definitely contain a value then we can use !!
ie str!!.length
this is similar to forced unwrapping
in swift
, here if the value is null, we will get a null pointer exception.
Entry point of the application.
Nothing new, same as normal if...else
val threshold = 200
if (threshold < 100){
println("its good")
}else if (threshold > 100){
println("need to worry")
}else if (threshold == 200){
println("reached maximum")
}
Similar to if but we dont specify any condition.
val state: Int = 1
when (state){
1 -> println("State is Running.")
2 -> {
// if there is multiple lines, use curly braces
println("State is Stopped.")
}
// Any unsatisfied state
else -> println("State is Stopped.")
}
val random = Random().nextInt(30)
println(random)
when (random){
in 1..10 -> {
println(" value between 1 and 10")
}
in 11..20 -> {
println(" value between 11 and 20")
}
else ->{
println(" value above 20")
}
}
// Iterate revers
for (i in 4 downTo 1)
print(i)
// Iterate with step
for (i in 1..4 step 2)
print(i)
Type Check using is and !is Operators
if (a is String) {
print(a.length)
}
if (a !is String) {
print("a is not a String")
}
Smart Casts
if (a is String) {
print(a.length) // val gets automatically cast to String
}
if (a !is String) return
print(a.length) // val gets automatically cast to String
// Usage with when
when (a) {
is Int -> print(a + 1)
is IntArray -> print(a.sum())
}
Type Casting : Unsafe Cast
val a: String = b as String
Type Casting : Safe Cast
val a: String? = b as? String
val array = arrayOf(1,2,3,4)
val mixedarray = arrayOf("String",1,2,false) // Any
val array2 = arrayOf(1,2,3,4)
val numbers = intArrayOf(1,2,3,4) // Only integers are possible
//Combine arrays, you can combine 2 arrays of same type
val combinedArray = array2 + array
// To check if array is empty
if (array.isEmpty()){
println("Array is empty")
}
// To check if array contains a particular element
if (array.contains(2)){
println("Array contains is 1")
}
println(mixedarray[0])
Arraly lists are mutable, you can add and remove elements from it.
val arrayList = arrayListOf("A","B","C")
val arrayList2 = arrayListOf("D","E","F")
// Combine array lists
println(arrayList + arrayList2)
// arraylist is mutable using the add method
val added = arrayList.add("T")
if (added){
println("Added")
}else{
println("Add failed")
}
// Add at a particular index. If there is no index, outof bound exception occurs
arrayList.add(2, "T")
// Remove element
val removed = arrayList.remove("A") //Boolean response
if (removed){
println("removed")
}else{
println("remove failed")
}
// Get a sublist from an array list, provide start index and end index (end index value wont be taken)
val sublist = arrayList.subList(1,2)
With for loop you can loop through collections, do operations on a list of values etc.
var total = 0
// Loop numbers 1 to 5, find their sum
for (i in 1..5){
println(i)
total = total + i
}
println(total)
//loop through collections
val collectionlist = listOf("A","B","C")
for (item in collectionlist){
println(item)
}
// Similar to SWift 3.0 enumerated() method
for ((index, item) in collectionlist.withIndex()){
println("Item at $index is $item")
}
for (i in myArray.indices){
println(myArray[i])
}
While A while loop statement in Kotlin programming language repeatedly executes a target statement as long as a given condition is true.
var index = 10
while (index < 20) {
println( "Value of index is $index")
index = index + 1
}
Break
:- To Break out of the entire loop
Continue
:- Skip a particular iteration
Naming loops Helpful in the case of nested loops, you can specify which loop to break and which loop to continue etc
outer@ for (i in 1..100) {
for (j in 1..100) {
if (...) break@outer
}
}
Below is the simple syntax for function in Kotlin
//fun <functionName>(<parameter>:<dataType>):<return datatype>{
// return <return value>
//}
// Simple function
fun hellokotlin(){
println("Hello kotlin")
}
// Function with parameters
fun sayHelloTo(name: String){
println("Hello" + name)
}
// Function accepts parameters and returns String
fun contructStringFrom(firstName:String, lastName:String):String{
return firstName + lastName
}
Basic syntax of a class is as follows.
class <ClassName>(Parameters for construction) {
}
By default a class is closed
, to inherit from a class, it need to be defined as open
open class <ClassName>(Parameters for construction): ParentClass {
}
For overriding properties of the parent class, the properties also need to be defined as open
in the Parent class
open class Vehicle(open val color:String,open var numberOfWheels:Int){
}
class Car(override val color: String, override var numberOfWheels: Int):Vehicle(color, numberOfWheels){
}
class Bike(override val color: String, override var numberOfWheels: Int):Vehicle(color, numberOfWheels){
}
Sealed
class is a class that can be subclassed only with in the same file. Compiler will be able to do extra checks on all the subclasses and will be able to know all the information about classes and subclasses at compile time
Abstract
classes are used when we want to restrict the users from creating an instance of a class, in the above example we wont end up a scenario of creating a Vehicle object, its going to be only Car or bike or may be buses later.
Abstract
classes are implictly open
Abstract methods are used when there is different implementation of the parent class method in the child class, so in the parent class only the declaration will be made and the child classes should implement the method.
abstract class Vehicle(open val color:String,open var numberOfWheels:Int){
abstract fun startEngine()
}
class Car(override val color: String, override var numberOfWheels: Int):Vehicle(color, numberOfWheels){
override fun startEngine() {
}
}
class Bike(override val color: String, override var numberOfWheels: Int):Vehicle(color, numberOfWheels){
override fun startEngine() {
}
}
Interface defines a contract which the adhering classes should implement, its like protocols
in Swift
. Interfaces can be extended also like protocol extensions
, they can contain abstract methods as well as method implementations. Properties can be declared in Interface but they need to abstact or can provide implementation for accessors. Interfaces cannot store state
interface Movable{
fun startEngine()
}
class Car( val color: String, var numberOfWheels: Int):Movable{
override fun startEngine() {
}
}
class Bike( val color: String, var numberOfWheels: Int):Movable{
override fun startEngine() {
}
}
Use enum
keyword.
enum class State{
STARTED, FAILED,SUCCESS
}
Usage
if(State.STARTED){
}
If you have a common functionality which need to handle multiple data types, we use generics.
class Collection<E>{
fun addElement(){
}
fun removeElement(){
}
}
Extensions are used to add a new behavior to a class eventhough we donot have access to the class's source code, it is similar to extensions in Swift. Extensions can be properties also.
Set doesnt accept duplicate values....set add unique values. val myCustomSet = HashSet<String>()
myCustomSet.add("Hello")
myCustomSet.add("Hello")
println(myCustomSet.size)
Maps are similar to dictionaries in Swift. You can have key value pairs
val mymap = emptyMap<String,String>() // empty readonly map
val anothermymap = mapOf<String, String>() // another empty readonly map
val contentMap = mapOf("Don" to "First Name","Bosco" to "LastName")// Read only
val mutableMap = mutableMapOf("First Name" to "Don" ,"LastName" to "Bosco")
mutableMap.put("name","Batista")
mutableMap.filter { it.value == "Don" }
//Looping through a map
for ((key, value) in map) { println("$key -> $value")
}
Execute an expression if not null
val value = ...
value?.let {
... // execute this block if not null
}
fun nullableTest(){
var str:String? = null
//str = "David"
val hello = str?.let { sayHello(it) }?: "Undefined"
Log.i("Kotlin",hello)
}
fun sayHello(name: String): String{
return "Hello $name"
}
fun loadNewActivity(view: View){
val intent = Intent(this, NewActivity::class.java)
//
intent.putExtra(...)
}
......more to come