Kotlin

Имея за плечами опыт с Java, я понял, что синтаксис Kotlin похож на Java, но в то же время может сильно отличаться. Kotlin — очень мощный язык, в котором много синтаксического сахара, что может немного напрягать.

В этой статье мы рассмотрим необходимый минимум, который поможет начать работать с Kotlin. Давайте сразу к делу.

1. Переменные

Чтобы объявить переменную, используйте var.

var username: String = "some user name"

Чтобы объявить константу, используйте val. val в Kotlin — это как final в Java.

val API_DELAY_CONSTANT: Int = 100

Чтобы инициализировать переменную как null, используйте оператор “?”. Если оператор “?” не указан, то компилятор не позволит присвоить переменной значение null.

var myString: String? = null

Используйте companion object для определения статической переменной.

class Animal {

    companion object {
        const val DEFAULT_NUM_OF_EYES = 2
    }
}

animal.numOfEyes = Animal.DEFAULT_NUM_OF_EYES

Используйте lateInit для отложенной инициализации переменной.

lateinit var user: User                 // Initialized later in code
lateinit var items: List<String>   // Initialized later in code

2. Функции

Простая функция в Kotlin выглядит следующим образом:

fun getNumber(): Int {
    return 1
}

Здесь функция getNumber() имеет область видимости public, не имеет параметров и возвращает Int.

Попробуем создать private функцию с несколькими параметрами.

private fun getStringLength(str1: String, str2: String): Int {
    return str1.length + str2.length
}

Функция getStringLength() имеет область видимости private и два параметра, возвращает Int.

Как насчёт статической функции?

class MyStringUtil {
    
    companion object {
        fun getOddLengthString(str: String): String? {
            if (str.length % 2 == 0) return null

            return str
        }
    }
}
var str: String = MyStringUtil.getOddLengthString("hey")

getOddLengthString() — статическая функция, которая принимает параметр и возвращает строку. Тип String указан с символом “?”. Это означает, что функция может возвращать значение NULL.

3. Циклы for, while, when

В цикле for, в Kotlin, используется ключевое слово “in” для доступа к элементам коллекции.

var items: List<String> = ArrayList<String>()

for (item in items) {
    // do something with item
}

Можно также получить доступ к индексам элементов в цикле for.

for (index in items.indices) {
    // access items using index
    // items.get(index)
}

Цикл while в Kotlin такой же, как и в Java. Тут ничего нового 🙂

var i: Int = 0
// Some while loop
do {
    // do something
    i++
} while (i < 5)
// Another while loop
while (i < 10) {
    // do something
    i++
}

А вот оператор switch в Java был создан проще. Kotlin использует ключ слово when для переключения между условиями, и это гораздо более мощный и краткий способ.

// A cool example of when statement
fun describe(obj: Any): String? {
    var res: String? = null

    when (obj) {
        1 -> { res = "One" }         // if obj == 1
        "Hello" -> res ="Greeting"  // if obj == "Hello"
        is Long -> "Long"            // if obj is of type Long
        !is String -> "Not string"   // if obj is not of type String
        else -> {
            // execute this block of code
        }
    }
    
    return res
}

4. Null Safety (Null безопасность)

 

В Java, чтобы избежать исключения NullPointerException, мы можем использовать блок “if”. Например:

if (person != null && person.department != null) {
    person.department.head = managersPool.getManager()
}

Но в Kotlin мы можем пропустить блок “if” и переписать наш код следующим образом:

// If either `person` or `person.department` is null, the function is not called:
person?.department?.head = managersPool.getManager()

“?.”известен как оператор безопасного вызова, и приведённый выше пример показывает, что его можно использовать в цепочках. Это помогает нам писать чистый, простой код и в то же время избегать NPE.

В случае, если вы хотите обработать сценарий, где объект равен null, вы можете использовать “?:”. Этот оператор, называют — Elvis operator.

var name = person?.name ?: throw InvalidDataException("Person cannot be null.")

5. Классы (конструкторы, методы, наследования)

Ключевое слово “open” указывает, что класс может быть унаследован. Класс, который не является “open”, такой же, как класс final в Java. Простой пример класса в Kotlin выглядит так:

open class Animal {
    // This class is open and
    // can be inherited    
}

class Dog : Animal() {  // Notice the paranthesis
    // Class dog is final and
    // can't be inherited
}
// Compiler throws error
class Labrador : Dog {

}

Ниже приведён более сложный пример класса и наследования в Kotlin:

open class Animal {  // Parent class
    var name: String? = null  // Nullable variable
    var legs: Int = 0         // Non-nullable variable
    lateinit var map: HashMap<Integer, String>  // Variable inited later in the code

    constructor(legs: Int) {
        this.legs = legs
    }

    constructor(legs: Int, name: String) {
        this.legs = legs
        this.name = name
    }

    // open keyword allows the function to be overridden
    open fun speak() : String? {
        return null
    }
}

class Dog : Animal { // Child class
    constructor(legs: Int) : super(legs) {
        // Optional code block
    }
    
    // Just a super call, without additional code block
    constructor(legs: Int, name: String) : super(legs, name)

    // Function over-ridding
    override fun speak(): String? {
        return "Bark! Bark!"
    }
}

Обратите внимание, что в наших классах нет методов getter и setter. Вместо этого мы обращаемся к свойствам объекта следующим образом:

Экземпляр собаки
var dog: Dog = Dog(0)
// Setters
dog.numOfLegs = 4
dog.name = "Labrador"
// Getter
println(dog.name)

6. Singleton (синглтоны)

Синглтоны в Kotlin реализуются с помощью ключевого слова “object”. Имея опыт с Java, использование “object” вместо “class”, кажется немного странным. Подробнее об этом можно прочитать в официальных документах Kotlin:

object Singleton {
    var name: String = "singleton object"

    fun printName() {
        println(name)
    }
}
// later in the code
Singleton.name
Singleton.printName()

7. Интерфейсы

Базовый интерфейс в Kotlin выглядит следующим образом:

interface Named {
    fun bar()
}

interface Person : Named { // Person inherits Named
    fun foo()
}

class Employee() : Person {
    override fun bar() {
        // do something
    }

    override fun foo() {
        // do something
    }
}

Наследование интерфейса довольно просто. Но передача интерфейса функции немного отличается. Посмотрите на этот пример:

// A function that accepts and interface as a parameter
private fun setEventListener(listener: EventListener) {
    // do something
}
// Passing an interface to the function
setEventListener(object : EventListener{
    override fun call() {
        // do something
    }
})

8. Type Casts (приведение типов)

Чтобы проверить, является ли объект экземпляром определённого класса, мы используем операторы “is” и “!is”.

if (obj is String) {
    print(obj.length)
}

if (obj !is String) {
    print("Not a String")
}

Чтобы предотвратить выбрасывание исключений, можно использовать оператор безопасного приведения “as?”, который возвращает null при сбое. Это называется safe typecast в Kotlin.

val x: String? = y as? String

В этом случае при сбое приведения типов, возвращается значение null, что предотвращает выбрасывание исключений.

9. Обработка исключений

Выбрасывание и обработка исключений практически такие же, как и в Java.

throw Exception("Hi There!")
try {
    // some code
}
catch (e: SomeException) {
    // handler
}
finally {
    // optional finally block
}

 

Перевод статьи: Mayur Rokade Learn Kotlin for Android in One Day