Kotlin from the Ground Up (Part 3)

Mike Warner
9 min readJul 10, 2020

--

Click here to go back to the start of the series where you can view the TOC.

What does this part cover:

  1. What does Kotlin have to do with Java?
  2. A few key takeaways

What does Kotlin have to do with Java?

This article describes how Kotlin relates to Java, how it targets the JVM, and a comparison between Kotlin, Scala and Java.

This article from the official docs details the main differences between Kotlin and Java (describing what each has that the other does not).

Some of the main things that Kotlin has that Java does not are:

  • Lambda expressions & inline functions
  • Extension functions
  • Null-safety
  • Smart casts
  • Type inference
  • Singletons
  • Data classes
  • Coroutines

Using Java libraries and classes in Kotlin:

Kotlin and Java are interoperable, meaning you can use Java libraries in your Kotlin project, but you can also write Java classes, hence why in a Gradle project it recommends separating the source into Java and Kotlin directories.

This tutorial shows you how to add a Java class to an existing Kotlin project. It’s pretty simple though, just right click in the project explorer and click New → Java Class.

So let’s create a new project where we mix in some Java and Kotlin for fun!

Follow these steps first:

  • File → New → Project
  • Kotlin → JVM | IDEA
  • Name it “kt-hello”, select JDK 11 or 12, and keep the “src” folder selected
  • Click on Tools → Kotlin → Configure Kotlin in Project
  • Right click on “src” in the project manager on the left
  • Click on New → Package
  • Enter com.example.greetings as package name

Right click on the package and create a new Kotlin class KotlinGreeter

package com.example.greetingsclass KotlinGreeter(name: String) {
init {
println("Hi $name!")
}
}

Right click on the package and create a new Java class JavaGreeter

package com.example.greetings;public class JavaGreeter {
public JavaGreeter(String name) {
System.out.println("Hello " + name);
}
}

Right click on src and create a new Kotlin file app.kt

import com.example.greetings.KotlinGreeter
import com.example.greetings.JavaGreeter
fun main(args: Array<String>) {
val name = args.firstOrNull() ?: "John"
KotlinGreeter(name)
JavaGreeter(name)
}

Click on “terminal” below (or View → Tool windows → Terminal) and run:

kotlinc src -include-runtime -d app.jarjava -jar app.jar BobOUTPUT:
Hi Bob!
thread "main" java.lang.NoClassDefFoundError: com/example/greetings/JavaGreeter at AppKt.main(app.kt:7)
Caused by: java.lang.ClassNotFoundException: com.example.greetings.JavaGreeter

Interesting! Let’s try running it using IntelliJ: Press the green “run” button…

If you don’t see a green play button on the left of “fun main” do this:

You should see that the output is now correct:

Hi John!
Hello John

If you look at the full command above you’ll see it has quite a large classpath (we’ll cover what classpath is in a bit, don’t worry)

What if we try to run what we were trying with that classpath?

kotlinc src -include-runtime -d app.jarjava -Dfile.encoding=UTF-8 -classpath "/Users/user/apps/kt-hello/app.jar:/Users/user/Library/Application Support/IdeaIC2019.2/Kotlin/kotlinc/lib/kotlin-stdlib.jar:/Users/user/Library/Application Support/IdeaIC2019.2/Kotlin/kotlinc/lib/kotlin-reflect.jar:/Users/user/Library/Application Support/IdeaIC2019.2/Kotlin/kotlinc/lib/kotlin-test.jar:/Users/user/Library/Application Support/IdeaIC2019.2/Kotlin/kotlinc/lib/kotlin-stdlib-jdk7.jar:/Users/user/Library/Application Support/IdeaIC2019.2/Kotlin/kotlinc/lib/kotlin-stdlib-jdk8.jar" -jar app.jar GregOUTPUT:
Same error as before...

Why is this happening? Let’s inspect our app.jar more closely.

What is a JAR? It is just a (compressed) java archive containing Java bytecode (which we’ll dive into very soon, I promise)

If you run jar xf app.jar you’ll decompress the archive. Be careful as it will extract the contents into the same directory!

This is the result of doing that:

Ok, so we only have our Kotlin classes, that’s the problem!

Oh, and did you notice kotlin? That’s due to -include-runtime 😄

kotlinc only compiles Kotlin files, see the top answer here for more info.

You need to use javac to compile Java classes!

This also explains why you have separate sections in Gradle for Java and Kotlin dependencies which we will see in Part 2.

What are those .class files by the way? Are they Java code?

Ok, not exactly… um… wait… what on earth is cafe babe at the start?!? 😂

This article has the answer. Essentially it is a hexadecimal number which is 3405691582 in decimal, used as a magic string. I highly recommend you go and read the full explanation in the article as it is rather funny.

However, what is the actual contents of the .class then?

You can decompile it with javap:

javap -c KotlinGreeterCompiled from "KotlinGreeter.kt"
public final class com.example.greetings.KotlinGreeter {
public com.example.greetings.KotlinGreeter(java.lang.String);
Code:
0: aload_1
1: ldc #9 // String name
3: invokestatic #15 // Method kotlin/...
6: aload_0
7: invokespecial #18 // Method java/lang/O...
10: new #20 // class java/lang/St...
13: dup
14: invokespecial #21 // Method java/lang/S...
17: ldc #23 // String Hi
19: invokevirtual #27 // Method java/lang/S...
22: aload_1
23: invokevirtual #27 // Method java/lang/S...
26: bipush 33
28: invokevirtual #30 // Method java/lang/S...
31: invokevirtual #34 // Method java/lang/S...
34: astore_2
35: iconst_0
36: istore_3
37: getstatic #40 // Field java/lang/Sy...
40: aload_2
41: invokevirtual #46 // Method java/io/Pri...
44: return
}

