Kotlin Flashcards
Sealed classes
Sealed classes
Sealed classes - абстрактные классы или интерфейсы, которые похожи на Enums (подклассы известныво время компиляции) но sealed подклассы могут иметь множество экземпляров с разными данными.
Главным преумуществом Sealed классов является использование их в when. Нет нужды в else блоке и благодаря смарт кастом, удобно использовать данные
sealed class Response<out R> class Success<R>(val value: R): Response<R>() class Failure(val error: Throwable): Response<Nothing>() fun handle(response: Response<String>) { val text = when (response) { is Success -> "Success, data are: " + response.value is Failure -> "Error" } print(text) }
аналог Enum. Нужно использовать Enum
~~~
sealed class PaymentOption {
object Cash
object Card
object Transfer
}
~~~
What types of delegation kotlin has? There are 2 types
Class and propery delegation
What is it explicit delegation?
This is delegation using OOP (composition) without any specific feature of the language
~~~
interface View {
fun show()
}
class ViewImpl(): View {
override fun show() {
println(“ViewImpl show”)
}
}
class Screen(private val view: View): View {
override fun show() {
view.show()
}
}
fun main() {
val screen = Screen(ViewImpl()) // establish delegation between two objects
screen.show(); //ViewImpl.show()
}
~~~
What is it implicit delegation?
class automatically delegates method calls to an instance of another class that implements a specific interface. Kotlin has this feature using by word
~~~
interface View {
fun show()
}
class ViewImpl(): View {
override fun show() {
println(“ViewImpl show”)
}
}
class Screen(private val view: View): View by view
fun main() {
val screen = Screen(ViewImpl()) // establish delegation between two objects
screen.show(); //ViewImpl.show()
}
~~~
What is it Delegated Properties?
Sometimes getters and setters use the same code in different classes. To reuse this code Delegated Properties were invented.
~~~
class SimpleDelegate {
operator fun getValue(thisRef: Any, property: KProperty<*>): String {
return thisRef::class.java.name
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) { println("you pass me $value") } }
class Example {
var mutable by SimpleDelegate()
}
~~~
How to create Delegated Property?
It’s possible to write any class that has getValue or setValue method. The best pratic is to implement interfaces ReadOnlyProperty or ReadWriteProperty. You can’t make a mistake implementing these interfaces
Delegation to another property
It’s possible to delegate one property to another by property of the same class, by top-level property or by property of another class
~~~
var topLevelInt: Int = 0
class ClassWithDelegate(val anotherClassInt: Int)
class MyClass(var memberInt: Int, val anotherClassInstance: ClassWithDelegate) {
// проперти самого класса
var delegatedToMember: Int by this::memberInt
// топ-левел проперти
var delegatedToTopLevel: Int by ::topLevelInt
// другой класс
val delegatedToAnotherClass: Int by anotherClassInstance::anotherClassInt
}
var MyClass.extDelegated: Int by ::topLevelInt
~~~
Example
class MyClass {
var newName: Int = 0
@Deprecated(“Use ‘newName’ instead”, ReplaceWith(“newName”))
var oldName: Int by this::newName
}
fun main() {
val myClass = MyClass()
// Notification: ‘oldName: Int’ is deprecated.
// Use ‘newName’ instead
myClass.oldName = 42
println(myClass.newName) // 42
}
How does groupBy work?
Transform collection to Map by some criteria
~~~
// Count the number of users in each city
val usersCount: Map<City, Int> = users
.groupBy { it.city }
.mapValues { (_, users) -> users.size }
~~~
Difference between With and Run in Kotlin
Run and With are interchangeable in some cases. For nullable variable it’s better to use run because you don’t need to check for null inside the block
with(webview.settings) {
this?.javaScriptEnabled = true
this?.databaseEnabled = true
}
// similarly
webview.settings?.run {
javaScriptEnabled = true
databaseEnabled = true
}
run - this is extension while with is lambda with receiver
~~~
public inline fun <T, R> T.run(block: T.() -> R): R = block() // equivalent to this.block()
public inline fun <T, R> with(receiver: T, block: T.() -> R): R = receiver.block()
~~~
What does contentEquals do in Kotlin?
contentEquals function is used to check if two arrays have the same content.
~~~
fun main() {
val array1 = arrayOf(1, 2, 3)
val array2 = arrayOf(1, 2, 3)
val result = array1.contentEquals(array2) println(result) // true // false if array1.equals(array2) } ~~~
Type hierarchy in Kotlin. What is it Any, Unit, Nothing?
Any is the root of the class hierarchy, and all classes inherit from it. Any = Object in Java without finalize, wait and notify methods
Unit = Void in Java. It means that method doesn’t return any value. Unis is a singleton object.
Nothing is the heir of any types. Nothing means that function never completes. For example: throw Exception or TODO
Kotlin has the same type hierarchy for nullable types:
Any? <- Number? <- Nothing?
Secondary constructor in Koltin
Secondary constructor should always call main consturctor
~~~
class SqlQuery(sqlDialect: String) {
val config = SqlConfig()
val dialect = SqlDialect(sqlDialect)
constructor() : this(””) {
config.hasCaching = false
}
}
~~~
this code create main and secondary constructors. Fields are initialized in main constructor
Interfaces in Kotlin
Interfaces can contain both abstract methods and implementations. The difference from abstract classes is that interfaces can’t have state
interface MyInterface { val prop: Int // abstract val propertyWithImplementation: String get() = "foo" fun foo() { print(prop) } } class Child : MyInterface { override val prop: Int = 29 }
Data classes in Kotlin. Restrictions.
data classes are a special type of class that is primarily used to hold data and provide automatic implementations for commonly used methods: toString(), equals(), hashCode(), copy(), componentN()
Data classes restrictions:
- no open
- no abstract
- no inner
- no sealed
You can inherit a data class from another regular class or an interface. The properties of the parent class will not affect the automatically generated methods of the data class, such as toString(), equals(), hashCode(), copy(), componentN() but only if they are not included in the primary constructor of the child data class.
Destructuring declarations in Kotlin
val (name, age) = person data class Person(val name: String, val age: Int) // under the hood data class Person(val name: String, val age: Int) { operator fun component1() : String = name operator fun component2() : String = age }
Function componentN() should be declared with operator. Data classes create componentN function by default. Destructuring declarations are positional-based, not named-based.
Destructuring declarations works in arrays and lists but have limitatation to 5
val array = arrayListOf<Int>(1,2,3,4,5,6)
val (b1, b2, b3, b4, b5) = list
b6 - will not compile</Int>