Are you one of those who want to try Kotlin but are not sure whether jump in and try?
This post should help you make your decision — to go all in or if you want to experiment with it first.
- Kotlin is a concise language that can drastically reduce boilerplate code when done correctly.
- It focuses on type and null safety while maintaining readability.
- Kotlin focuses on being lightweight and totally interoperable with Java making it perfect for Android application development
- Kotlin 1.1 support from Java 1.6 — Most of the legacy Android or Backend Project are supported.
So what do the developers say :
- “It’s really incredible how much we can pare down without sacrificing readability” — Christina Lee, Pintrest (https://youtu.be/xRDqDe4rxkM)
- “A data point (for Android devs who are Kotlin-curious): @trello is happily using @kotlin in production nowadays” — Dan Lew, Trello (https://twitter.com/danlew42/status/809065097339564032)
- “Kotlin makes writing math code almost as nice as C++. Properties and operator overloading offers many possibilities for swizzling & slicing” — Romain Guy, Google (https://twitter.com/romainguy/status/812454073232453632)
- “Today with IntelliJ’s help I upgraded Rounds from Java to Kotlin. It took 12 hours to go from 5395 lines of .java to 4924 lines of .kt” — Jesse Wilson, Square (https://twitter.com/jessewilson/status/803122976321400834)
Let’s get started
Few things that help you get started easily
Naming
Java:
private String mSomeString = “Hello world”
Kotlin :
private val someString : String = “Hello world”
val name: String //Final (cant change types)var count: Int //Mutable variable
Use camelcase for naming your variables.
val myVal //kotlinmyClass.getMyVal() //java
The data type is inferred
val a: Int = 100 // Int is redundantval a = 100 // Int is inferredval b: Int// Do somethingb = getResultAsInt()
Void
is a plain Java class and has no meaning in Kotlin.
Unit
→ replaces java'svoid
Nothing
→'a value that never exists'
Methods / functions in kotlin
fun doSomething()
Class naming convention :
Write a property in its own line
class Person(
public open var firstName: String,
public open var lastName: String,
public open var age:Int
) {}//Subclass - do thisclass Person(
public open var firstName: String,
public open var lastName: String,
public open var age:Int
) : RealmObject() {}
No need of writing getters and setters
class MyClass {
public var myString: String = ""
}//You can call
myClassInstance.myString = "Hello"
Log.d("TAG","Value is ${myClassInstance.myString}) //prints Hello
Neat feature : Print variables using string interpolation
$object or ${object.property}
switch() → when(condition)
return when(object) {
is String -> object + "test"
is Number -> String.valueOf(object)
else -> null
}
Nullability — As a rule of thumb, !!
should never be used and ?
should be used rarely. Theses checks can often be avoided and doing so will provide for a more stable code-base. Whenever possible, objects and properties should be made to be not nullable.
Extensions functions / Utility functions
It lets us to add functions to existing classes and by doing so reducing a lot of boiler plate code ,without having to touch the source code of such classes.
- Extend an entire class
- Use added util function
Such functions can be written as you would normally would, and put the name of the class before separated by a point. These functions can be everywhere, usually in an Extensions
file which doesn’t even need to contain a class
Example :
class MyClass {
fun doThisAndReturnModified(value:Int) {
return value*2
}
}
Now i need to get the result in a different format but using the above , the method it has cant be modified for new requirement , and let’s say we don’t want to change the entire class by adding a new set of function , we could
MyClass.doThatAndReturnModified(value:Int) {
return value+2
}
Your original class wont be tampered , we just added a new functionality without modifying it
Kotlin Android Extensions
Kotlin Android Extensions is another Kotlin plugin that is included in the regular one, and that will allow to recover views from Activities, Fragments ,Views in an amazing seamless way.
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_main.*class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)//tvTitle is a TextView in layout activity_main
tvTitle.text = "Hello Kotlin!!"}
}//magic comes from this import
//import kotlinx.android.synthetic.main.activity_main.*
Some nifty examples :
Some learnings on the way :
int → Int
public static final String HOLA ="hola"
converts to
val HOLA: String ="hola" // Kotlin does not know what static is //Betterclass SomeClass {
companion object{
const val HOLA = "hola"
}
//...
}
Lazy initialisation
val person by lazy {
SomeUtil(parameter1, parameter2)
}
this helps to initialise certain code only once upon the first usage of person Object.
Then , there is
lateinit var myCustomIntentObj: CustomObject // wont crash
...onCreate(...){
myCustomIntentObj = intent.getExtras().get("key") // this init
}
This greatly helps in Dependency injected variables , ex :
@Inject
lateinit var presenter: MyPresenter
When to use lateinit
- If you’re variable is mutable
- If you’re sending a object from another component/ screen — ex Intent extras
Kotlin classes can be declared as sealed
— to avoid subclassing
// with the sealed keyword, we cannot create subclasses for MyClass
sealed class MyClass {
// ...
}
constructor
signifies the declaration of the primary or secondary constructor with params
Note : The primary constructor cannot contain any code. Initialization code can be placed in initializer blocks, which are prefixed with the init keyword:
// (name: String, surname: String) default constructor signature
class Person(name: String, surname: String?) {
// init block , represents the body of default constructor
init {
Log.d("primary", "Hello");
}
// secondary constructor
// this(name,"") call to default constructor
constructor(name : String):this(name,null){
this.myname = name }
}
init
helps introduce an initializer block for the class that may contain code to execute when class is created.
Data classes
Almost all android apps , we build have some sort of POJO or data classes with accessors methods , we override toString() , hashcode(), and more
Kotlin helps reduce boilerplate
public class User {
private String name;
private int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public String component1() {
return name;
}
public int component2() {
return age;
}
public User copy() {
return new User(name, age);
}
public User copy(String newName) {
return new User(newName, age);
}
public User copy(String newName, int newAge) {
return new User(newName, newAge);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
if (age != user.age) return false;
return name != null ? name.equals(user.name) : user.name == null;
}
@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + age;
return result;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
into :
data class User(val name: String, val age: Int)
Data classes simply help avoid writing boilerplate code for a lot of those big Java bean classes / POJO , kotlin’s data classes provide compiler generated equals , hashcode , toString and more
Java Singleton → Kotlin object
object Payment{
val transactions = arrayListOf<Checkouts>()
fun calculateSalary() {
for (trans in transactions) {
... }
}
}
Kotlin does not have
static
Kotlin recommends using top-level functions instead.
public class MyFragment extends Fragment { public static MyFragment newInstance(int a, String b){
Fragment frag = new MyFragment()
Bundle args = new Bundle()
args.putExtra(...)
}....
}
Kotlin way —
class MyFragment : Fragment() {
companion object {
/**
* new instance pattern for fragment
*/
@JvmStatic
fun newInstance(a:Int, b:String): MyFragment {
val fragment = ActivitiesMainFragment()
val args = Bundle()
args.putInt("key1",a)
args.putString("key2",b)
fragment.arguments = args
return fragment
}
}...
}
Looping
val myList :ArrayList<Item> = ArrayList()
myList.add()
//...for(item in myList) {
//item is one Item
item.doStuff()
}
Conclusion
Using the conversion tool in Android Studio will be a great start. However, exploring the language slowly and carefully will result in better code.
Migrating you existing codebase to Kotlin will be fun and difficult at some times , but my advice give the language a try.
Check my slides on introduction to Kotlin —