Kotlin Best Practices

Kotlin, created just 5 years ago, has been considered the priority programming language for Android since 2019. And yet this language is young enough and continues to evolve, so sometimes it is not clear how best to write the code. We often have discussions in our team on the topic of pure Kotlin code, and on their basis we have compiled our best practices. We would like to share these recommendations and look forward to your questions.





Well, let's get started! First of all, there is a lot of syntactic sugar in Kotlin, and if it is overused it becomes difficult to read such code. The next few points can be attributed to the struggle between brevity and readability





Don't write a class declaration in one line

– . .





class ChannelViewModel(
       val conversationId: String,
       getChannelUseCase: GetChannelUseCase,
) : ViewModel() {
      
      



, :





  • , ( Android Studio / Shift+Command+Up/Down)





  • .





return

:





data class MyClass(val number: Int, val flag: Boolean)

fun create(numberParam: Int?, flag: Boolean?): MyClass? {
   return MyClass(numberParam ?: return null, flag == true)
}
      
      



return, , . , numberParam null,  return MyClass(...) return null. if, :





fun create(numberParam: Int?, flag: Boolean?): MyClass? {
   if (numberParam == null) {
       return null
   }
   return MyClass(numberParam, flag == true)
}
      
      



it

, it , - :





values?.filterNot { selectedValues?.contains(it) == true }
   ?.let {
       selectedValues?.addAll(it)
       result[key]?.values = selectedValues?.filter { it.isChecked }
   }
      
      



let:





values?.filterNot { allSelectedValues?.contains(it) == true }
   ?.let { newValues ->
       allSelectedValues?.addAll(newValues)
       result[key]?.values = allSelectedValues?.filter { it.isChecked }
   }
      
      



it – . -null, . :





val newValues = values.filterNot { selectedValues.contains(it) }
selectedValues.addAll(newValues)
result[key]?.values = selectedValues.filter { it.isChecked }
      
      



?. -null

:






private var animatedView: FrameLayout? = null
...
animatedView?.animate()?.alpha(1f)?.setDuration(500)?.interpolator = AccelerateInterpolator()
      
      



null , animatedView null. if (animatedView != null) . ,   animatedView null. lateinit , null:





private lateinit var animatedView: FrameLayout
...
animatedView.animate().alpha(1f).setDuration(500).interpolator = AccelerateInterpolator()
      
      



Java Kotlin, “ ”. . Java - if when, (let, apply, also, with, run), , Utils extension .





!!

!! , NullPointerException, !! “”. 





!! : 





  • -null ( lateinit animatedView)





  • let ?.let { … }





  • - ?:





  • , , , null, checkNotNull requireNotNull. : IllegalStateException IllegalArgumentException . 





, !! Java Kotlin, @NonNull Java-.





when if

:





val price = if (priceData.isWeightPrice) {
   priceData.minDiscountPrice.toInt()
} else if (priceData.discountPrice != 0.0) {
   priceData.discountPrice.toInt()
} else {
   priceData.price.toInt()
}
      
      



when:





val price = when {
   priceData.isWeightPrice -> priceData.minDiscountPrice.toInt()
   priceData.discountPrice != 0.0 -> priceData.discountPrice.toInt()
   else -> priceData.price.toInt()
}
      
      



when , , . 





when , . , when .





Util

- , extension. . 





, . , , .





, Util Kotlin ( : Java , Kotlin – ). - , (package) . (extension , , ; , - ). , , , .





, ( “ ”). , .





(trailing commas) 

1.4. ( ) : diff . 





Single Abstract Method interface (Fun interface)

Kotlin 1.4.0. , fun :





this.actionClickListener = object : BubbleView.ClickListener {
   override fun onBubbleViewClick() {
           ...
       }
   }
      
      







 this.actionClickListener = BubbleView.ClickListener {
      ...
  }
      
      



 fun:





fun interface ClickListener {
   fun onBubbleViewClick()
}
      
      



, Java, Kotlin , SAM- . :





  • (T) -> R;





  • , SAM-;





  • , . 





Kotlin , , , . , , , . , /





?





val itemIdsSet: Set<String> = ...
val currentItemIds: Set<String> = ...
for(itemId in itemIdsSet) {
   if(!currentItemIds.contains(itemId)) {
       repository.exclude(itemId)
   }
}
      
      



:





val itemIdsSet: Set<String> = ...
val currentItemIds: Set<String> = ...
for (itemId in itemIdsSet subtract currentItemIds) {
   repository.exclude(itemId)
}
      
      



API , exclude , :





repository.exclude(itemIdsSet subtract currentItemIds)  
      
      



code style

, “”. : 





  • (, _ enum )









  • companion object ( ) .. 





, . , best practices.





, Kotlin- :





https://developer.android.com/kotlin/style-guide https://proandroiddev.com/an-opinionated-guide-on-how-to-make-your-kotlin-code-fun-to-read-and-joy-to-work-with-caa3a4036f9e 

https://developer.android.com/kotlin/coroutines/coroutines-best-practices








All Articles