Should I use double =, or triple =?
if(a === null)  {
//do something
}
or
if(a == null)  {
//do something
}
Similarly for 'not equals':
if(a !== null)  {
//do something
}
or
if(a != null)  {
//do something
}
Should I use double =, or triple =?
if(a === null)  {
//do something
}
or
if(a == null)  {
//do something
}
Similarly for 'not equals':
if(a !== null)  {
//do something
}
or
if(a != null)  {
//do something
}
 
    
     
    
    A structural equality a == b is translated to
a?.equals(b) ?: (b === null)
Therefore when comparing to null, the structural equality a == null is translated to a referential equality a === null.
According to the docs, there is no point in optimizing your code, so you can use a == null and a != null
Note that if the variable is a mutable property, you won't be able to smart cast it to its non-nullable type inside the if statement (because the value might have been modified by another thread) and you'd have to use the safe call operator with let instead. 
Safe call operator ?.
a?.let {
   // not null do something
   println(it)
   println("not null")
}
You can use it in combination with the Elvis operator.
Elvis operator ?: (I'm guessing because the interrogation mark looks like Elvis' hair)
a ?: println("null")
And if you want to run a block of code
a ?: run {
    println("null")
    println("The King has left the building")
}
Combining the two
a?.let {
   println("not null")
   println("Wop-bop-a-loom-a-boom-bam-boom")
} ?: run {
    println("null")
    println("When things go null, don't go with them")
}
 
    
    Secure Access Operation
val dialog: Dialog? = Dialog()
dialog?.dismiss()  // If the dialog is null, the dismiss call will be omitted
Let function
user?.let {
  // Work with non-null user
  handleNonNullUser(user)
}
Early exit
fun handleUser(user: User?) {
  user ?: return // Exit the function if user is null
  // Now the compiler knows user is non-null
}
Immutable shadows
var user: User? = null
fun handleUser() {
  val user = user ?: return // Return if null, otherwise create immutable shadow
  // Work with a local non-null variable named user
}
Default value
fun getUserName(): String {
 // If our nullable reference is not null, use it, otherwise use non-null value 
 return userName ?: "Anonymous"
}
Use val instead of var
val is read-only, var is mutable. It's recommended to use as many read-only properties as you can, they are thread-safe.
Use lateinit
Sometimes you can't use immutable properties. For example, it happens on Android when some property is initialized in onCreate() call. For these situations, Kotlin has a language feature called lateinit.
private lateinit var mAdapter: RecyclerAdapter<Transaction>
override fun onCreate(savedInstanceState: Bundle?) {
   super.onCreate(savedInstanceState)
   mAdapter = RecyclerAdapter(R.layout.item_transaction)
}
fun updateTransactions() {
   mAdapter.notifyDataSetChanged()
}
 
    
     
    
    Both approaches generate the same bytecode so you can choose whatever you prefer.
 
    
    Addition to @Benito Bertoli,
the combination is actually unlike if-else
"test" ?. let {
    println ( "1. it=$it" )
} ?: let {
    println ( "2. it is null!" )
}
The result is:
1. it=test
But if:
"test" ?. let {
    println ( "1. it=$it" )
    null // finally returns null
} ?: let {
    println ( "2. it is null!" )
}
The result is:
1. it=test
2. it is null!
Also, if use elvis first:
null ?: let {
    println ( "1. it is null!" )
} ?. let {
    println ( "2. it=$it" )
}
The result is:
1. it is null!
2. it=kotlin.Unit
 
    
    Check useful methods out, it could be useful:
/**
 * Performs [R] when [T] is not null. Block [R] will have context of [T]
 */
inline fun <T : Any, R> ifNotNull(input: T?, callback: (T) -> R): R? {
    return input?.let(callback)
}
/**
 * Checking if [T] is not `null` and if its function completes or satisfies to some condition.
 */
inline fun <T: Any> T?.isNotNullAndSatisfies(check: T.() -> Boolean?): Boolean{
    return ifNotNull(this) { it.run(check) } ?: false
}
Below is possible example how to use those functions:
var s: String? = null
// ...
if (s.isNotNullAndSatisfies{ isEmpty() }{
   // do something
}
 
    
    I want to respond to answers of @Benito Bertoli and @BingLi224 and provide imho correct solution.
Problem is with using let, because result of let is it's last expression. You just want to pass the same thing as is passed into it, so also is a better solution. At the same time, after using elvis operator, let is impossible to use, because there is no object to call extension function to so I am using run (functional version). More on that in the scope functions official documentation
Another downside of this compared to using if/when is not being able to use this as an expression so I  wouldn't recommend using it :-)
Final code:
"test"?.also {
    println("1. it=$it")
} ?: run {
    println("2. it is null!")
}
"test"?.also {
    println("1. it=$it")
    null
} ?: run {
    println("2. it is null!")
}
null?.also {
    println("1. it is null!")
} ?: run {
    println("2. it is null")
}
null?.also {
    println("1. it is null!")
    null
} ?: run {
    println("2. it is null")
}
And output:
1. it=test
1. it=test
2. it is null
2. it is null
