Menu Close

Kotlin – The complete guide

kotlin tutorial

 

kotlin for android
I was also an amateur in kotlin once XD

 

Kotlin language was introduced JetBrains in 2011, but took off recently when it was announced as an official language for Android Development at Google I/O 2017.

It is really easy to learn and more so if you are already familiar with an Object Oriented Programming language such as Java, C++ etc.

Kotlin has many great features such as Data Classes, Null checking, Lambdas, Higher Order functions and much more.

I have compared Java and Kotlin for android developers, and listed out some reasons as to why you might consider switching to Kotlin for Android Development.

So, let’s get started.

 

Variables and Constants declaration

Java

String name = "Ayusch";
final String name = "Ayusch"; //const

Kotlin

var name = "Ayusch"
val name = "Ayusch" //const

 

Checking Nullability

Java

if (text != null) {
  int length = text.length();
}

Kotlin

text?.let {
    val length = text.length
}
// or simply
val length = text?.length

 

Concatenation of strings

Java

String firstName = "Ayusch";
String lastName = "Jain";
String message = "My name is: " + firstName + " " + lastName;

Kotlin

val firstName = "Ayusch"
val lastName = "Jain"
val message = "My name is: $firstName $lastName"

 

String formatting

Java

String text = "First Line\n" +
              "Second Line\n" +
              "Third Line";

Kotlin

val text = """
        |First Line
        |Second Line
        |Third Line
        """.trimMargin()

 

Ternary Operations

Java

String text = x > 5 ? "x > 5" : "x <= 5";

String message = null;
log(message != null ? message : "");

Kotlin

val text = if (x > 5)
              "x > 5"
           else "x <= 5"

val message: String? = null
log(message ?: "")

 

Logical Operators

Java

final int andOperator  = a & b;
final int orOperator   = a | b;
final int xorOperator  = a ^ b;
final int rightShiftOperator = a >> 2;
final int leftShiftOperator  = a << 2;
final int unsignedRightShiftOperator = a >>> 2;

Kotlin

val andOperator  = a and b
val orOperator   = a or b
val xorOperator  = a xor b
val rightShiftOperator = a shr 2
val leftShiftOperator  = a shl 2
val unsignedRightShiftOperator = a ushr 2

 

Type Checking and Type Casting

Java

if (user instanceof Person) {
}
Person user = (Person) object;

Kotlin

if (user is Person) {
}
var user = object as Person

// if object is null
var person = object as? Person// var person = object as Person?

 

Switch Case

Java

int score = // some score;
String grade;
switch (score) {
	case 10:
	case 9:
		grade = "Excellent";
		break;
	case 8:
	case 7:
	case 6:
		grade = "Good";
		break;
	case 5:
	case 4:
		grade = "OK";
		break;
	case 3:
	case 2:
	case 1:
		grade = "Fail";
		break;
	default:
	    grade = "Fail";				
}

Kotlin

var score = // some score
var grade = when (score) {
	9, 10 -> "Excellent"
	in 6..8 -> "Good"
	4, 5 -> "OK"
	in 1..3 -> "Fail"
	else -> "Fail"
}

 

For Loop

Java

for (int i = 1; i <= 10 ; i++) { }

for (int i = 1; i < 10 ; i++) { }

for (int i = 10; i >= 0 ; i--) { }

for (int i = 1; i <= 10 ; i+=2) { }

for (int i = 10; i >= 0 ; i-=2) { }

for (String item : collection) { }

for (Map.Entry<String, String> entry: map.entrySet()) { }

Kotlin

for (i in 1..10) { }

for (i in 1 until 10) { }

for (i in 10 downTo 0) { }

for (i in 1..10 step 2) { }

for (i in 10 downTo 1 step 2) { }

for (item in collection) { }

for ((key, value) in map) { }

 

Collections

Java

final List<Integer> listOfNumber = Arrays.asList(1, 2, 3, 4);

final Map<Integer, String> keyValue = new HashMap<Integer, String>();
map.put(1, "Ayusch");
map.put(2, "Abhishek");
map.put(3, "Anuj");

// Java 9
final List<Integer> listOfNumber = List.of(1, 2, 3, 4);

final Map<Integer, String> keyValue = Map.of(1, "Ayusch",
                                             2, "Abhishek",
                                             3, "Anuj");

Kotlin

val listOfNumber = listOf(1, 2, 3, 4)
val keyValue = mapOf(1 to "Ayusch",
                     2 to "Abhishek",
                     3 to "Anuj")

 

for each

Java

// Java 7 and below
for (Car car : cars) {
  System.out.println(car.speed);
}

// Java 8+
cars.forEach(car -> System.out.println(car.speed));

// Java 7 and below
for (Car car : cars) {
  if (car.speed > 100) {
    System.out.println(car.speed);
  }
}

// Java 8+
cars.stream().filter(car -> car.speed > 100).forEach(car -> System.out.println(car.speed));

Kotlin

cars.forEach {
    println(it.speed)
}

cars.filter { it.speed > 100 }
      .forEach { println(it.speed)}

