Kotlin is a modern alternative to Java that supports functional programming in the JVM. Here's a first look at programming with Kotlin using some of the concepts and syntax you already know from Java.
After Java, Kotlin is the most popular JVM language. Kotlin is an expressive, concise language with strong functional programming support.ย Itโs especially appealing to Java developers because it is fully interoperable with Java, and the syntax is an easy transition.ย Letโs take a look at this dynamic programming language.
Get started with Kotlin
Kotlin is a great language for Java developers to expand into. It complements and embellishes what you already can do with Java and offers serious power from within the JVM ecosystem. Best of all, learning and using Kotlin doesnโt demand much from your already overworked brain, as switching between Java and Kotlin is fairly simple.
Like Java, Kotlin requires that you have a JDK installed. The command-line tool SDKMan makes installing and managing Kotlin simple:
$ sdk install kotlin 2.0.20
$ kotlin -version
Kotlin version 2.0.20-release-327 (JRE 23-ea+24-1995)
Once installed, you can create and run a simple Main.kt file:
// Main.kt
fun main() {
println("Hello, InfoWorld!")
}
To compile it, enter:
$ kotlinc Main.kt
This command outputs a class file: MainKt.class, which you can run just like any other:
$ java MainKt
Hello, Kotlin!
Notice that a function with no return value, like the one above, doesnโt declare a void return value like in Java. Instead, it simply has no return modifier at all.ย Unlike Java, you can declare a function with the fun keyword outside of a class. In simple cases, functions lack all the trappings weโd find in Java: no package, class name, or public static void qualifiers.ย Kotlin has all these capabilities, but it hides them by default, using conventions to provide a simpler syntax up front.
The basic idea in this section was to show how easy it is to write your code in Kotlin, which is like a streamlined and expanded Java, and run it within the JVM. Itโs not that common to run Kotlin directly with Java tooling, but the example makes clear the relationship between Kotlin and Java. Usually, weโd run Kotlin using the kotlin runtime or a build tool like Gradle, which youโll see in a moment.
First-class functions in Kotlin
Kotlin is a first-class functional language. It lets you pass around and return functional references from other functions, which provides enormous flexibility.
It is also often valid to write Java code right beside Kotlin:
// Main.kt
fun main() {
System.out.println("Hello from Java, InfoWorld!");
println("Hello, InfoWorld!")
}
On the other hand, some differences in Kotlinโs syntax make standard Java invalid. For one thing, Kotlin does not have or allow primitive types. In this respect, it is even more Java-like than Java: everything in Kotlin really is an object. There are no int, long, double, or char exceptions. (Project Valhalla is moving Java in a similar direction.)
Kotlin also makes a strong distinction between mutable and immutable variables. This is a common trend in modern languages. Any time you can live with an immutable version, you reduce the complexity of the program. In Kotlin, val means an immutable variable, while var means mutable:
val myValInt: Int = 10;
var myVarInt: Int = 10
// myValInt++;
You may have also noticed by now that semicolons are optional in Kotlin, as they are in JavaScript. However, the common practice in Kotlin is to avoid using terminating semicolons.
Kotlin infers types like so:
val myString = "FooBar";
println("My string ${myString} is a classic.");
The above snippet also demonstrates Kotlinโs built-in String interpolation support, which has a similar syntax to many templating tools. The dollar-sign curly-brace (${}) can also contain expressions, as in: ${myString.upperCase()}. If the variable name is one without special characters, you can use a simplified form of it:
println("When in doubt, $myString.");
Beneath everything is Javaโs type system, which you can access by typing:
println(myString::class.java.typeName); // Outputs โStringโ
Nulls
One of Kotlinโs embellishments is its more explicit handling of nulls. The NullPointerException is one of the most familiar exceptions in Java. In Kotlin, variables are non-nullable by default. The compiler will not allow you to set a null on normal variables. If you want a nullable version, you can set it up like so:
val myNullableString: String? = null
Kotlin also has the .? and :? operators to help deal with nulls. The .? is similar to JavaScriptโs recently added optional chaining operator, and lets you short-circuit on null values without verbose checks:
possiblyNull.?possiblyNullMember.?anotherMember
If any of the parts are null, the whole expression returns null, without error. The nullish coalescing operator (?:โalso called Elvis operator because itโs like an emoji with Elvis hair) lets you test the left side for null and return it if its non-null. Otherwise, itโll return the right side, which may also be null:
something :? somethingElse
If something is null, youโll get somethingElse.
Collections
Of course, you need to be able to handle collections of variables, and Kotlin has all the sets, lists, and maps youโd expect. These also allow for both mutable and immutable variants. So if you want a mutable list of strings you can enter something like:
import kotlin.collections.*;
fun main() {
val books: MutableList = mutableListOf("Autobiography of a Yogi", "Slaughterhouse Five", "Phaedrus");
println(books[2]);
}
Notice we imported the collections library in this snippet. Since that library exists in the Kotlin standard library, we can compile it:
$ kotlinc Main.kt
But it wonโt run. Instead, we get
$ java MainKt
Exception in thread "main" java.lang.NoClassDefFoundError: kotlin/collections/CollectionsKt
at MainKt.main(Main.kt:14)
at MainKt.main(Main.kt)
Caused by: java.lang.ClassNotFoundException: kotlin.collections.CollectionsKt
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:528)
This is a familiar Java error telling us a class definition for CollectionsKt canโt be found. To get around the error, we need to include the standard library during runtime, like so:
$ java -cp /home/matthewcarltyson/kotlin:/home/matthewcarltyson/.sdkman/candidates/kotlin/current/lib/kotlin-stdlib.jar MainKt
Phaedrus
This command tells Java to include the kotlin-stdlib.jar (though yours might be be in a different location). Another approach is to use the kotlin runtime, which automatically includes stdlib for you:
$ kotlin MainKt
Kotlin also gives you strong functional programming support. For example, to check our books collection for a book we want, weโd enter:
println("Phaedrus" in books) // outputs true
Also note that we can access lists just like arrays, using brackets:
println(books[2]) // outputs โPhaedrusโ
Using Gradle with Kotlin
Gradle is often used as a build tool in Kotlin because you can use the Kotlin DSL instead of Groovy.
The easiest way to use Gradle and Kotlin together is to start a fresh project with Gradle init. That command launches an interactive questionnaire from the command line, shown with my answers here:
$ gradle init
Select type of project to generate: 2: application
Select implementation language: 4: Kotlin
Split functionality across multiple subprojects?: 1: no - only one application project
Select build script DSL: 2: Kotlin
Generate build using new APIs and behavior (some features may change in the next minor release)? (default: no) [yes, no]: no
Project name (default: kotlin): kotlin
Source package (default: kotlin): com.infoworld
My selections results in a Kotlin application using Kotlin as the build script language. Now, you can run this simple program from the project root with:
$ ./gradlew run
When you run the program, youโll get a โHello, Worldโ greeting. Hereโs how the project is laid out:
/settings.gradle.kts - Global settings for Gradle
/app/ build.gradle.kts - The build file
/app/src/main/kotlin/com/infoworld/App.kt - The single source file
Looking at the App.kt file, youโll see:
package com.infoworld
class App {
val greeting: String
get() {
return "Hello World!"
}
}
fun main() {
println(App().greeting)
}
There are some features here that you have not yet seen, including the use of a package declaration (in Kotlin, the package and directory structure donโt strictly have to match).
You can also see Kotlinโs streamlined syntax for declaring a class. In Kotlin, thedefault visibility of a class is public, so App is a public class. Inside of it, there is a read-only String member called greeting (remember that val declares a read-only variable). Notice that the greeting property declares a get() function. This is what will be executed when we use the dot operator to access it, something like a streamlined getter.
Now letโs attempt something more ambitious and download the character data for Chewbacca from the Star Wars API. We can modify the App.kt file like so:
//app/src/main/kotlin/com/infoworld/App.kt
package com.infoworld
import com.google.gson.Gson
import java.net.URL
class App {
fun fetchAndPrintCharacterInfo(url: String) {
val gson = Gson()
val response = URL(url).readText()
val character = gson.fromJson(response, StarWarsCharacter::class.java)
println("Name: ${character.name}")
println("Height: ${character.height}")
}
}
data class StarWarsCharacter(
val name: String,
val height: String,
)
fun main() {
val chewbaccaUrl = "https://swapi.dev/api/people/13/"
val app = App()
app.fetchAndPrintCharacterInfo(chewbaccaUrl)
}
This gives us a look at Kotlinโs data class, which is designed for holding information (something akin to Javaโs value objects). The StarWarsCharacter class has all the standard methods like getters and setters, hashCode, toString, and equals. It is ideal for unpacking API data into a container, which is what weโre doing here.
Add the following dependency to the dependencies section of /app/build.gradle.kts:
implementation("com.google.code.gson:gson:2.9.1")
This lets us handle the JSON weโll get back from the API. Now, if we run the app weโll see some information about Chewbacca:
$ ./gradlew run
> Task :app:run
Name: Chewbacca
Height: 228
Hair color: null
Eye color: null
BUILD SUCCESSFUL in 2s
Conclusion
The beauty of Kotlin for Java developers is that it fits fairly easily into your existing mental model. Kotlin lets you program inside the JVM, with all its intensive optimization and vast ecosystem, but with a functional language that is in some ways โmore Java than Java,โ yet easy to grasp and powerful. You can also use Kotlin alongside Java, so you donโt have to choose one or the other.
Thereโs a lot more to Kotlin, including an extension function (which lets you add class functions without subclasses), coroutines, more functional capabilities, lack of checked exceptions, and a simplified approach to object-oriented programming. Weโll continue exploring Kotlin and its features in my next article.


