Recently I decided to start learning Kotlin by converting one of my project’s code from Java to Kotlin (PS — Android Studio proved helpful in doing so). With this, I was able to learn much of Kotlin quickly and also see it in action on one of my already deployed apps on Playstore.
Basic Steps —
- The first thing I did is to add Kotlin support and dependencies to my already existing project. To do so, Google has good documentation available here. Essentially, we will add kotlin gradle plugin in the project-level build.gradle file
ext { kotlin_version = '1.4.32' } classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
And in the app’s build.gradle we will add —
apply plugin: 'kotlin-android' apply plugin: 'kotlin-kapt' implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
If you were already using Room or Hilt libraries in Java, you will have to change the annotation processor dependency to kapt —
//Hilt kapt 'com.google.dagger:hilt-android-compiler:2.35' //Room kapt "androidx.room:room-compiler:$room_version"
2. Now to convert the existing Java file to Kotlin, it can be done in multiple ways —
a. Select the file, click on Code from the Menu bar and select the ‘Convert Java File to Kotlin File’ option to convert the Java file to Kotlin.
b. Right-click on the file and select the ‘Convert Java File to Kotlin File’ option.
c. It will help if you remember the shortcut — ‘Ctrl + Alt + Shift + K’ since we will be converting a lot of files.
Note — Start with converting simple Java classes (Ex — Activity which has ideally no code, Splash screens, Model classes, etc) so it will be easy to convert a few, learn the syntax, and deploy it with Kotlin code included.
Terminologies —
Let’s learn a few basic Kotlin syntax to help understand the code which was converted by the Android Studio for us —
Variables —
- var — Variables defined with var qualifier are Mutable variables. They can be assigned values multiple times. When a value is assigned the first time, it takes that value’s type as the variable’s type. Ex —
var newstitle: String = "News Title"
2. val — Variables defined with val qualifier are Immutable variables. They can be initialized only once and are very similar to Java’s final declared variables.
private val LOGGER = MyApplication::class.java.name
3. lateint — It is used to define variables with non-nullable types indicating that they will be declared later. We will understand the exact use case of it when we understand the various nullable operators below.
lateinit var courseName: String
4. const — It is used to define constant variables. Pretty similar to static in Java. These are also Immutable variables and differ from val as these are known at Compile Time.
const val CONNECT_TIMEOUT: Long = 30000
5. lazy — Another way to declare variables is by using the by lazy { … } block. This will declare the variable when it is called the first time, hence the lazy keyword meaning. It can be used only on val and lateint var.
private val heavyObject: HeavyClass by lazy { HeavyClass() }
Operators —
Kotlin is null-safe and that is probably one of the biggest advantages of it over Java. To use that, we have few operators defined —
- !! operator — This is used to ensure the variable is not null. If it is null, Kotlin throws an NPE for us. Use this when you are sure that the variable’s value should not be null and if it is, it is because of some error
return webViewViewModel!!
2. ? and ?. operator — The ? operator is used to say that the variable can have null values. These are primarily used when we declare the var variables and initialize them to null with a ? The ?. operator can be used in the chain when we try to access value from Network response or model classes where the condition can be like — ObjectA is not null then ObjectA.ObjectB and if ObjectB is not null then ObjectB.ObjectC.
student?.department?.teacher?.name
3. Typecasting —
For typecasting in Kotlin, we will use the as operator. It can be coupled with a nullable operator? — as Type?. If the cast is not valid, it will return null.
val navHostFragment = supportFragmentManager.findFragmentById(R.id.navHost) as NavHostFragment?
Expressions —
One new expression I liked in Kotlin is — when expression. It can be used similarly as the switch from Java but also has the capability to support different types of evaluation, multiple conditions together separated with a comma and also include non-compile time constants which cannot be done using the switch in Java and we end up using If-Else If blocks.
when (teamName) { "CSK" -> return Teams.CSK "MI" -> return Teams.MI }
Methods —
In Kotlin, methods (functions) are defined in a little differen way than Java’s convention ‘modified returnType funName(args…) { … } —
modifier fun funName(args...): returnType { ...}
Ex- private fun getEmojiResourceID(integer: Int?): Int { .... }
‘@JvmStatic’ — Annotation is used to ask the class to define two methods — one static and another which is called from the instance of a class.
Extend & Implement classes —
Kotlin makes it easier to Extend and Implement Classes.
Instead of Java’s extend ClassName, implements ClassName, in Kotlin we have —
Class : Extend(), ImplementA, ImplementB { ... }
Companion Object —
You will notice that your final static variables declared will be put under a block of companion object —
companion object { private val LOGGER = MyApplication::class.java.name operator fun get(activity: Activity): MyApplication { return activity.application as MyApplication } }
All the static methods, variables that can be called without instantiating an object of the class will be present inside this block. The static methods will have operator keywords attached in front.
Object Class —
If the class has only static variables and methods, the class definition will be converted to the object ClassName. These are more like Singleton classes. These classes cannot be instantiated and the variables and methods can be accessed directly using the class name.
object Constants { const val GOOGLE_SIGN_IN = 30 }
Modifier —
Kotlin introduces a new modifier called — ‘internal’. The internal keyword is used to define variables and methods with module access. If our code has multiple modules, the variables and methods will not be exposed beyond the current module.
String Operations —
String operations are made easy in Kotlin. Now if we want to append a variable in a hard-coded string, we can do that like —
val facebookUrl = "https://www.facebook.com/$FACEBOOK_PAGE_ID"
Where FACEBOOK_PAGE_ID is a variable.
We can also use, .plus() or ‘+’ operator outside the double-quotes.
Let —
Let is Kotlin’s scope function which allows us to execute code block within the context of an object.
var upperStr = str.let { it.toUpperCase()}
Open —
In Kotlin, all the classes are final by default and so they cannot be inherited. To make a class inheritable, we need to define the class with the keyword — ‘open’.
Data Class —
Data class is one of the special features of Kotlin. Data classes are for one purpose — To hold data. If we define a class with the ‘data’ keyword, it would automatically generate the getters, setters, hashCode(), equals(), toString(), copy(), and componentN() methods used to destructure the variables from the class.
data class User(val name: String, val age: Int)
Sealed Class —
Sealed classes are used to define restricted class hierarchies and the constructors are private by default. It cannot be instantiated and differs from Enum by allowing us to create instances with different types.
sealed class Expr data class Const(val number: Double) : Expr() data class Sum(val e1: Expr, val e2: Expr) : Expr() object NotANumber : Expr()
Constructors —
The constructors in Kotlin have become much more concise and one-liner. Ex —
class NewsDataSource internal constructor(private val newsRepository: NewsRepository) : PageKeyedDataSource<Int, News>() { ... }
Others —
- We don’t use the function call to access any variable. It is done using the property access syntax. Ex — Instead of authenticationBinding.getRoot(), we use authenticationBinding.root.
- Instead of ‘@Override’ in Java, we directly use — ‘override fun ..’ in Kotlin.
- We do not have the new keyword in Kotlin. Instead, we call the constructor method directly as a normal method call.
- Semi-colons are optional in Kotlin!
- ‘@Nullable’ — annotations used in Java to define null arguments are replaced by using the ‘?’ operator in Kotlin.
- init { … } — init blocks can be used as secondary constructors and there can be more than one init block.
- Android-specific — We now get requireActivity() which can be used in Fragments to get Activity (If not available, it throws ex) and requireView() methods.
Conclusion —
I have been meaning to study Kotlin for a long time and it is well-known fact that if we learn it practically we tend to learn it at a faster pace so this is what I did. I took a recently published application which I wrote in 100% Java and converted it to Kotlin within 3–4 hours. It was a bit overwhelming at the beginning but by the end of 1st hour, I was starting to get the hang of Kotlin’s syntax and understand the code flow as well as understanding the syntax of Kotlin. Kotlin does seem a bit easy and more powerful than Java 8. It helps us write concise code and increases our speed since it generates a lot of boilerplate code for us.
To help understand more on Kotlin and the advanced concepts, do refer to the Kotlin official documentation here.
To expand your knowledge and learn more Kotlin for Android, you can start with learning about Coroutines and Flows which really enhances asynchronous programming to another level.
Useful Links –
- For implementing Retrofit + Hilt + RxJava in Kotlin MVVM Architecture, read the guide here.