This is the part 9 of series Java to Kotlin - Learning Simplified. I hope you are learning something new from every part. I believe last 2 parts were little difficult to grasp but this part is very very easy.

If you have not read part 8, please do here.

Index of this Part: Collection Utilities, Generics, Annotations




Collection Utilities


In Java and Kotlin both, we have similar collections and data structure. The slight difference is Kotlin offers a lot of utility methods and concise syntax to create collections. We do not consider Array under collection or not but for the sake of this topic, I am including Array as well.

The Kotlin utilities are available in the package kotlin.collections Kotlin is offering xxxOf utility method for almost any collection+array you want. To name a few there are arrayOf, listOf, arrayListOf, mapOf, setOf, emptyXXX etc

Interesting part to note is, the default collection objects are immutable unless you specify. It means you can not add the elements later, you need to ask for mutableXXX explicitly if thats what you desire. Few examples are:

	// Kotlin

	val cars = arrayOf("iPace","GLA 100","Mustang","Sirocco")

	for(car in cars) {
		// do your magic
	}

	val cars = listOf("iPace","GLA 100","Mustang","Sirocco")
    for (car in cars){
        println(car)
    }

    val isPresent = "iPace" in cars // πŸ”₯ you can use in with collection

    // same goes to set

Kotlin has a Pair class which it uses inside Map, There are two ways to create a Pair:

	// Kotlin

	val p1 = Pair(1, "Gaurav")

	val p2 = 1 to "Gaurav"

πŸ’‘ Check the syntax in 2nd statement above, We can use X to Y syntax to create a pair. Map is made up of pairs.

	// Kotlin

	val m = mapOf( 1 to "Gaurav", 2 to "Khanna", 3 to "Gaurav Khanna")
	for ((key, value) in m){
        println("Key is $key and value is $value")
    }

    // you can access map element as 

    m.get(key)

    // OR

    m[key]

πŸ”₯ Map elements can also be accessed in array like fashion map[key]

πŸ’‘ In Java the default collections are mutable and we need to create immutable explicitly if required. Kotlin took to opposite approach and in my opinion it makes me think clearly my architecture. There are collection transformation functions like filter, mapsimilar to Java. I suggest you to read official documentation here




Generics


Collections without generics is like politics without scams. They complete each other. The goodpart is Kotlin and Java both have same Generic implementation with slight syntax change. I do not have preference for any but I see people tend to like Kotlin syntax over Java in longer run.

	// a simple hierarchy of Car

	open class Car{}

	open class RaceCar:Car(){}

	class SuperCar:RaceCar(){}

	class CityCar:Car(){}

Let’s see generic in action below:

	// Java
	class Track<T>{}

	Track<Car> carTrack = new Track<Car>(); πŸš—πŸš—
	Track<RaceCar> raceCarTrack = new Track<RaceCar>(); 🏎🏎

	carTrack.add(new Car());      βœ… allowed
	carTrack.add(new RaceCar());  βœ… allowed 
	
	raceCarTrack.add(new RaceCar()); βœ… allowed
	raceCarTrack.add(new Car());     ❌ not allowed

πŸ’‘ raceCarTrack is made up of RaceCar and it can have RaceCar OR any of its subclass as per OOPS IS relation

But

	// Java
	carTrack = raceCarTrack ❌ not allowed

🀯 At first glance it looks odd! Why can’t we assign raceTrack to carTrack Instance. The answer is very simple, carTrack is made of Track<Car> which can accept any Car but raceCar is made of Track<RaceCar> which can accept any RaceCar if the assignment of carTrack = raceCarTrack was allowed, you could do carTrack.add(cityCar) and raceCar Track contains a city car now. Boom!! Not fair and crash! Accident! Bad things!!

	// why not allowed
	carTrack = raceCarTrack;

	// if it was allowed
	carTrack.add(new CityCar()); // allowed because carTrack can accept any car

	❌ Now race track has a city car! Boom! 🏎πŸ’₯πŸš—πŸ’₯🏎

To solve the other problem, Java has a syntax <? extends T> which means T OR any child of T is allowed but only to get from the class, not to add. It is called Covariance, Let’s make the above code work:

	// Java
	Track<? extends Car> carTrack = new Track<>(); 
	Track<RaceCar> raceCarTrack = new Track<RaceCar>();
	carTrack =  raceCarTrack; βœ… allowed with a catch

	// Now if you use T anywhere as input in the Track
	// Java wont allow to call the function 