// kotlin 1.1+
cars.stream().filter { it.speed > 100 }.forEach { println(it.speed)}
cars.parallelStream().filter { it.speed > 100 }.forEach { println(it.speed)}

 

Splitting arrays

java

String[] splits = "param=car".split("=");
String param = splits[0];
String value = splits[1];

kotlin

val (param, value) = "param=car".split("=")

 

Defining methods

Java

void doSomething() {
   // logic here
}

Kotlin

fun doSomething() {
   // logic here
}

Variable number of arguments

Java

void doSomething(int... numbers) {
   // logic here
}

Kotlin

fun doSomething(vararg numbers: Int) {
   // logic here
}

 

Defining methods with return

Java

int getScore() {
   // logic here
   return score;
}

Kotlin

fun getScore(): Int {
   // logic here
   return score
}

// as a single-expression function

fun getScore(): Int = score

// even simpler (type will be determined automatically)

fun getScore() = score // return-type is Int

 

Returning result of an operation

Java

int getScore(int value) {
    // logic here
    return 2 * value;
}

Kotlin

fun getScore(value: Int): Int {
   // logic here
   return 2 * value
}

// as a single-expression function
fun getScore(value: Int): Int = 2 * value

// even simpler (type will be determined automatically)

fun getScore(value: Int) = 2 * value // return-type is int

 

Constructors

Java

public class Utils {

    private Utils() {
      // This utility class is not publicly instantiable
    }

    public static int getScore(int value) {
        return 2 * value;
    }

}

Kotlin

class Utils private constructor() {

    companion object {

        fun getScore(value: Int): Int {
            return 2 * value
        }

    }
}

// another way

object Utils {

    fun getScore(value: Int): Int {
        return 2 * value
    }

}

 

Getters and Setters (Data Class)

Java

public class Developer {

    private String name;
    private int age;

    public Developer(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Developer developer = (Developer) o;

        if (age != developer.age) return false;
        return name != null ? name.equals(developer.name) : developer.name == null;

    }

    @Override
    public int hashCode() {
        int result = name != null ? name.hashCode() : 0;
        result = 31 * result + age;
        return result;
    }

    @Override
    public String toString() {
        return "Developer{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

Kotlin

data class Developer(var name: String, var age: Int)

 

Cloning or copying

Java

public class Developer implements Cloneable {

    private String name;
    private int age;

    public Developer(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return (Developer)super.clone();
    }
}

// cloning or copying
Developer dev = new Developer("Ayusch", 30);
try {
    Developer dev2 = (Developer) dev.clone();
} catch (CloneNotSupportedException e) {
    // handle exception
}

Kotlin

data class Developer(var name: String, var age: Int)

// cloning or copying
val dev = Developer("Ayusch", 30)
val dev2 = dev.copy()
// in case you only want to copy selected properties
val dev2 = dev.copy(age = 25)

 

Class methods

Java

public class Utils {

    private Utils() {
      // This utility class is not publicly instantiable
    }

    public static int triple(int value) {
        return 3 * value;
    }

}

int result = Utils.triple(3);

Kotlin

fun Int.triple(): Int {
  return this * 3
}

var result = 3.triple()

 

Defining uninitialized objects

Java

Person person;

Kotlin

internal lateinit var person: Person

 

enum

Java

public enum Direction {
        NORTH(1),
        SOUTH(2),
        WEST(3),
        EAST(4);

        int direction;

        Direction(int direction) {
            this.direction = direction;
        }

        public int getDirection() {
            return direction;
        }
    }

Kotlin

enum class Direction constructor(direction: Int) {
    NORTH(1),
    SOUTH(2),
    WEST(3),
    EAST(4);

    var direction: Int = 0
        private set

    init {
        this.direction = direction
    }
}

 

Sorting List

Java

List<Profile> profiles = loadProfiles(context);
Collections.sort(profiles, new Comparator<Profile>() {
    @Override
    public int compare(Profile profile1, Profile profile2) {
        if (profile1.getAge() > profile2.getAge()) return 1;
        if (profile1.getAge() < profile2.getAge()) return -1;
        return 0;
    }
});

Kotlin

val profile = loadProfiles(context)
profile.sortedWith(Comparator({ profile1, profile2 ->
    if (profile1.age > profile2.age) return@Comparator 1
    if (profile1.age < profile2.age) return@Comparator -1
    return@Comparator 0
}))

 

Anonymous Class

Java

 AsyncTask<Void, Void, Profile> task = new AsyncTask<Void, Void, Profile>() {
    @Override
    protected Profile doInBackground(Void... voids) {
        // fetch profile from API or DB
        return null;
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        // do something
    }
};

Kotlin

val task = object : AsyncTask<Void, Void, Profile>() {
    override fun doInBackground(vararg voids: Void): Profile? {
        // fetch profile from API or DB
        return null
    }

    override fun onPreExecute() {
        super.onPreExecute()
        // do something
    }
}

 

Like what you read ? Don’t forget to share this post on FacebookWhatsapp and LinkedIn.

You can follow me on LinkedInQuoraTwitter and Instagram where I answer questions related to Mobile Development, especially Android and Flutter.