Переходим с Java на Kotlin: 5 крутых особенностей для Android-разработчиков

Переходим с Java на Kotlin: 5 крутых особенностей для Android-разработчиков

После Google I/O 2017 стало ясно, что Kotlin теперь будет не просто популярным, но и официальным языком разработки на Android. И эта трансформация происходит на наших глазах. Кроме того, Android Studio 3.0 полностью поддерживает Kotlin, и больше нет никаких проблем с совместимостью. Некоторые новые функции Kotlin могут заставить поволноваться Java-разработчиков, решивших перейти на него. Давайте посмотрим на мои любимые.

1. Именованные аргументы

Кошмар каждого Java-разработчика — огромное количество параметров (например, при создании запросов в Cursor или SQLite), их имена и порядок. Без документации вы просто не сможете правильно написать такой код в Java:

@Override
public Loader<Cursor> onCreateLoader(int i, Bundle bundle) {
    return new CursorLoader(this, CONTENT_URI, proj, 
                             null, null, null);
}

К счастью, в Android Studio появилась полезная функция, которая выделяет имена параметров, переданных в такую функцию. Тем не менее, в Kotlin это возможно и без участия IDE:

override fun onCreateLoader(i : Int, b : Bundle): Loader<Cursor> 
     = CursorLoader(sortOrder = null, selectionArgs = null, selection = null, 
                    context = this, uri = CONTENT_URI, projection = proj)

Порядок аргументов абсолютно неважен. Код выглядит намного чище, и теперь сразу видно, что мы передали в метод. Это действительно удобно.

2. Классы данных

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

Java:

public class Person {
    private final String name;
    private final int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }
}

Kotlin ❤ :

data class Person(val name: String, val age: Int)

Что происходит под капотом? Для всех свойств, объявленных в основном конструкторе, компилятор автоматически генерирует:

Эта функциональность помогает избавиться от шаблонного кода, который, как правило, лень поддерживать. В Kotlin компилятор делает это за нас. Теперь вместо повторения одного и того же кода снова и снова, можно сосредоточиться на основной функциональности приложения.

3. Безопасность от null и безопасные вызовы

Я называю это своей ошибкой ценой в миллиард долларов… В то время я разрабатывал первую огромную систему типов для ссылок на объектно-ориентированном языке. Моя цель состояла в том, чтобы гарантировать, что всё использование ссылок должно быть абсолютно безопасным, причём проверка должна выполняться автоматически компилятором. Но я не мог удержаться от соблазна использовать ссылку на null просто потому, что её было очень легко реализовать. Это привело к бесконечным ошибкам, уязвимостям и сбоям системы, которые, вероятно, принесли боли и ущерба на миллиард долларов за последние сорок лет.
— Тони Хоар, изобретатель ALGOL W.

Одна из главных целей Kotlin — избавиться от исключений, вызванных ссылками на null. Здесь по-прежнему доступны типы со значением null, но только для того, чтобы поддерживать совместимость с Java-кодом. По умолчанию типы в Kotlin не могут принимать значение null, и если даже вы попытаетесь использовать null, то ваш код просто не скомпилируется.

var bundle : Bundle = null //won't compile
var bundle : Bundle? = null //nullable type, it compiles

Типичная ситуация в Java:

public void sendMessage(@Nullable Person person, @NotNull Mailer mailer, String message) {
    if (person == null || message == null) return;
    PersonalInfo personalInfo = person.getPersonalInfo();
  
    if (personalInfo == null) return;
    String email = personalInfo.getEmail();
  
    if (email == null) return;
    mailer.sendMessage(email, message);
}

…и та же самая ситуация в Kotlin:

fun sendMessage(person: Person?, mailer: Mailer, message: String?) {
    val email = person?.personalInfo?.email ?: return //Safe calls and Elvis operator
    
    //message is nullable here
    if (message != null) {
        //mailer is not nullable by default, so we don't have to check it
        mailer.sendMessage(email, message)
    }
}

// same function as above, but with use of kolin's `let` block as suggested by one of the readers
fun sendMessage(person: Person?, mailer: Mailer, message: String?) {
    val email = person?.personalInfo?.email ?: return //Safe calls and Elvis operator
    
    message?.let { 
        mailer.sendMessage(email, it) 
    }
}

Такие проверки на null позволяют писать гораздо меньше кода и заставляют разработчиков делать приложение не только работающим, но и хорошо выглядящим. Разве это не потрясающе?

4. Свойства-расширения

Свойства расширения помогают каждый раз, когда нужно удалить кучу повторяющихся приведений типов. Обычно мы писали что-то вроде этого:

var myBigDecimal = 26 as BigDecimal
var otherBigDecimal : BigDecimal = myBigDecimal

Теперь давайте вместо этого используем свойство-расширение:

val Int.bd : BigDecimal                           
     get() = BigDecimal(this)

После того, как мы расширили класс Int, можно легко превратить Int в BigDecimal. Работает он точно так же:

var myBigDecimal = 26.bd
var otherBigDecimal : BigDecimal = myBigDecimal

Мы сделали это, не наследуясь от класса, и не используя никаких паттернов типа Decorator. Kotlin предоставляет возможность быстрого и простого расширения классов новыми функциями.

5. Умные приведения типов

Kotlin довольно приятен в использовании, когда дело касается приведения типов. Давайте посмотрим на этот короткий и простой фрагмент кода:

fun demo(x: Any) {
    if (x is String) {
        print(x.length) // x is automatically cast to String
    }
}

Ключевое слово is идентично instanceof в Java, но оно гораздо мощнее. Компилятор проверяет экземпляр объекта в выражении if, а затем воспринимает его как String в теле блока if. То же самое происходит и в блоках when:

when (x) {
    is Int -> print(x + 1)
    is String -> print(x.length + 1)
    is IntArray -> print(x.sum())
}

Это всего лишь небольшая демонстрация возможностей умных приведений типов. Существуют ещё «небезопасные» приведения, «безопасные» приведения и т.д. Больше информации вы можете найти в документации Kotlin.

Итоги

Я очень доволен возможностями Kotlin. Кроме того, инструменты JetBrains максимально упрощают процесс начала написания кода на Kotlin — автоматический конвертер Java-кода в код на Kotlin, полная совместимость языка с Java и хорошая документация. Android максимально открыт к новому и это не может не радовать!

Перевод статьи «Switching from Java to Kotlin: 5 exciting features for Android Developers»

0 комментариев к статье "Переходим с Java на Kotlin: 5 крутых особенностей для Android-разработчиков"

Добавить комментарий