In this article, we’ll make a comparison between Java and Kotlin, two popular Java programming languages.
2. Java Specific Features
2.1. Checked Exceptions
Java has support for the checked exceptions that must be declared and caught in the code. Therefore, Java developers ensure more robust code by handling errors in the code.
2.2. Primitive Types
Java contains primitive types that are pre-defined data types. Consequently, a variable declared with a primitive type is not an object.
Furthermore, Java has eight primitive data types: int, byte, short, double, float, boolean, char, and long.
2.3. Wildcard Types
Java supports the use of wildcard types by the placement of a question mark (?) in a type specifier. Hence, it suggests an unknown type of a local variable, parameter, field, or return value.
2.4. Ternary Operator
Java’s ternary operator ?: is a condensed substitute of the if-else condition that returns the value, offering shorter, more readable, and clearer code.
Internally, however, Java compiles the ternary operator exactly like the if-else condition.
2.5. Static Members
Java supports static members, implying that only one such instance is created and shared across all instances of a class.
2.6. Implicit Widening Conversions
Java supports widening conversions implicitly. Hence, it allows the conversion of smaller-sized data types to larger-sized data types.
2.7. Non-private Fields
Java allows non-private or public fields — handy in scenarios where a developer might want to allow access from anywhere.
3. Kotlin Specific Features
3.1. Data Classes
Kotlin supports data classes (meant to hold some data) by defining a data keyword in the class definition. So, the compiler auto-generates getters/setters and constructors for the data class. However, since Java 14, the record keyword is available to define immutable data classes in Java.
3.2. String Templates
Kotlin supports the String template – String literals that contain embedded expressions. Also, the value of the embedded expression is determined and concatenated into the string at runtime.
3.3. Primary Constructors
Kotlin supports primary constructors. A Kotlin class can have secondary constructors if required, in addition to a primary constructor.
Kotlin makes it easy to declare a singleton simply by declaring an object. Further, the initialization of the singleton object is done on the first access and is thread-safe, too.
3.5. Range Expressions
Kotlin supports range expressions using the rangeTo function (expressed as ..), which proves handy to create and iterate over a range of values, thereby promoting shorter and readable code.
Similarly, we can use the downTo operator to iterate over a range in reverse order.
3.6. Operator Overloading
Kotlin supports operator overloading by defining custom implementations for the pre-defined set of operators on types.
3.7. Implicit Delegation
Kotlin supports implicit delegation by utilizing the composition over inheritance design pattern. Furthermore, class delegation provides the possibility of having multiple inheritances.
3.8. Trailing Lambdas
If we pass a lambda as the last parameter to a function, we can pass the lambda outside of the parentheses. An example can be found in our article about lambdas in Kotlin: Lambda Literal Outside the Brackets.
3.9. Lamdas with a Single Parameter
In Kotlin we can use the shorthand variable it to refer to the single parameter inside a lambda.
3.10. Infix Notation
A function with only one single parameter can be declared as an infix function. This allows us to call it without parentheses, which makes the function call look much more like natural language.
3.11. Named and Default Arguments
Kotlin provides an alternative to method overloading. A function can have named parameters, which allow us to call a function with its parameters in a different order. Also, using named parameters can improve the readability of the code. You can read more about this topic in our article Quick Guide to Kotlin Default and Named Arguments.
3.12. Lazy Initialization
Kotlin provides built-in support for lazy initialization of objects. Read more about that interesting feature in our article Lazy Initialization in Kotlin.
4. Java vs. Kotlin
Java follows the traditional approach of verbosity in writing the code. However, Kotlin, being a modern programming language, applies the principle of conciseness.
Kotlin, known for brevity, allows us to significantly reduce the amount of boilerplate code, resulting in fewer lines of code than we’d need in the Java equivalent. Hence, Kotlin is more readable and less prone to human-made errors.
4.2. Null Safety
Java allows assigning null values to the objects. So, when a member of a null reference is accessed, it results in the most notorious NullPointerException.
However, Kotlin doesn’t allow us to set the null values by default. Hence, Kotlin offers better code stability by practicing null safety.
4.3. Extension Functions
To extend methods in Java, we must inherit the class and override them. However, Kotlin comes with the feature of extension functions that don’t necessarily require inheriting the class.
4.4. Strict vs. Static Typing
Java is a strictly typed language, meaning all variables are declared with a type when created. On the other hand, Kotlin is a statically typed language that can decide the type of a variable based on the type of the assignment value.
4.5. Smart Casting
With Java, the developer must check the type of the variable and cast it accordingly per operation.
However, Kotlin comes with a smart casting feature as the compiler automatically manages it.
4.6. Functional Programming
Java is an Object-Oriented Programming language, whereas Kotlin features the behavior of both OOPs and Functional programming languages.
For instance, in comparison to Java, we can use Lambda expressions with inline functions in Kotlin. Additionally, Kotlin supports other functional programming features like delegates and extension functions.
4.7. Coroutines Support
Java allows creating multiple threads in the background to run long-running, CPU-intensive operations. However, it’s a complex task to manage multiple threads.
On the other hand, Kotlin has coroutines support that can suspend the execution of blocking threads at a certain point.
4.8. Sealed Classes
Kotlin implemented the concept of sealed classes from its start. Java introduced sealed classes as a preview feature in Java 15, and as of Java 17, sealed classes are fully part of the language. Our two articles Sealed Classes in Kotlin, and Sealed Classes and Interfaces in Java 15 cover sealed classes in both languages. Here, we’ll only give a short summary of the main difference between the implementation in Java and Kotlin.
- In Java, only classes in the same module can inherit from a sealed class. In Kotlin, the subclass must be defined in the same file.
- In Java, a sealed class must define explicitly which classes can extend it. To do so, we can use the reserved identifier permits. In Kotlin, any class in the same file can inherit from a sealed class.
- In Kotlin, the type of an object can be used in the switch statement, whereas Java introduces pattern matching for its switch statement only as a preview feature in Java 17.
4.9. Compilation Time
Java compilation time is 15-20% faster than Kotlin. However, when we consider incremental build compilation, Kotlin shows compilation performance similar to Java.
4.10. Platform Compatability
Also, we can use the Kotlin Multiplatform framework to extract one common codebase compatible with all the platforms.
4.11. Use Cases
Java, as we know, is the most general-purpose JVM programming language. Therefore, it’s usually favored for a variety of projects like standalone applications and backend applications.
On the other hand, Kotlin is another popular programming language that’s also the most preferred language for Android development.
In this article, we compared two JVM programming languages, Java and Kotlin.
First, we explored a few specific features of both Java and Kotlin. Then, we made a direct comparison between the two.