Everyone’s heard of Java. According to PYPL’s analysis of Google Trends, it sits at second place after Python on the popularity ranking — with 17.17% of total language tutorials searches. Java has been around since 1995 and can be considered a staple to application stacks due to its long history, general reliability, and active support.
It is the default language for Android development, along with server-side and back-end development projects. Java is well established in desktop, mobile, and gaming. So where does Kotlin come in?
Kotlin, however, is native by design and is able to run on any that Java can also run. Since October 2017, Kotlin is treated as a first-class and supported language for Android development, in addition to Java.
But Kotlin is not Java — in fact, it is being labeled as safer than Java. This leads to the question of how and why? and what does it mean for the security of your apps when it comes down to using either Java or Kotlin.
Typing, syntax, and speed compared
Over the past few years, Android has shifted its focus on Java over to Kotlin. So what makes Kotlin special?
Kotlin’s security against NullPointerException is implemented through a null safety methodology, whereas catches are required to be implemented by the developer in Java. The security risk of NullPointerException is that it has the potential to crash a program and is often considered in the realm of being a serious bug. Vulnerabilities rise in Java when null is accepted in places where they shouldn’t be.
The security dangers of null reference exceptions
Null reference exceptions, also known as null dereference, is one of OWASP major security vulnerabilities to look out for in an application. The problem is null is that it is a non-value value. In Java, it has no intrinsic data type and requires special handling.
For example, you are designing a method that finds a user in a database. The bad, but common practice is to return null when nothing is found. While on the surface, it makes sense — because null is supposed to represent a lack of the thing existing — however, it morphs the expected object returned type, which can lead to potential crashes further in the code.
When it comes to object-oriented thinking, the general recommendation is to design objects with immutability in mind. When an object changes its state, it exposes vulnerabilities to data structures and integrity. When null is used, the object is both incomplete and mutable. By default, Java crashes a program when null is raised, which causes a null pointer exception. However, developers often put in a catch exception handling to combat this issue, meaning that it allows the program to bypass the potential risk of null being accepted in spaces where it should not.
For example, the code below is a bad case of the developer ignoring the potential issue of a null slipping through by creating a NullPointerException catch. This catch silently fails the program, which allows it to continue to run.
The proper pattern to prevent a null from occurring is to explicitly create checks against the existence of null. Here is what the code should look like:
We don’t have this issue of null handling in Kotlin because it introduces a concept of null safety as part of its overall design and implementation. While null pointer exceptions can still occur in Kotlin, there are only a handful of ways this can occur.
One way is to explicitly call thow NullPointerException() in the code. Another method is through the usage of !! (not null) operators. Lastly, null pointers only occur in Kotlin if there is data inconsistency in the initialization.
By design, Kotlin type system comes with the ability to throw exceptions if a cast is considered unsafe, and therefore making the type un-nullable. This cannot be done in Java. Unsafe casts are considered so because it creates an invalid definition of the typed item, which can lead to undefined errors on static targets.
Kotlin has everything that Java needs
In addition to null safety, Kotlin contains a long list of features that Java needs but doesn’t have. This includes:
- lambda expressions and inline functions
- extension functions
- smart casting
- string templates
- primary constructors
- first-class delegation
- type inference for variable and property types
- range expressions
- operator overloading
- companion objects
- data classes
- separate interfaces for read-only and mutable collections
- and coroutines
In contrast, features that are available in Java that aren’t available in Kotlin are a much shorter list. However, the ‘missing’ features are made up by replacement and alternative features that are available in Kotlin.
These features are:
- static members in Java is replaced by companion objects, top-level functions, and extension functions in Kotlin
- wildcard-types are replaced by declaration site variance and type projections
- and ternary-operators are replaced with if expressions
Final thoughts: There’s more to it than just null
The issue with null is only one of the many security vulnerabilities that come by default with Java. While Kotlin doesn’t eliminate the usage of null, its handling of it is much better and less tempting for developers to simply use a NullPointerException catch.
For example, raw types still exist in Java due to compatibility reasons but are highly recommended against since the introduction of generics. While raw types are legal during run time, it poses a security risk because manual checks are required when a raw type contains anything other than the expected type. In a way, it can be viewed as another messy version of null, but with types involved.
Raw type is just one example of things that Java knows it should no longer support or have, but continues to exist for various reasons. Kotlin, being a newer language, is able to mitigate this by looking at all the things that Java is good at, take the best parts, and eliminate the dangerous and unnecessary. As a result, Kotlin’s overall security is much tighter than Java.