Let's Code: Switching From Java to Kotlin, Pt. 2

There aren't many differences between Java and Kotlin, making it a great language to switch to if you already know the former. There's a small learning curve, sure, but that's true for switching to any language. There will always be small things that trip you up repeatedly until you get used to them.

One thing to get used to is the difference in the way Kotlin declares properties.

In my original draft of this post, I tried to say something like, "There's only one way to declare a variable in Java." And then I started typing and... no, it's just as complex as it is in Kotlin, they're just done differently. I say all that to say: don't let the unfamiliarity catch you by surprise.

Declaring Properties

If you're coming from Java, you've probably been declaring variables like this:

String anotherString = "Hey!"

@Nullable String aDefinitelyNullableString;
@NonNull String aDefinitelyWontBeNullString = ""

final String aFinalString = "Ye shall not pass!"

We have the lawless variable first, the one where we're unsure of whether the value will be null or not later on. This is followed by some that clearly labeled, showing whether or not they can contain a null value and lastly one that has a value that definitely will not change. Pretty simple.

In Kotlin, some different assumptions are made, a lot for the sake of Null Safety.

var mutablev1: String = "CAN be changed"
var mutablev2 = "CAN be changed"

val immutablev1: String = "Can't be changed"
val immutablev2 = "Can't be changed"

There are two things to tackle here. First, it's all non-null by default. You have to go "out of your way" to make a value nullable. (I'll show you how in the next section.) Secondly, there are two new keywords we have to be aware of: var and val. var means that the value can be changed in the future and val means it can not be, as if you made a final variable in Java.

Kotlin Null Safety

?

If you want to go "out of your way" to make a value nullable, you simply add a ? to the end of the property type.

var nullableMutable: String? = null

After you mark something as nullable, you'll get plenty of warnings within your code that you should be checking if that value is null before being used.

!!

Similarly, if you have a nullable property that at some point later on you know is going to be not-null for whatever reason, you can tell you code that you are 100% confident in its non-nullness by adding !!. For example:

private var importantCustomer: Customer? = null

fun getCustomerOrder(): Order? {	
	return orderService.getOrderForCustomer(importantCustomer!!)
}

.let

Let's say you're not 100% sure, though. importantCustomer could be null, right? You can either wrap getCustomerOrder() in a null check, or you can wrap the return. Or...

private var importantCustomer: Customer? = null

fun getCustomerOrder(): Order? {
	return importantCustomer?.let {
		orderService.getOrderForCustomer(it)
	}
}

I use the let extension function pretty often. It's essentially the same thing as adding a null check. In Java, it would look like this:

@Nullable Order getCustomerOrder() {
	return importantCustomer != null ? orderService.getCustomerOrder(importantCustomer) : null;
}

And while I don't think Kotlin has a "pretty" ternary operator like Java does, it does allow you to do similar things based on null responses.

private var importantCustomer: Customer? = null

fun getCustomerOrder(): Order {
	return importantCustomer?.let {
		orderService.getOrderForCustomer(it)
	} ?: Order.BLANK_ORDER
}

lateinit

In Java, you can annotate a variable with @NonNull and you can be sure the compiler will let you know that it's supposed to be non-null and will remind you that you need to initialize it. But there's no way to say, "Hey, this can't be null but I don't feel like setting it right now. I'll get to it later, I promise."

In Kotlin, you can!

lateinit var customerId: String

fun functionOne() {
	if (customerId == null) {
		//	Doesn't matter
	}
}

fun functionTwo() {
	customerId = "4815162342"
	if (customerId 3 == null) {
		// Doesn't matter. 
		// Can't be null. 
		// You should get a lint warning about this.
	}
}

If I were to run this code, calling functionOne() first causes the app to crash. customerId hasn't been set yet. But by setting it first in functionTwo(), it works. And now you can call functionOne() because it knows what customerId is now.

lazy

You've seen that piece of code in Java before, the getter that checks to see if the variable is null first. If it is, it sets it, then just returns that variable.

int sloth;

private String getSloth() {
	if (sloth == null) {
		sloth = getRandomNumber() * 12;
	}
	return sloth; 
}

In Kotlin, the same concept exists, more or less, in the keyword lazy:

val sloth: Int by lazy {
	getRandomNumber() * 12
}

fun getTheSloth() {
	Timber.d("Got the sloth: $sloth")
	Timber.d("Just checking it again: $sloth")
}

I'm going to be honest: I realized while typing this up that I've been using lazy wrong for a whiiiiile. The example above has the way it probably should be used. What I always did was val sloth = lazy { } That's not wrong per se, however it returns a Lazy object; you would need to do sloth.value to get the value, but it also comes with sloth.isInitialized(). The method above actually gives you back the value so you can use it normally. Use whichever method works best for you.

Wrap Up

That's all I can cram in this week. This should cover the bases for switching from Java to Kotlin, yes? If you have any specific questions, let me know in the comments below, or you can reach me on Twitter @gatlingxyz.