Java bytecode! At last we meet!

Given that running javac will generate a new JAR, we will need to run our app with both JARs in the classpath

So lets try it out:

  • We already have our Kotlin app.jar so I won’t worry about that
  • Let’s generate one for Java: javac $(find . -name “*.java”) -d java.jar
  • The command in $() will recursively find our Java files in the project
  • You can alternatively run javac src/com/example/greetings/JavaGreeter.java -d java.jar

This will create the following JAR:

Yes! Our Java class, finally! And with the right path as well!

Now let’s “smash them together” to run our application:

java -cp app.jar:java.jar AppKt "Bob"OUTPUT:
Hi Bob!
Hello Bob

Greetings Bob! Just who I was expecting to see 😄

You’ll notice we used AppKt instead of -jar app.jar this time, that’s because we provided a classpath with multiple JARs, so we had to instead input the class name for the entry point, and kotlinc appends Kt to the name 😁

What about converting existing Java code to Kotlin?

You have two options:

  1. The Kotlin plugin (when we start working with Gradle in part 2 you’ll learn more about this) bundles a J2K plugin which converts Java to Kotlin. You can use it to convert full Java files by clicking on “Code → Convert Java File to Kotlin File” in IntelliJ.
  2. When pasting Java code in a Kotlin file a dialog box will pop up prompting you if you’d like to convert it into Kotlin code

Some manual tweaking may be required. It is useful to remain vigilant of non-optimal code, as certain Kotlin construct may result in slightly worse-performing code than the Java equivalent. We’ll have a section on writing performant code in the last part of this tutorial.

Java bytecode:

Now, we had a brief look at what Java bytecode looks like, but what is it?

Java bytecode is the instruction set of the JVM, you don’t need to know it or understand it, but it’s useful to know a bit about it. In most cases if you want to analyse performance you’ll transpile your Kotlin code to Java to see what it is doing behind the scenes.

To see the Java bytecode (or Java source) of a Kotlin file, follow these steps. You can go to any Kotlin class and go to Tools → Kotlin → Show Bytecode

For now I won’t dive into this as we’ll have a section on writing performant code in one of the future parts of this tutorial.

This short article will give you a bit more insight into Java bytecode, if you aren’t bored by me rambling on and you’re still hungry for knowledge :)

The “classpath”:

The CLASSPATH env variable tells the JDK which Java classes/JARs to use. At least one of them should have a main function to use as an entry point (for projects that are not libraries).

It is similar to the PATH variable in the sense that you concatenate paths using : as a separator.

The preferred way of using it is to set the -cp or -classpath argument to set the locations (you can find some examples above). If the argument is not passed it should fall back on the environment variable.

This article explains in more detail how to set it. This Wikipedia article explains in more detail what a classpath is, including how to add all JARs in a directory to the classpath dynamically.

Null-safety:

You might remember earlier on we briefly touched upon null-safety and I brought up this article. Well, it is finally time to tackle it.

Sir Tony Hoare invented null references in 1965, which he calls his billion-dollar mistake.

In many programming languages, trying to access a property or method of a null reference results in a null reference exception. You might have seen it as NullPointerException in Java, or the infamous cannot read property of undefined in Javascript. It’s also the reason you’ll find isset() and !empty() everywhere in PHP code.

Kotlin aims to eliminate these exceptions through various means.

The article I linked to above covers null-safety in great detail, so instead of just repeating it, I’ll explain the main points through examples in a code block:

// Variables are non-nullable by default
var person = "John"
person = null
>> error: null can not be a value of a non-null type String
// Add a question mark after the type to make it nullable
var name: String? = "John"
name = null
// Printing a null variable will output "null"
println("Hi $name")
>> Hi null
// Accessing a property/method on null will not let you compile
println(name.length)
>> error: unresolved reference: length
// What if we need to access a property on a nullable object?
var longName = if (name != null) name.length > 10 else false
println(longName)
>> false
// Can we set longName to the length only if it is not null?
val nameSize = name?.length
println(longName)
>> 4
// Can we create chains of those to check for anything being null?
val firstLetter = name?.firstOrNull()?.toString()?.toLowerCase()
>> null // If anything in the chain is null, it returns null
// The Elvis operator can set a default if the left part is null
val firstOrX = name?.firstOrNull() ?: 'x'
>> x
// What if you really want an NPE (or you are SURE it is not null)
val first = name!!.firstOrNull()
>> kotlin.KotlinNullPointerException

The last one (not-null assertion operator !!) is useful with Java libraries in certain occasions. However, if you see these being used in pure Kotlin code they should raise a red flag. Read this article to learn more about proper usage.

Debugging exceptions in Java classes:

You might end up eventually using Java classes or libraries in your Kotlin project, specially when a library has only been made for Java.

You might get errors like “‘…/bin/java’ finished with non-zero exit value 1” but you can’t see the stack trace. A way around this is to try running your project with ./gradlew run --stacktrace to see the full exception.

Of course you’ll need Gradle for this, which we’ll cover in Part 2. I didn’t find how to output the stack traces only using kotlinc and java, so if you find a way, please let me know :)

Some final reference material:

This article from the official docs dives into Java-Kotlin interoperability more extensively, which I’d recommend you read after finishing this tutorial.

This article from the official docs dives a bit further into kotlinc arguments.

This article dives into the java command line options.

See this article for more info on javac arguments

A few key takeaways

  1. JARs: (compressed) Java archive which contains Java bytecode (.class files) as well as artefacts, resources, metadata, etc.
  2. cafe babe

Thanks for reading, click here to go to the next part.

--

--

Mike Warner

Software Engineer specialised in PHP, Python, NodeJS, Kotlin and React