Kotlin has been around for a while now, but hasn't been getting the attention it deserves. Stack Overflow makes this painfully obvious:
(Source: Stack Overflow)
For every Kotlin-related question on Stackoverflow, people ask 30 Java-related questions. On the other side, it's not a bad score for a language that had its 1.0 birthday last year. Kotlin clearly isn't the latest fad for hipster programmers (do those actually exist?).
This article is meant for you: the Java programmer who hasn't heard of Kotlin (or tried it), and is eager to make his day-to-day Java programming easier.
So, why should you try it?
Having a Java background, I was able to write Kotlin almost instantly. For example, take a simple 'Hello, World!' program:
public class HelloWorld {
public static void main(String... args) {
System.out.println("Hello, World!");
}
}
In Kotlin, it becomes:
fun main(args: Array<String>) = println("Hello, World!")
Notice a few things here:
The JVM has proven to be a great platform for languages other than Java, both functional and procedural; (e.g.: Clojure, Groovy, Scala, Jython, JRuby, etc). It's mature, runs on almost any platform and there are loads of debugging/monitoring tools.
Although you can run the Kotlin compiler as a standalone Command Line utility, there is support for Ant, Maven, Gradle and Griffon. Since it is backed by JetBrains (known for their top-of-the-line developer tools) more can be expected in future.
You can call any Java code from your Kotlin application the same way you call Kotlin code. Calling Kotlin code from Java is just as easy although there are some things to consider, because there are constructs in Kotlin that don't exist in Java.
Kotlin allows you to write code that is null safe; think Elm's Maybe or Java 8's Optional. By default, values or variables are non-nullable unless you specify it as being nullable:
data class Record(val name: String)
val record = Record(null) // Compile error!
Consuming potential null values leads to compiler errors:
fun retrieveName(): String? = null // Notice the ? (question mark), indicating the result may be null
fun execute() {
val name = retrieveName()
val nameLength = name.length // Compile error! 'name' might be null
if (name != null) {
val nameLength = name.length // This compiles (null has been checked)
}
}
Unfortunately, we're not entirely cured from NullPointerExceptions. When dereferencing a Java type (for which Kotlin has no notion about nullability), you still have to explicitly check for null values:
fun openUrl(url: String) =
URL(url).openConnection()?.connect() // openConnection() might return null, so use the question mark to call connect() safely
Google recommends you to use it when developing for Android, so why not stick to their advice?
Writing code that is clean, expressive, no-nonsense and maintainable is fun, the opposite (messy, redundant, wrong kind of verbosity) isn't. That's why you should write code using Kotlin.
import java.io.File
import java.nio.file.Files
import java.nio.file.Paths
fun fileToStdOut(fileName: String) =
File(fileName)
.inputStream()
.reader()
.use { println(it.readText()) }
or:
import java.nio.file.Files
import java.nio.file.Paths
fun fileToStdOut(fileName: String) =
println(String(Files.readAllBytes(Paths.get(fileName)), Charsets.UTF_8))
The Java-equivalent would be:
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Paths;
public class Example {
public void fileToStdOut(final String fileName) throws IOException {
if (fileName == null) {
throw new IllegalArgumentException("fileName is null");
}
final String text = new String(Files.readAllBytes(Paths.get(fileName)), Charset.forName("UTF-8"));
System.out.println(text);
}
}
Beside the JVM, Kotlin compiles to Javascript and native code. Not that I felt the need (yet), but it's nice to have the options.
No more poorly implemented singletons: Kotlin's 'object' keyword transforms a class into a singleton.
interface State {
fun report()
}
object StaticState : State {
override fun report() = println("This is a singleton.")
}
class Application(val state: State) {
fun run() = state.report()
}
fun main() = Application(StaticState).run()
A few things are happening here:
That's it!