πŸ‘‰ Java error when you try to send any Car instance in any method of the carTrack : capture not allowed

Kotlin solution for co-variance

	// Kotlin

	class Track<T>{
		var obj:T? = null
		fun add(t:T){}
		fun get():T{
		return obj!!
		}
	}

	var carTrack: Track<Car> = Track()
	var raceCarTrack = Track<RaceCar>()

	carTrack = raceCarTrack  ❌ not allowed , covariance

Kotlin has a different syntax for the same problem. It is out

πŸ’‘ out of Kotlin is equivalent to ? extends T in Java, Here is Kotlin solution:

	// Kotlin, either we can make the instance co-variant OR the class

	// Solution 1
	// now T can only be used as return type and not in the paramters
	class Track<out T>{ 
	fun add(t:T){} ❌ not allowed

	fun get():T{}  βœ… allowed
	}
 

	// Solution 2
	var carTrack: Track<out Car> = Track()	
 //  we can not use Car in the function parameters but only accept

πŸ‘‰ Kotlin error when you try to send any Car instance in any method of the carTrack : out projected type prohibits the use inside

ContraVariance

	// Java
	class Track<T>{}

	Track<Car> carTrack = new Track<Car>(); πŸš—πŸš—
	Track<RaceCar> raceCarTrack = new Track<RaceCar>(); 🏎🏎	

	raceCarTrack = carTrack; ❌ not allowed

If the assignment raceCarTrack = carTrack was allowed, then there is a clear problem. raceCarTrack instace is type Track<RaceCar> and when it will read from the Track, it will expect only RaceCars but carTrack can have other types as well. The software might try to fit race tyres to city car! Boom! Bad things! Lets see solution:

	// Java solution
	Track<Car> carTrack = new Track<Car>();
	Track<? super RaceCar> raceCarTrack = new Track<RaceCar>();

	// Now it will work
	raceCarTrack = carTrack; βœ… allowed with a catch
	// we can add cars in the raceCarTrack
	raceCarTrack.add(new RaceCar()); βœ… allowed
	// but we can not read from raceCarTrack 
	Car xyz = raceCarTrack.get(); ❌ not allowed

In the java solution ? super T, as you are not sure what type you will get at runtime, read is not allowed but only write is allowed.

Kotlin contraVariance solution

πŸ’‘ Kotlin offers same solution with different syntax. The syntax is in T

	// Kotlin
	class Track<in T>{
	fun add(t:T){} βœ… allowed

	fun get():T{}  ❌ not allowed
	}

Kotin in T is same as Java ? super T, which means T is only allowed to write. T is allowed as a parameter in function but not as return type.

πŸ’‘ out means out is allowed (return type) and in means only in is allowed (method parameters) which is easier to read than ? extends and ? super




Enum and Sealed Classes


Enum in kotlin is same as Java with a small syntax change. We need to write enum and class both keywords in Kotlin. Lets see a snippet:

	// Java
	enum States{
		ERROR("Some error while downloading"), LOADING("Downloading the file.."), COMPLETED("Downlaod Completed");
		States(String message) {
		}
	}

	// Kotlin
	enum class States(val message: String) {
		ERROR("Some error while downloading"),
		LOADING("Downloading the file..")
		COMPLETED("Downlaod Completed")
	}

The only difference is class keyword! What happened to concise principle? I have no idea!

πŸ’‘ Have you ever felt need of a state/property in one of the ENUM, lets say in our example LOADING shuld show a message and the load percentage. In Java if we add such property to one enum instance, it has to be added in all. Many developers use a dummy value in other enum instances which overall is a sacrifice and not a good architecture.

πŸ”₯ Presenting Sealed Classes

There are many adjectives this concept has gained. Few say it is enum on steriod, feww say it is enum on swag, few day it is not enum, few say ….! Let people say what they want πŸ”₯ I call it Smart Enum. You are free to call whatever you want. The concept is simple, It is an abstract class which has a limited scope. It can only be extended in the same file and it can be used similar to enums (e.g in When block). Here is an example:

	// Kotlin
	sealed class SealedStates(val message:String) {
    	object ERROR:SealedStates("Some error while downloading")
    	object COMPLETED:SealedStates("Downlaod Completed"),
    	class LOADING(var percentage:Int):SealedStates("")
	}

