New era of java?
Each year we hear the same old story that Java is too old and it has to stay in the past, it has outdated syntax and features are like from ninetieth or something similar. It might be true in some areas, but today java maintainers do a really good job to modernize language and at the same time we have a lot of other JVM languages that can be used instead of java. One of such languages is Kotlin. Nowadays kotlin became a trend language - it can be used in different cases: traditional backend, web-frontend, mobile-frontend, native applications. Concise and effective syntax is a distinctive feature of this language, but not only this makes it so interesting to use. Let’s take a closer look to Kotlin together - there are a lot of interesting things.
Named arguments and default arguments (less overloading and more readability)
Kotlin allows us to use named and default arguments which makes our code much more readable with less code lines:
- we don’t need to write a lot of overloaded methods
- we can easily change order of arguments if we use named arguments
- we don’t have to name variables before sending them to method - it can be done just during method invocation
We have to keep in mind that:
- if argument with no default value comes after default argument - we have to use named arguments
- if we are overriding some method with default values it is not allowed to provide default values there
- if we are using positional arguments together with named arguments all positional arguments have to come before named arguments
String literals and string formatting
Literals
In kotlin there are two types of string literals: raw strings and escaped strings. The last are just like strings in java - they may contain escape symbols. Raw strings can contain arbitrary text which means we can write text with special characters, new lines.
Escape string literals are delimited with double quotes""
:
Raw strings are delimited with triple quotes """
Raw strings make regexp a bit cleaner because you don’t need to escape backlash with another backslash
Formatting
In kotlin we can use variable just inside of the string using $
symbol
More over we can use expressions inside the string using curly braces like this:
This approach looks much neater then string formatting in java:
Data classes
We all know that getters and setters are needed, but usually we don’t want to write them. More over when they are already written this code is almost never read by others just because it is usually simple and should not contain any heavy logic.
Most of us are probably using lombok for creation of setters and getters. In Kotlin we can have
them by just defining our class as a data
class.
Data class should have at least one property and all properties should be var
or val
.
It can not be abstract, sealed, inner or open.
Every property declared in this class will be used in automatically created equals()
, hashcode ()
,
toString()
, copy()
methods.
Explicit modifiers
Kotlin requires explicit modifiers for class member that can be overridden: which means that
overridable members should have open
modifier and in the deriving class those members should
have override
modifier:
override
modifier allows overriding in the next child class, so if we want to prohibit
overriding we have to use final
modifier.
In cases when we have ambiguity during methods inheritance like this:
Child class inherits do
method from both Parent1
and Parent2
we have to explicitly specify
which implementation has to be called or write our own implementation, but the same logic is in
java as well.
The same rules are applicable for properties, but we have to remember that we can override val
property with var
, but not vice versa - the reason for this is: declared val
property has
only getter when var
property is declared with both getter and setter. So if val
property is
declared in the parent class we automatically have setter for it exposed and inherited by child
classes and it is impossible to hide setter method (therefore impossible to override var
with
val
property)
NOTE: In Kotlin all classes are final by default, we have to specify open
modifier explicitly
Static members
On of the most unusual part as for me is how kotlin allows us to create static fields and methods.
Static fields
We have several ways to provide static fields and for all of them we have to use named objects or companion objects:
- const modifier turns field into static final field:
- lateinit modifier helps us initialize variables with non-null type, but not in the constructor - for example we know that field will be initialized and we don’t want to make it nullable. In this case field will be static and modifiable.
NOTE: The property type has to comply with this restrictions: non-nullable type, not
primitive type. If this property will be accessed before it will be initialized - corresponding
exception will say this explicitly (UninitializedPropertyAccessException: lateinit property name has
not been initialized
). The access level is the same as the access level of getter. Property has
to marked as modifiable variable with var
modifier.
- @JvmField annotation makes field static:
Static methods
Kotlin has two types of static methods:
- top-level methods that are defined in the package:
- methods that are defined in the named objects or companion objects:
Visibility
In kotlin there are four access modifiers: public
, internal
, protected
, private
- which
are almost the same as in java, but:
- the default modifier is
public
internal
modifier is sort ofdefault
modifier in java.
We can use these modifiers for class properties, but not for local variables. When class property
has access modifier - the same modifier will be used for it’s getter
, but we can explicitly
specify the modifier for setter
like this:
Also we can specify classes, properties and functions on top-level:
In the context of top-level members - protected
modifier can not be used.
Nullability
Kotlin avoids NullPointerException by introducing nullable and non-nullable types:
In this example name
variable is nullable (?
indicates about it) when lastName
is
non-nullable. So you can safely use lastName
without worrying about NPE.
Kotlin introduces several convenient ways to use nullable values:
- after checking nullability in if statement compiler already knows that it can trust this variable:
- we can use
?
operator to access members of the nullable variable. In this case if value ofname
variable is null - null will be returned, but if the value is present - length field will be accessed and real value will be returned
Elvis operator
can also help us. It checks whether the variable or expression is null. If it is null it will return value from the right side of the expression, if not null - from the left side
- to safely call method of the nullable type we can use
let
: it will execute piece of code only if object is not null:
In case we think that we can trust variable with nullable type we can use !!
operator to
indicate that this nullable type will be converted explicitly to non-nullable type.
Smart cast
Kotlin’s compiler is pretty smart one: it can autocast your object to needed class once you did check of the type:
Extensions
Another interesting feature of Kotlin is that we can create our own extension of the existing classes without inheritance. There are possibility to create functional extension and property extension by adding receiver type before the name of the property or function:
NOTE: initializers are not allowed in property extension and function extensions are resolved statically which means they are related not to the runtime object, but to the class that was declared
Object expression and declaration
If we want to create an instance of the anonymous class in kotlin we have to use an object
expression
:
As derives from the name object expression
this object can be assigned to some variable when
object declaration
is just a statement:
Object declaration represent singleton which is initialized only when it will be used for the first time (lazily).
Overloading of operators
Kotlin allows us to overload operators - which should be used just as a convenient way to write
concise code. For example if we want to compare two ducks by the length of their name we can do
it with >
, <
operators just by implementing this kind of code:
So for overloading we have to:
- create member function or extension function with receiver
- this function should have
operator
modifier which is a marker for compiler - it has to have argument if we are overloading binary operator (if it is unary operator there should be no arguments)
NOTE: At the same time it is not possible to overload standard operators for basic types because those methods are already declared and they are final. Even we we try to overload it with extension function it will be shadowed by the member function because member function has a precedence.
NOTE: Kotlin allows us to overload ==
which means that Java rule that this operator can be used only
for primitive types to check equality of values is not applicable here as far as we can overload
this operator for specific type to do proper evaluation using equals
method.
Extension functions of the collections
In kotlin standard java collections are used but with additional methods which are provided thanks to extension mechanism:
- convenience method
toList
,toSet
,toMutableSet
,toMutableList
,toSortedSet
filter
andmap
methods can be called directly on collections and we can use them like this:
As you can see we can use:
** explicit variable name duck
or implicit it
** lambda expression can be moved outside from brackets to curly braces according to the rule,
that if lambda is last method argument - it can be moved outside
** filter
method returns filtered collection and not a stream like in java
- methods like
any
,all
,count
,find
that can be used directly on collections and return collection - method like
flatMap
has almost the same logic as in java, but returns collection instead of stream - method that I really like is
groupBy
which creates a map based on you criteria:
Intellij IDEA support
Intellij IDEA is a product of JetBrains as well as Kotlin so naturally that this IDE has outstanding built-in support for Kotlin:
- autocompletion and syntax support
- training courses to master kotlin using Intellij IDEa which I found really useful (a specially when you read docs and do exercises in parallel)
- code style template, for now (February 2019) there are two of them: old and new one - the recommended is a new one.
Integration with Spring
Kotlin is integrated with Spring pretty good. The things you need to remember to use kotlin in your spring boot projects:
- folder structure is a bit different
- additional kotlin dependencies are needed
- kotlin plugin is needed
Folder structure
There is no need to have exactly the same package structure as folder structure in Kotlin.
Dependencies and plugins
In order to use kotlin in our project (built using gradle) we have to include such dependency:
AllOpen plugin is needed to make some classes marked with specific annotations specified in
allOpen
block open. Just keep in mind that all classes in kotlin are final which means that we
will have problems when we want to use spring, because a lot of classes has to be opened in order
to be used by spring. So AllOpen
plugin helps us to specify which classes will be converted
from final
to open
, but as far as those classes are typical for spring jetBrains created wrapper
on top of AllOpen
plugin which makes opened already predefined set of annotations like:
@Transactional, @Cacheable, @SpringBootTest, @Component, @Async
. This plugin has name spring
and can be enabled like this:
Also in order to use kotlin features we need to add standard kotlin library to our dependency:
If we are using gradle we will need also to add kotlin-gradle-plugin which help us create kotlin resources and compile classes:
Typical questions about kotlin
Can I use kotlin and java at the same time?
We can easily use kotlin and java in one project and we can even have a mix of classes in one package written in kotlin and java. But at the same time we have to remember some rules.
Invoke java code from kotlin
- if java code contains method or variables with names that are kotlin keywords we can still use them, but with single quotes:
-
void
return type in kotlin will be converted toUnit
class which is known during the compilation which means that if any variable was using the result of void method - it will be immediately assigned to Unit object during compilation -
if java class contains fields with getters and setters in kotlin they will be visible just like fields, but if the field in java class does not have public getter - this field won’t be visible, because kotlin does not allow fields that can be set-only.
NOTE: setters and getters names have to follow to the naming conventions
- when we are calling java methods from kotlin the return value of them can be null - this
means that java calls are not
NPE
safe. So kotlin can not rely on java api completely and as far as we can not avoid java calls kotlin has to treat java calls a bit differently. That’s why kotlin checks those invocations in a relaxed way. It means that kotlin’s compiler won’t complain during the compilation time, but we might get an exception at runtime (NullPointerException or IllegalStateException in case if we were trying to assignnull
to non-null type variable)
- if
nullability
annotations were used in java - most of them are used by kotlin to createnullable
ornon-nullable
types. For now kotlin considers these annotations:
nullability
annotations can be also used with type arguments in generic types
@NonNull
annotation from the JSR-305 is also supported:
-
kotlin uses it’s own basic types that are mapped to the java types. To see details you can use this link
-
kotlin arrays are invariant which means that it is not possible to put
Integer
inside the array with typeString
. It was done to prevent possible runtime error. Arrays of the primitive types have their own types likeIntArray
,CharArray
. -
to invoke java method’s with varargs we can use spread operator
*
-
the really nice thing is that kotlin does not have checked exception which means that if you invoke java methods that throw checked exceptions, you don’t need to do anything with them.
-
inheritance between java classes and kotlin classes is can be done as usual without additional hassles