I started converting my first project to Kotlin just a couple of months ago and literally after only a couple of hours I immediately saw how cool Kotlin was. To put this in perspective, I started writing Android apps with the release of Froyo back in the Eclipse days so of course I was giddy about a complete language change. Along the way I’ve picked up some different languages to write Android apps like PhoneGap, Xamarin, and Rhomobile (don’t laugh) but Kotlin is the first to be officially supported by Google. Now a lot of people like to say Kotlin is a lot like Swift but I want to stop you right there and tell you to reorder that. Kotlin was released back in 2012 a full 2 years before Swift appeared. So yes, it is true a lot of Swift syntax looks like Kotlin, and that is a good thing. To make the transition even easier, Kotlin is also interoperable with Java so we can still use 3rd party libraries that are written in Java. I plan to update this post periodically as I use Kotlin more and more in my project and use it as sort of a guide to show the differences and downfalls of the language.

Creating an Activity

Java

public class MainActivity extends AppCompatActivity {

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}

Kotlin

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }
}

NOTES: Notice Kotlin does not have a void return type. Functions are declared using the fun keyword and there are no semicolons at the end of lines. The Bundle? means that there is a possibility that the Bundle code be null.

Creating a TextView

Java

TextView textView = (TextView) findViewById(R.id.tv_greeting);
textView.setText("Hello");

Kotlin

import kotlinx.android.synthetic.main.activity_main.*

tv_greeting.text = "hello"

NOTES: The layout has been binded using synthetic in the import statement. This allows us to reference any view in the xml by name. We no longer need findViewById.

Creating a Button

Java

Button button = findViewById(R.id.btn_submit);
button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                    // button clicked
            }
});

Kotlin

import kotlinx.android.synthetic.main.activity_main.*

btn_submit.setOnClickListener {
       // button clicked
}

NOTES: The layout has been binded using synthetic in the import statement. This allows us to reference any view in the xml by name. We no longer need findViewById.

Variables

Java

// immutable variable (variables that cannot change or constants)
final String URL = "www.google.com";

// mutable variable (variable can change)
Int age = "19";

// concatenation
String companyAge = URL + " is " + age + " years old.";

Kotlin

// immutable variable (variables that cannot change or constants)
val URL = "www.google.com"

// mutable variable (variable can change)
var age = 19

// String Template
String companyAge = "$URL is $age years old."

NOTES: Kotlin variables do not require a type and it is recommended to use val as much as possible.

Creating an EditText

Java

EditText editText = (EditText) findViewById(R.id.et_username);

// get text from EditText
String username =  editText.getText().toString();

// clear text from EditText
editText.getText().clear();

Kotlin

import kotlinx.android.synthetic.main.activity_main.*

// get text from EditText
val username =  et_username.text.toString()

// clear text from EditText
et_username.text.clear()

NOTES: The layout has been binded using synthetic in the import statement. This allows us to reference any view in the xml by name. We no longer need findViewById.

Null Safety

Now this is something totally new. Kotlin also helps us avoid NullPointerExceptions that are a common problem with Java.

Kotlin

// If name is not null, store name as username. If name is null, store no name as username
val name = "Malcolm"
val username = name ?: "no name" // Elvis Operator

// Declare a String that can be null
var teamName : String? = "Hawks" 

// Safe Call Operator
// if name is not null, print the length. If name is null, then null is printed
println(name?.length)

Raw Strings

One of my favorite things about Kotlin is no longer having to escape special characters. You can put nearly anything into a raw string and still call common methods like toUppercase() on it.

Kotlin

val rawQuestion = """Can I please "borrow" $1,000,000 dollars?"""

Methods

Java

private void getJob() {
        // apply for jobs
}

private void goToWork(String workAddress) {
        // drive to work
}

private int getPaid(int hours, int rate) {
        return hours * rate;
}

Kotlin

fun getJob() {
        // apply for jobs
}

fun goToWork(workAddress:String) {
        // drive to work
}

fun  getPaid(hours:Int, rate:Int): Int {
        return hours * rate
}

NOTES: Return types are declared towards the end of the method declaration in Kotlin and there is no keyword needed for void return types.

Switch Statements

Java

int x = 2;
switch (x) {
        case 1: //do something
                     break;
        case 2: //do something
                     break;
        default: //do something
                     break;
}

Kotlin

val x = 2
when (x) {
        1 -> //do something
        2 -> //do something
        else -> //do something
}

Optional Parameters

Surprise, we don’t have this in Java.

Kotlin

fun greatestOfAllTime(player:String = "Jordan") {
      println(player)
}

// prints "Jordan"
greatestOfAllTime()
// prints "LeBron"
greatestOfAllTime("LeBron")

Arrays

Java

String[] players = {"LeBron", "Jordan", "Kobe", "Curry"};

// prints "Jordan"
System.out.println(players[1]);

// loop through array elements
for (String player : players) {
        System.out.println(player);
}

Kotlin

val players = ("LeBron", "Jordan", "Kobe", "Curry")

// prints "Jordan"
println(myArray[1])

// loop through array elements
for (player in players) {
        println(player)
}

Classes

Java

public class Player {
    private String name;
    private String team;
    private int weight;

