5 Things You Will Like in Kotlin as a Java Developer
5 Things You Will Like in Kotlin as a Java Developer
On the fence about whether to get into the Kotlin world? Here are five things that could very well make up your mind.
Join the DZone community and get the full member experience.Join For Free
Atomist automates your software deliver experience. It's how modern teams deliver modern software.
The Kotlin language is gaining more and more popularity. It is widely used no longer just in mobile apps development, but also for server-side systems. As you probably know, it is a statically-typed programming language that runs on the JVM. That's why it is often compared with the Java language. One of the main reasons for Kotlin popularity is simplicity. It cleans and removes a lot of the code bloat from Java. However, it is also very similar to Java so that any experienced Java developer can pick up Kotlin in just a few hours.
In this article, I'm going to discuss some interesting Kotlin features used for server-side development in comparison to Java. Here's my personal list of favorite Kotlin features that are unavailable with the Java language.
1. Collections and Generics
I really like Java, but sometimes, working with generic collections may be an unpleasant experience, especially if you have to use wildcard types. The good news) { this.l.addAll(l); } public void add(T t) { l.add(t); } }
Now, I would like to store all the vehicles in that repository, so I declare the
Repository r = new Repository(). But, invoking the repository method
addAll with
List as a parameter will receive the following error:
Of course, this situation has a logical explanation. First, generic types in Java are invariant, which, in fact, means that
List is not a subtype of
List, although
Truck is a subtype of
Vehicle. The
addAll method takes the wildcard type argument and extends T as a parameter, which indicates that this method accepts a collection of objects of T or some subtype of T — not just T itself.
The
List is a subtype of
List<? extends Vehicle>, but the target list is still
List. I don't want to get into details about this behavior — you can read more about it in Java specification. The important thing for us is that Kotlin is solving this problem using a feature called Declaration-site variance. If we add the
out modifier to the
MutableList parameter inside the
addAll method declaration, the compiler will allow adding a list of
Truck objects. The smart explanation of that process is provided on the Kotlin site: ) { val r = Repository<Vehicle>() var l1: MutableList<Truck> = ArrayList() l1.add(Truck()) r.addAll(l1) println("${r.l.size}") }
2. Data Classes
You probably know Java's POJOs (Plain Old Java Object). If you are following the Java best practices, such a class should implement getters, setters,
hashCode, and
equals methods, as well as the
toString method for logging needs. Such an implementation may take up a lot of space, even for a simple class with only four fields. This is also, which a Java application is quite simple and supported by all the main developer IDEs, but Kotlin solves this issue out-of-the-box. It provides functionality called data classes, which are enabled after adding the keyword
data to the class definition. The compiler automatically derives the methods from all properties declared in the primary constructor: here is that the compiler only uses the properties defined inside the primary constructor for the automatically generated functions. So, the field
age, which is declared inside the class body, will not be used by
toString,
equals,
hashCode, and
copy implementations.
3. Names for Test Methods
Now, let's implement some test cases to prove that the features described in step twowork properly. The following three tests are comparing two objects with different values of
age property, trying to add the same object to the Java
HashSet twice and checking if the
componentN method of() val person = Person("John", "Smith", 1) var added = s.add(person) Assert.assertTrue(added) added = s.add(person) Assert.assertFalse(added) }
As you can see on the fragment of code above, Kotlin is accepting to use method names with spaces enclosed in backticks. Thanks to that, I can set a descriptive form of test name, which is then visible during execution, and you know exactly what's going on.
4. Extensions
Let's consider the situation that we have a library that contains class definitions, which cannot be changed, and we need to add there some methods. In Java, we have some choices to implement such an approach. We can just extend the existing class, implement a new method, or, for example, implement it with the Decorator pattern.
Now, let's assume we have the following Java class containing the list of persons and exposing getters/setters.
public class Organization { private List<Person> persons; public List<Person> getPersons() { return persons; } public void setPersons(List<Person> persons) { this.persons = persons; } }
If I would like to have the method for adding a single
Person object to the list, I would have to extend the
Organization and implement a a simple
Listclass as immutable, we need to define the
MutableList.
class Organization(val persons: MutableList = ArrayList()) { }
We can easily extend it with that is not available in Java.
println("Organization ${organization.name} with ${organization.persons.size} persons")
Conclusion
Of course, there are some other differences between Java and Kotlin. This is only my personal list of favorite features that are unavailable in Java. The sample source code with described samples is available on GitHub.
Get the open source Atomist Software Delivery Machine and start automating your delivery right there on your own laptop, today! }}