Subscribe / Unsubscribe Enewsletters | Login | Register

Pencil Banner

What is Kotlin? The Java alternative explained

Martin Heller | Sept. 18, 2017
Kotlin offers big advantages over Java for JVM and Android development, and plays nicely with Java in the same projects. Why not give it a try?

For example, a regular variable of type String cannot hold null:

var a : String = "abc" 
a = null // compilation error

If you need to allow nulls, for example to hold SQL query results, you can declare a nullable type by appending a question mark to the type, e.g. String?.

var b: String? = "abc"
b = null // ok

The protections go a little further. You can use a non-nullable type with impunity, but you have to test a nullable type for null values before using it.

To avoid the verbose grammar normally needed for null testing, Kotlin introduces a safe call, written ?.. For example, b?.length returns b.length if b is not null, and null otherwise. The type of this expression is Int?.

In other words, b?.length is a shortcut for if (b != null) b.length else null. This syntax chains nicely, eliminating quite a lot of prolix logic, especially when an object was populated from a series of database queries, any of which might have failed. For instance, bob?.department?.head?.name would return the name of Bob’s department head if Bob, the department, and the department head are all non-null.

To perform a certain operation only for non-null values, you can use the safe call operator ?. together with let:

val listWithNulls: List<String?> = listOf("A", null) 
for (item in listWithNulls) {
      item?.let { println(it) } // prints A and ignores null }

Often you want to return a valid but special value from a nullable expression, usually so that you can save it into a non-nullable type. There’s a special syntax for this called the Elvis operator (I kid you not), written ?:.

val l = b?.length ?: -1

is the equivalent of 

val l: Int = if (b != null) b.length else -1

In the same vein, Kotlin lacks Java’s checked exceptions, which are throwable conditions that must be caught. For example, the JDK signature

Appendable append(CharSequence csq) throws IOException;

requires you to catch IOException every time you call an append method:

try {
  log.append(message)
}
catch (IOException e) {
  // Do something with the exception
}

The designers of Java thought this was a good idea, and it was a net win for toy programs, as long as the programmers implemented something sensible in the catch clause. All too often in large Java programs, however, you see code in which the mandatory catch clause contains nothing but a comment: //todo: handle this. This doesn’t help anyone, and checked exceptions turned out to be a net loss for large programs.

 

Kotlin interoperability with Java

At this point you may be wondering how Kotlin handles the results of Java interoperability calls, given the differences in null handling and checked exceptions. Kotlin silently and reliably infers what is called a “platform type” that behaves exactly like a Java type, meaning that is nullable but can generate null-pointer exceptions. Kotlin may also inject an assertion into the code at compile time to avoid triggering an actual null pointer exception. There’s no explicit language notation for a platform type, but in the event Kotlin has to report a platform type, such as in an error message, it appends ! to the type.

 

Previous Page  1  2  3  4  Next Page 

Sign up for Computerworld eNewsletters.