Kotlin, Java, and C#. Differences and Similarities.
You may know that Java and Kotlin programming languages are similar. But what might be surprising is that C# is not that far off. Let’s do some overview.
Here, I will first cover a few fundamental features and then go over some syntax details that are worth mentioning.
Age and popularity
Java appeared in 1995, and C# in 2000. Kotlin first appeared much later, in 2011, and the first stable version was released in 2016.
According to some data, Java is the 4th most popular programming language in 2024. C# is right behind it in 5th place. Kotlin is far behind in 17th place.
Here is a more visual picture according to another source (statista.com):
“Write once, run anywhere”
The main slogan behind Java. This is a good example that in 1995 people were already thinking about cross-platform development, as we do nowadays. C# and Kotlin also try to follow this principle in their own way.
Java uses a virtual machine to run code in different environments. C# can use the .Net framework for the same purpose. Kotlin can be compiled into a JVM and run wherever Java can, or it can be compiled for different platforms independently.
Platforms and applicability
Java is supported on a wide range of platforms, including Windows, macOS, and Linux. Nowadays the largest applicability of Java is server-side development.
C# is primarily used on Windows, although it can be used on other platforms with the .NET Core runtime. C# is used for server-side but also can be helpful for frontend development with Blazor. Atop of this C# is used in Unity cross-platform game engine and Xamarin cross-platform framework.
Kotlin Multiplatform can be compiled for Android, iOS, Web, and Desktop. Kotlin can be used for server-side development almost anywhere Java is used. Also, it’s the main programming language for Android development. Additionally, with the latest updates of the Compose Multiplatform framework, Kotlin is a promising language for cross-platform mobile development.
Bytecode / Intermediate language
All 3 languages are compiled. They compile source code to an intermediate format before translating it to machine code. Java is compiled to bytecode. Kotlin can be compiled to bytecode as well if it targets JVM platform. C# compiles to something similar to bytecode, it’s called Intermediate Language by Microsoft.
Garbage collectors
Another similarity between these languages is that they all have automatic memory management (garbage collectors). The general rule for releasing the memory is simple: if an object is not referenced by someone, it should be cleaned from memory.
Of course, you have to watch your references to prevent memory leaks but in general, Garbage Collector saves a lot of time for programmers.
For comparison: the most famous language where you have to manage memory yourself with functions like
malloc
andfree
is C.
Object-oriented
All these languages are object-oriented which means they support the main concepts of the OOP: Encapsulation, Abstraction, Inheritance, and Polymorphism.
Fun fact: originally, C# was called “Cool” or “C-like Object Oriented Language”.
Strong types
Kotlin, Java, and C# have strong typing systems. This means that the type of a variable is checked before the program is run, and any type mismatches are flagged as errors. This is in contrast to weak typing, where type-checking is done at runtime. In general, it helps to prevent bugs and makes the code more reliable.
For comparison: the most popular language without strong typing is JavaScript. Weak typing may be convenient for small applications, but for a larger codebase it’s a common source of errors.
Structures, inline value classes
What is structure (struct)? It’s a set of fields, like a lightweight class, that doesn’t require heavy class allocations. Structs are useful when you operate with pure data values.
In C# structure types are part of the language, whereas in Java and Kotlin it’s not the case.
In Kotlin, however, there is something similar — inline value classes, but they are very limited in comparison to structs. Why did I mention it as an analog of structures? In some cases, you can pack several values into a single Long or Double variable and it will serve as a struct. For example, take a look at IntOffset
class in Jetpack Compose.
The absence of structs can be mitigated with the Objects Pool pattern which reuses created objects without new allocations, but this requires additional programming efforts.
// Kotlin: Value class will be compiled as a primitive
@JvmInline
value class SomeValueClass(
val first: Int
)
// C#: Struct example
public struct SomeStruct
{
public int First;
public float Second;
}
Null safety
Kotlin has built-in null safety features that help prevent null pointer exceptions in compile time. However, it doesn’t mean that we don’t have null-related errors in Kotlin, because we can still use unsafe casts !!
.
In Java, it’s not the core part of the language but you can use static analysis and Nullable
annotations. Also, Optional
wrappers come to help.
C# has the null-coalescing operator ??
which helps reduce code boilerplate. Also, it has the option to enable compile-time warnings for possible null errors in its latest versions.
Exception handling
In Java there are checked and unchecked Exceptions. You must declare checked exceptions with the throws
keyword and use a try/catch
when invoking it.
In Kotlin you don’t have to declare throws
signature and you don’t have to catch Exceptions. It’s optional. The same in C#.
This may be controversial. Some people like checked exceptions because they declare clearly what to expect from a method. Some people prefer simplicity without checked exceptions.
Pointers / ref
Need to operate on a reference to something? All 3 languages provide this ability but in different ways. In C# there is a ref
and out
keywords for achieving this. Pointers are also supported in C#.
In Kotlin and Java any kind of a reference wrapper can be used, that is in fact just a class that holds a value. Probably the most common reference holders in Kotlin/Java are WeakReference
and AtomicReference
.
Returning multiple values
Functions that return more than one value as a result can be useful in development.
In Kotlin it’s achievable via Pair
, Triple
, and destructuring declarations
.
fun getSomething() = Pair(1, 2f)
Java can return only 1 value from a method. In this case an array
or List
as the returning value can be used as a workaround.
C# can easily return multiple values (typles).
public (int, float) GetSomething() => (1, 2f);
Extension functions
Extensions are very convenient in case of performing some operations on some value. Kotlin and C# have extension functions, whereas Java doesn’t.
Of course, Java community is missing this functionality and in general, it can be achieved with compiler plugins like Manifold.
Interoperability
Kotlin and Java are interoperable, which means that you can use Kotlin/JVM code in Java projects and vice versa.
C# is not interoperable with Java or Kotlin because it doesn’t use JVM.
There’s so much more
Of course, there are a lot of differences that were not mentioned here. But as we just saw, these 3 languages have a lot of features and concepts in common.
Also, languages evolve and adopt new features from each other. For example, in early versions of Java and C# there were not many concerns about null safety but now there are tools for solving nullable-related issues.
Feel free to add your comparison in the comments.
Thanks for reading!