πŸ’‘ 🀯 πŸ”₯ In the above example, we have a sealed class which we extended 3 times, ERROR and COMPLETED are made singleton on purpose where LOADING can be instantiated with new percentage The only rule is Sealed classes must be declared in the same file. The sublclasses can have states as well. Are not they extension to enums? Sorry, Smart Enums





Annotation as a concept is same in both Java and Kotlin, however there are a very few special annotations which I want to cover here and these are: @JvmStatic, @JvmField, @JvmOverloads, @file:JvmName, and @Throws. Let’s see some code:

@JvmStatic

Remember our Singleton and Companion classes in Kotlin? Singleton has only one instance named INSTANCE and Companion classes are singleton inside any class which is static equivalent in Kotlin classes. But if we access singleton OR companion from the Java code, we need to use following:

	object Single{
		fun doSomething(){}
	}

	class Car{
		companion object{
			fun doSomething(){}		
		}
	}

Access these in Kotlin and Java

	// FROM Kotlin
	Single.doSomething() βœ… allowed even though it is singleton
	Car.doSomething() βœ… allowed even though it is singleton

	// FROM Java
	Single.doSomething() ❌ not allowed
	Single.INSTANCE.doSomething() βœ… allowed

	Car.doSomething() ❌ not allowed
	Car.Companion.doSomething()  βœ… allowed

As we see in Java, we need to use the singleton instance but kotlin has static like structure. If you want to access these static fashion, you need @JvmStatic annotations

	// Kotlin with annotation
	object Single{
		@JvmStatic fun doSomething(){}
	}

	class Car{
		companion object{
			@JvmStatic fun doSomething(){}		
		}
	}	

	// Now Java can call similar to Kotlin
	// From Java
	Single.doSomething()  βœ…
	Car.doSomething()     βœ…

πŸ’‘ @JvmField has exact use case but for fields

@JvmOverloads

If you remember Kotlin has a notion of default value in function parameters. If a function has a parameter with default value, Kotlin allows you not to pass the parameter but if you use same method from Java, Kotlin wants you to pass all the values. By marking it @JvmOverloads, you say to Kotlin to generate overloaded methods for Java and you get variant will default value passed from the overloaded variant.

@file:JvmName

This annotation is very simple. If you have a file name MyFile.kt Kotlin generates a clas for Java named MyFileKt which you can use to access the top level members. If you want to rename the file for Java callers, you can use this annotation on the top of the Kotlin file above package statement. You can say @file:JvmName('MyCustomName') and now Java can call const members with MyCustomName.

@Throws

It is a simple one. Java has a notion of checked exception and unchecked exceptions. If a method is throwing some checked exception then the caller must handle it. But Kotlin does not differentiate between checked and unchecked exception. If you want Java to handle the exception, use @Throws(ExceptionName) in front of the fun definition.


Summary


We started this part with Collection Utilities and saw many offerings from Kotlin. A few popular are arrayOf, listOf, mapOf and setOf. Collections by default are immutable in Kotlin and we have mutableXXX variants for all.

We learned Generics after that and saw Kotlin flavor of Covariance and contraVariance. I feel Kotlin syntax out T and in T is easier than Java alternative ? extends T and ? super T.

Then we saw enum and Smart enum. Enum is same in both Kotlin and Java where Kotlin forces us to use class keyword along with enum. Sealed classes are what I am referring to smart enum Sealed classes are special as they are abstract and their subclasses must be defined in the same file. You can use them as enum + extended enums.

Finally we learned popular annotations in Kotlin which you will need to interact with Java. @JvmStatic, @JvmField, @Throws, @JvmOverloads, @file:JvmName

πŸ”₯ Hope you learned something, This part was easy and impressive Kotlin. Here is part 10

Subscribe to newsletter and keep learning good stuff

Email

πŸ‘‰ If you like article, click on β™₯️ recommend and share on social πŸ‘₯ media.
πŸ‘‰ Feel free to comment πŸ’¬
πŸ‘‰ Follow me πŸ‘€ for the more interesting articles. Twitter Medium
πŸ‘‰ Subscribe to newsletter and keep learning