    public Player(String name, String team, int weight) {
        this.name = name;
        this.team = team;
        this.weight = weight;
    }

    public String getName() {
        return name;
    }

    public String getTeam() {
        return team;
    }

    public int getWeight() {
        return weight;
    }

    public void setWeight(int weight) {
        this.weight = weight;
    }
    
    public void shoot() {
        System.out.println(name + " for two!");
    }
}

// Instantiate the class in Activity
Player ai = new Player("Allen Iverson", "76ers", 185);
ai.shoot();

Kotlin

open class Player (val name: String, val team: String, var weight: Int) {
    open fun shoot() {
        println("$name for two!")
    }
}

// Instantiate the class in Activity
val ai = Player("Allen Iverson", "76ers", 185)
println(ai.name)
ai.shoot()

NOTES: Notice Kotlin classes do not need getters and setters but in order to access setters, you need to use var in the constructor arguments. open in the Kotlin class signifies that it can inherited, by default no Kotlin class be inherited. The open in the shoot() method signifies that it can be overridden. Significantly less code!

Inheritance

Java

public class MaxPlayer extends Player {
    private String name;
    private String team;
    private int weight;
    private int salary;

    public MaxPlayer(String name, String team, int weight, int salary) {
        super(name, team, weight);
        this.name = name;
        this.team = team;
        this.weight = weight;
        this.salary = salary;
    }

    public int getSalary() {
        return salary;
    }

    public void setSalary(int salary) {
        this.salary = salary;
    }

    public void shoot() {
        System.out.println(name + " for three!");
        // Put in super to also print $name for two!
        //super.shoot();
    }

    public void hookShot() {
        System.out.println(name + "  with the hook!");
    }
}

// Instantiate MaxPlayer class in an Activity
MaxPlayer bRussell = new MaxPlayer("Bill Russell", "Celtics", 235, 5000000);
bRussell.hookShot();
bRussell.shoot();

Kotlin

class MaxPlayer(val name: String, val team: String, var weight: Int, var salary: Int) : Player(name, team, weight) {
	override fun shoot() {
            println("$name for three!")
            // Put in super to also print $name for two!
            //super.shoot()
        }

        fun hookShot() {
            println("$name with the hook!")
        }
}

// Instantiate the class in Activity
val bRussell = MaxPlayer("Bill Russell", "Celtics", 235, 50000000)
bRussell.shoot()
bRussell.hookShot()

Lambdas

This is something new. Lambdas are basically functions that are passed as parameters. Essentially Lambdas can be used all callbacks.

Kotlin

// regular method
fun draftPlayer(playerName: String, pickNumber: Int) {
    println("$playerName has been drafted with the $pickNumber pick!")
}
// call method
draftPlayer("Chris Paul", 2)

// same method as a Lambda
val draftPlayer = { playerName: String, pickNumber: Int -> "$playerName has been drafted with the $pickNumber pick!"}
// call Lambda
println(draftPlayer("Chris Paul", 2))

// Same Lambda written in shorthand
val draftPlayer : (String, Int) -> String = {playerName, pickNumber -> "$playerName has been drafted with the $pickNumber pick!"}
// call Lambda
println(draftPlayer("Jordan", 1)) 

// Lambda used as callback
fun downloadPosts(url: String, done: ()-> Unit) {
    // sent download request
    // data was returned
    // there were no errros
    done()
}

// call Lambda as callback
downloadPosts("http://www.mclfysoftware.com/posts", {
    print("download posts SUCCESS")
    // update UI
})

// use lambda with parameter saving response in object
fun downloadSinglePost(url: String, done: (Post) -> Unit) {
    // sent download request
    // post data was returned
    // there were no errros
    // mock save returned post data into Post object
    val post = Post("My Kotlin Tutorial", "4/15/2018", "http://www.mcflysoftware.com/postImage.jpg")
    done(post)
}

// call Lambda
downloadSinglePost("http://www.mclfysoftware.com/post/1532") { post -> 
    println("download post SUCCESS")
    // post.image
    // post.title
    // post.date
}

// call Lambda (alternate if there is only 1 object parameter)
downloadSinglePost("http://www.mclfysoftware.com/post/1532") {
    println("download post SUCCESS")
    // it.image
    // it.title
    // it.date
}

// use lambda with parameter saving response in nullable object
fun downloadSinglePost(url: String, done: (Post?, Boolean) -> Unit) {
    // sent download request
    // post data was returned
    // mock network success/failure
    val webRequestSuccess = true
    if (webRequestSuccess) {
        val post = Post("My Kotlin Tutorial", "4/15/2018", "http://www.mcflysoftware.com/postImage.jpg")
        done(post, true)
    } else {
        done(null, false)
    }
}

// call lambda with parameter and nullable
downloadSinglePost("http://www.mclfysoftware.com/post/1532") { post, success ->
    if (success) {
        println("download post SUCCESS")
        // post?.image
        // post?.title
        // post?.date
    } else {
        // handle failure
        println("download post FAILURE")
    }
}

NOTES: All Lambdas must be inside {...}. Unit is the same as the Void return type in Java. done is user defined can be named anything you want e.g. completion, success. success is user defined can be named anything you want e.g. result, status.