What is Kotlin? The Java alternative explained

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?

Kotlin is a general purpose, open source, statically typed “pragmatic” programming language for the JVM and Android that combines object-oriented and functional programming features. It is focused on interoperability, safety, clarity, and tooling support. Versions of Kotlin for JavaScript (ECMAScript 5.1) and native code (using LLVM) are in the works.

Kotlin originated at JetBrains, the company behind IntelliJ IDEA, in 2010, and has been open source since 2012. The Kotlin team currently has more than 20 full-time members from JetBrains, and the Kotlin project on GitHub has about 100 contributors. JetBrains uses Kotlin in many of its products including its flagship IntelliJ IDEA.

convert java to kotlin JetBrains

At first glance, Kotlin looks like a streamlined version of Java. Consider the screenshot above, where I have converted a Java code sample (provided by the Kotlin folks) to Kotlin automatically. Notice that the mindless repetition inherent in instantiating Java variables has gone away. The Java idiom

StringBuilder sb = new StringBuilder();

in Kotlin becomes

val sb = StringBuilder()

You can see that functions are defined with the fun keyword, and that semicolons are now optional when newlines are present. The val keyword declares a read-only property or local variable. Similarly, the var keyword declares a mutable property or local variable.

Nevertheless, Kotlin is strongly typed. The val and var keywords can be used only when the type can be inferred. Otherwise you need to declare the type. Type inference seems to be improving with each release of Kotlin.

Have a look at the function declaration near the top of both panes. The return type in Java precedes the prototype, but in Kotlin it succeeds the prototype, demarcated with a colon as in Pascal.

It is not obvious from this example, but Kotlin has relaxed Java’s requirement that functions be class members. In Kotlin, functions may be declared at top level in a file, locally inside other functions, as a member function inside a class or object, and as an extension function. Extension functions provide the C#-like ability to extend a class with new functionality without having to inherit from the class or use any type of design pattern such as Decorator.

For Groovy fans, Kotlin implements builders; in fact, Kotlin builders can be type checked. Kotlin supports delegated properties, which can be used to implement lazy properties, observable properties, vetoable properties, and mapped properties.

Many asynchronous mechanisms available in other languages can be implemented as libraries using Kotlin coroutines, which are experimental in Kotlin 1.1. This includes async/await from C# and ECMAScript, channels and select from Go, and generators/yield from C# and Python.

Functional programming in Kotlin

Allowing top-level functions is just the beginning of the functional programming story for Kotlin. The language also supports higher-order functions, anonymous functions, lambdas, inline functions, closures, tail regression, and generics. In other words, Kotlin has all of the features and advantages of a functional language. For example, consider the following functional Kotlin idioms.

Filtering a list

val positives = list.filter { x -> x > 0 }

For an even shorter expression, use it when there is only a single parameter in the lambda function:

val positives = list.filter { it > 0 }

Traversing a map/list of pairs

for ((k, v) in map) { println(“$k -> $v”) }

k and v can be called anything.

Using ranges

for (i in 1..100) { ... }  // closed range: includes 100
for (i in 1 until 100) { ... } // half-open range: does not include 100
for (x in 2..10 step 2) { ... }
for (x in 10 downTo 1) { ... }
if (x in 1..10) { ... }

The above examples show the for keyword as well as the use of ranges.

Object-oriented programming in Kotlin

Even though Kotlin is a full-fledged functional programming language, it preserves most of the object-oriented nature of Java as an alternative programming style, which is very handy when converting existing Java code. Kotlin has classes with constructors, along with nested, inner, and anonymous inner classes, and it has interfaces like Java 8. Kotlin does not have a new keyword. To create a class instance, call the constructor just like a regular function. We saw that in the screenshot above.

Kotlin has single inheritance from a named superclass, and all Kotlin classes have a default superclass Any, which is not the same as the Java base class java.lang.Object. Any contains only three predefined member functions: equals(), hashCode(), and toString().

Kotlin classes have to be marked with the open keyword in order to allow other classes to inherit from them; Java classes are kind of the opposite, as they are inheritable unless marked with the final keyword. To override a superclass method, the method itself must be marked open, and the subclass method must be marked override. This is all of a piece with Kotlin’s philosophy of making things explicit rather than relying on defaults. In this particular case, I can see where Kotlin’s way of explicitly marking base class members as open for inheritance and derived class members as overrides avoids several kinds of common Java errors.

Safety features in Kotlin

Speaking of avoiding common errors, Kotlin was designed to eliminate the danger of null pointer references and streamline the handling of null values. It does this by making a null illegal for standard types, adding nullable types, and implementing shortcut notations to handle tests for null.

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.

In most cases, calling Java code from Kotlin works the way you might expect. For example, any time both getters and setters exist in a Java class, Kotlin treats them as properties with the same name. Similarly, Boolean accessor methods are treated as properties that have the same name as the getter method. For example:

import java.util.Calendar  

fun calendarDemo() {
     val calendar = Calendar.getInstance()
     if (calendar.firstDayOfWeek == Calendar.SUNDAY) {  // call getFirstDayOfWeek()
         calendar.firstDayOfWeek = Calendar.MONDAY      // call setFirstDayOfWeek()
     }
     if (!calendar.isLenient) {                       // call isLenient()
         calendar.isLenient = true                  // call setLenient()
     }
}

This scheme breaks down for the case of Java set-only properties, which are not yet supported in Kotlin. If a Java class has only a setter, it will not be visible as a property in Kotlin.

Kotlin’s interoperability with Java extends to Java tools. Kotlin doesn’t have its own editors or IDEs; it has plug-ins for the popular Java editors and IDEs, including IntelliJ IDEA, Android Studio, and Eclipse. Kotlin doesn’t have its own build system; it uses Gradle, Maven, and Ant.

Kotlin interoperability with JavaScript

You can use Kotlin to write code for browsers and Node.js. With this target, Kotlin is transpiled to JavaScript ES5.1 instead of being compiled to JVM byte code.

Because JavaScript is a dynamic language, Kotlin for JavaScript adds a dynamic type not available in Kotlin for the JVM:

val dyn: dynamic = ...

The Kotlin type checker ignores dynamic types and lets JavaScript deal with them at runtime. Expressions using values of dynamic type are translated to JavaScript as written. Again, Kotlin basically punts and lets JavaScript interpret the expressions at runtime.

You can call JavaScript from Kotlin two ways: using dynamic types or using strongly typed Kotlin headers for JavaScript libraries. To access well-known, third-party JavaScript frameworks with a strongly typed API, you can convert TypeScript definitions from the DefinitelyTyped type definitions repository to Kotlin using the ts2kt tool.

You can inline JavaScript code as text into your Kotlin code using the js(“…”) function. You can mark package declarations in Kotlin code as pure JavaScript with the external modifier. You can call Kotlin code from JavaScript, but you need to use fully qualified names.

Overall, Kotlin offers a number of advantages over Java for code to be run on the JVM, and can also generate JavaScript and native code. Compared to Java, Kotlin is safer, more concise, and more explicit. It supports functional programming in addition to object-oriented programming, offers a bunch of useful features (extension functions, builders, coroutines, lambdas, etc.), and provides null safety through nullable and non-nullable types. Best of all, if you already know Java, you’ll be productive in Kotlin in no time.

Join the newsletter!

Error: Please check your email address.

More about Eclipse

Show Comments

Market Place

[]