Kotlin Developer
6.23K subscribers
257 photos
8 videos
352 links
Самый топовый канал по Kotlin

По вопросам сотрудничества и рекламы: @NadikaKir

Мы на бирже: https://telega.in/c/KotlinSenior
Download Telegram
Строим мосты: подключение зависимостей с Cocoapods в Kotlin Multiplatform Mobile

При создании КММ проекта Android Studio предоставляет разработчику выбор между использованием Regular Framework и Cocoapods Dependency Manager для добавления iOS-специфических библиотек, который может быть крайне неочевидным на первый взгляд, ведь использование Regular Framework кажется затруднительным и не пользуется популярностью в отличие от удобного Cocoapods. В данной статье мы рассмотрим, как интегрировать Cocoapods в разработку, создав небольшое Android приложение.

Читать статью
Какая польза от typealias? Во что он компилируется?

Typealias — это механизм создания синонимов (псевдонимов) для существующих типов. То есть, можно создать новое имя для уже существующего типа данных.

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

typealias NodeSet = Set<Network.Node>
typealias FileTable<K> = MutableMap<K, MutableList<File>>

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

К примеру, если в проекте используется много Map<String, String> и вместо этого вы хотите использовать более описательное название, например Properties, вы можете определить новый тип для Map<String, String> с помощью следующего кода:

typealias Properties = Map<String, String>

Теперь вместо использования Map<String, String> можно использовать Properties для обозначения одного и того же типа данных. Таким образом, код становится более читаемым и понятным.

Во что компилируется
typealias?

Typealias не создает новый тип данных, а только создает псевдоним для существующего типа. При компиляции кода, все typealias заменяются на соответствующий тип, поэтому typealias не приводит к увеличению размера кода.

Например, typealias IntPredicate = (Int) -> Boolean при компиляции будет заменено на (Int) -> Boolean, то есть функцию, принимающую значение типа Int и возвращающую значение типа Boolean.

Можно ли использовать
typealias для функциональных типов?

Да, можно использовать typealias для функциональных типов в Kotlin. Например, вы можете создать псевдоним для типа функции, которая принимает два параметра типа Int и возвращает значение типа String, следующим образом:

typealias IntToString = (Int, Int) -> String

Это позволит вам использовать созданный псевдоним вместо полного объявления типа, то есть вместо:

fun processValues(f: (Int, Int) -> String) {
// ...
}

можно использовать:

fun processValues(f: IntToString) {
// ...
}

Как и в случае с другими typealias, компилятор Kotlin просто заменяет псевдоним на соответствующий тип при компиляции кода.
Что такое функции высшего порядка (higher-order functions), лямбда-выражения (lambda-expressions), анонимные функции (anonymous functions), указатели на методы (method references, bound callable references)?

Функции высшего порядка - это функции, которые принимают функцию в качестве аргумента и/или возвращает функцию в качестве результата

Лямбда выражения - не объявленная функция, которая немедленно используется в качестве выражения

Анонимные функции - альтернативный синтаксис лямбда выражения с иными правилами для выражения return(можно использовать для создания блока кода с несколькими точками выхода )

Указатели на методы - упрощенный синтаксис создания значения функции, вызывающего ровно один метод или обращающегося к свойству.
{p:Person --> p.age} ==Person::age
Какой толк от inline-функций, как компилируется сама функция и места её использования?

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

Когда функция объявляется с модификатором inline, её тело становится встраиваемым, т.е. оно подставляется вместо обычного вызова функции.

Если отметить функцию модификатором inline, компилятор не будет генерировать вызов функции в месте её использования, а просто вставит код её реализации.
Alfa Backend Stories Meetup #2 🔥

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

🔺 Александр Карташов, Senior Java Developer, расскажет про технологии межсервисного взаимодействия на примере проектов Альфа-Банка.

🔺 Василий Рыбин, Java Developer, познакомит с архитектурным паттерном API Gateway.

🔺 Павел Агалецкий, Lead Engineer в Авито, рассмотрит механики валидации контрактов внутренних API и протокол межсервисного взаимодействия в Авито.

🔺 Екатерина Попкова, Java/Kotlin Developer, расскажет, что такое Сага и как его можно реализовать на Camunda Platform 8.

✔️ Зарегистрироваться на митап и узнать больше о программе
Можно ли сделать extension к интерфейсу? Тайпалиасу? Функциональному типу?

Интерфейс - да
Псевдонимы типов - да
функциональный тип - нет(там есть Литералы функций с объектом-приёмником)
companion/object - да
Как адаптировать Android-приложение под Huawei

Всем привет! Меня зовут Миша Вассер, я Head of Android в AGIMA. Мы занимаемся разработкой Digital-продуктов для больших и маленьких компаний, в том числе пилим мобильные приложения.

Не так давно — по сравнению со всей историей Android — Huawei выкатил собственную операционную систему и сказал: «Ребята, вот вам новая система, кайфуйте». Многие отнеслись к новой ОС скептически. Остальным пришлось адаптировать под нее свои Android-приложения.

Мы оказались во второй группе. К нам время от времени обращаются с просьбой помочь с адаптацией под Huawei. И мы неплохо в этом вопросе прокачались. Поэтому сейчас расскажу, что надо сделать, чтобы стало хорошо. А покажу всё это на примере крупного ретейлера, с которым мы работаем.

Читать статью
Во что компилируется typealias?

Typealias не создает новый тип данных, а только создает псевдоним для существующего типа. При компиляции кода, все typealias заменяются на соответствующий тип, поэтому typealias не приводит к увеличению размера кода.

Например, typealias IntPredicate = (Int) -> Boolean при компиляции будет заменено на (Int) -> Boolean, то есть функцию, принимающую значение типа Int и возвращающую значение типа Boolean.

Можно ли использовать typealias для функциональных типов?

Да, можно использовать typealias для функциональных типов в Kotlin. Например, вы можете создать псевдоним для типа функции, которая принимает два параметра типа Int и возвращает значение типа String, следующим образом:

typealias IntToString = (Int, Int) -> String

Это позволит вам использовать созданный псевдоним вместо полного объявления типа, то есть вместо:

fun processValues(f: (Int, Int) -> String) {
// ...
}

можно использовать:

fun processValues(f: IntToString) {
// ...
}

Как и в случае с другими typealias, компилятор Kotlin просто заменяет псевдоним на соответствующий тип при компиляции кода.
Какие коллекции есть в Kotlin?

Коллекция
— это объект, содержащий в себе набор значений одного или различных типов, а также позволяющий к этим значениям обращаться и извлекать. Другими словами — это контейнер, в который вы можете помещать то, что вам нужно, а затем каким-либо образом с ним взаимодействовать. В Kotlin есть три типа коллекций:

List (список). Упорядоченная коллекция, в которой к элементам можно обращаться по их индексам. Идентичные элементы (дубликаты) могут встречаться в списке более одного раза. Примером списка является предложение: это группа слов, их порядок важен, и они могут повторяться.

Set (множество/набор). Неупорядоченная коллекция без повторяющихся значений. Примером множества является алфавит.

Map (словарь/ассоциативный список). Набор из пар "ключ-значение". Ключи уникальны и каждый из них соответствует ровно одному значению. В коллекции могут присутствовать повторяющиеся значения, но не повторяющиеся ключи. Пример — ID сотрудников и их должностей. Map не является наследником интерфейса Collection.

Два типа интерфейсов, на основе которых создаются коллекции:

1. Неизменяемый (read-only) — дают доступ только для чтения (Set, List, Map, Collection).

2. Изменяемый (mutable) — расширяет предыдущий интерфейс и дополнительно даёт доступ к операциям добавления, удаления и обновления элементов коллекции (
MutableSet, MutableList, MutableMap, MutableCollection).
Давно в IT и хотите сменить профиль? Стремитесь попробовать что-то новое? Испытайте себя в роли Java-разработчика на практике! Популярность языка Java растёт, востребованность разработчиков — тоже. А возрастных ограничений для специалистов нет.

Бесплатный онлайн интенсив пройдёт с 31 июля по 2 августа в 19:00 по московскому времени.

Регистрация: 👉https://epic.st/sd-oR-

Сразу после регистрации пришлём гайд по профессии Java-разработчика 😉

За 3 вечера вы узнаете, в чем различия Python и Java, какие навыки нужны для трудоустройства Java-разработчику, и попробуете написать Telegram-бота на Java. В него будет «зашит» тест по Java от реального работодателя, но вы сможете модифицировать его и реализовать собственную логику.

🔝Знаниями поделится Даниил Пилипенко — основатель и директор центра подбора IT-специалистов SymbioWay.

🎁 Тем, кто будет онлайн, подарим сертификаты на скидку 10 000 рублей для обучения на образовательной платформе Skillbox. А всем, кто дойдёт до конца интенсива, — электронную книгу издательства МИФ.

Реклама. ЧОУ ДПО «Образовательные технологии «Скилбокс (Коробка навыков)», ИНН: 9704088880
Все, что вам нужно знать о Kotlin Multiplatform

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

Читать статью
List

Список — это упорядоченная коллекция. Каждое значение, помещённое в List, называется элементом, к которому можно обращаться по индексу. Индексы начинаются с "0" и заканчиваются индексом последнего элемента в списке — (list.size - 1). Список может содержать сколько угодно одинаковых элементов — дублей (в том числе null).

val trees = listOf("Сосна", "Берёза", "Дуб") // неизменяемый список
trees.add("Ясень") // ошибка

val mutableTrees = mutableListOf("Сосна", "Берёза", "Дуб") // изменяемый список
mutableTrees.add("Ясень") // всё ок

По умолчанию в Kotlin реализацией List является ArrayList, его можно создать напрямую:

val mutableTrees = ArrayList<String>()
mutableTrees.add("Ясень")
Set

Множество — это коллекция уникальных элементов.
Это означает, что Set не может содержать дублей. Обратите внимание, что null — это тоже уникальный элемент.

val trees = setOf("Сосна", "Берёза", "Дуб") // неизменяемый сет
trees.add("Ясень") // ошибка

val mutableTrees = mutableSetOf("Сосна", "Берёза", "Дуб") // изменяемый сет
mutableTrees.add("Сосна") // проигнорируется

В отличие от списка, множество не заботится о порядке элементов. Это означает, что при использовании функций, зависящих от порядка элементов, вы можете получить непредсказуемый результат. Но это зависит от реализации сета. Например, по умолчанию реализацией Set является LinkedHashSet, который сохраняет порядок вставки элементов.

val numbers = setOf(1, 2, 3, 4)  // по умолчанию LinkedHashSet
val numbersBackwards = setOf(4, 3, 2, 1)

println(numbers.first() == numbersBackwards.first()) // false
println(numbers.first() == numbersBackwards.last()) // true

Но также существует HashSet, который не сохраняет порядок вставки элементов. И LinkedHashSet, и HashSet можно создать напрямую.

val linkedHashSet = LinkedHashSet<String>()
linkedHashSet.add("Дуб")

val hashSet = HashSet<String>()
hashSet.add("Ясень")
Курс «Английский для разработчиков» Яндекс Практикума

Для тех, кто хочет изменить свою профессиональную жизнь и работать в международной команде.

Обучение построено не вокруг абстрактной теории, а вокруг рабочих ситуаций и полезных для карьеры навыков:

Стендапы. Подготовитесь обсуждать задачи, задавать вопросы и просить о помощи.
👨‍💻 Работа с заказчиками. Научитесь презентовать решения, говорить про баги и фичи.
📣 Митапы. Сможете понимать на слух доклады и выступать сами.
😎 Собеседования. Научитесь рассказывать про свой опыт, понимать вопросы и тактично переспрашивать.
👯 Неформальное общение с коллегами. Сможете рассказать о своих интересах, опыте, планах на будущее.
💻 Код-ревью. Сможете описать сделанное, дать обратную связь, тактично отстоять своё мнение.

Запишитесь на бесплатную консультацию. Кураторы определят ваш уровень языка и расскажут подробнее про обучение.
Map

Ассоциативные списки с уникальными ключами и любыми значениями (дубликаты ключей не допускаются, значения могут быть одинаковыми). Связь между ключами и значениями происходит через специальную форму вызова метода (инфиксный вызов) to.

// числа - это ключи, деревья - значения
val map = mapOf(1 to "Сосна", 2 to "Берёза", 3 to "Дуб") // неизменяемая мапа
map.put(4, "Ясень") // ошибка

val mutableMap = mutableMapOf(1 to "Сосна", 2 to "Берёза", 3 to "Дуб") // изменяемая мапа
mutableMap.put(4, "Ясень")

По умолчанию реализацией мапы является LinkedHashMap, который сохраняет порядок вставки записей. Есть ещё HashMap, которая не сохраняет порядок вставки записей. Обе реализации можно создать напрямую.

val linkedHashMap = LinkedHashMap<Int, String>()
linkedHashMap.put(1, "Дуб")

val hashMap = HashMap<Int, String>()
hashMap.put(1, "Ясень")
Промежуточные (intermediate) и терминальные (terminal) операции в Sequences

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

Операции над Sequence можно разделить на две категории: промежуточные (intermediate) и терминальные (terminal).

Промежуточные операции (intermediate) — это операции, которые возвращают новую Sequence.

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

filter(predicate: (T) -> Boolean): фильтрует элементы по заданному условию и возвращает новую Sequence

map(transform: (T) -> R): преобразует каждый элемент в новый элемент типа R и возвращает новую Sequence

sortedBy(selector: (T) -> R?): сортирует элементы по заданному ключу и возвращает новую Sequence

Терминальные операции (terminal) — это операции, которые выполняются немедленно и возвращают результат (не Sequence).

Терминальные операции могут быть вызваны только после всех промежуточных операций, так как они завершают последовательность и начинают вычисление результатов на основе всей последовательности, полученной после выполнения всех промежуточных операций. Если же терминальная операция вызывается до выполнения всех промежуточных операций, то она не будет иметь доступа к полной последовательности и вернет неполный результат. Примеры:

toList(): преобразует Sequence в список

toSet(): преобразует Sequence в множество

count(): возвращает количество элементов в Sequence

forEach(action: (T) -> Unit): выполняет действие для каждого элемента Sequence

ВАЖНО: вычисления запускаются только при вызове терминальной функции (до этого момента никаких вычислений не производится).
Kotlin: взгляд изнутри — преимущества, недостатки и особенности

Всем привет! На связи Сергей Керенцев, Android-разработчик Студии Олега Чулакова на проектах Сбера.

В данной статье мы углубимся в мир Kotlin, рассмотрим его основные преимущества, недостатки и особенности. Мы обойдем такие важные аспекты, как безопасность работы с null-значениями, гибкость типизации с помощью Generics, возможности расширения функциональности с помощью extension-функций, inline-функции, а также многое другое.

Давайте начнем наше увлекательное путешествие в мир Kotlin и раскроем его потенциал!

Читать статью
Extensions (расширения) — что это и для чего нужны?

Это функции, которые позволяют добавить функционал к уже определенным типам.

Kotlin предлагает нам концепцию «Extension Function»: мы можем к любому существующему типу добавить функцию-расширение, которая будет доступна через все объекты этого типа (но будет иметь доступ только к публичным частям).

Для добавления функционала класса, если он закрыт для расширения (например, лежит в сторонней библиотеке).

• Для расширения nullable типов.
• Для расширения companion object.
• Для расширения свойств существующих классов.
• Для конвертации моделей из одной в другую.
•Для расширения функционала дженериков.
Как функции расширения работают под капотом?

По своей задумке, функция расширения Kotlin — это дополнительный метод для любого объекта, даже для потенциально несуществующего (нуллабельного). Этот инструмент является прямой реализацией переопределения методов паттерна проектирования Декоратор.

ВАЖНО: В функциях расширения мы можем обращаться к любым общедоступным свойствам и методам объекта, однако не можем обращаться к свойствам и методам с модификаторами private и protected.

ВАЖНО: Функции расширения не переопределяют функции, которые уже определены в классе. Если функция расширения имеет ту же сигнатуру, что и уже имеющаяся функция класса, то компилятор просто будет игнорировать подобную функцию расширения.

Определение аналогично определению обычной функции за тем исключением, что после слова fun идет название типа, для которого определяется функция, и через точку название функции. Определим пару функций расширения к типам Int и String:

fun main() {

val hello: String = "hello world"
println(hello.wordCount('l')) // 3
println(hello.wordCount('o')) // 2
println(4.square()) // 16
println(6.square()) // 36
}

fun String.wordCount(c: Char) : Int {
var count = 0
for(n in this) {
if(n == c) count++
}
return count
}
fun Int.square(): Int {
return this * this
}

Для типа Int определена функция возведения в квадрат. В каждой функции расширения через ключевое слово this мы можем ссылаться на текущий объект того типа, для которого создается функция. Например, в функции:

fun Int.square(): Int {
return this * this
}

Через this обращаемся к тому объекту, для которого будет вызываться функция. И затем вы можем вызвать ее следующим образом:

4.square()      // 16

Для типа String определена функция wordCount, которая подсчитывает, сколько встречается определенный символ в строке.
Как extensions выглядят в Java?

Функции расширения для JVM являются static final методами.

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

В данной статье описана работа ОС Аврора с технологией Kotlin Multiplatform. Рассматривается метод подключения модуля Kotlin Multiplatform к приложению на Qt/QML. Для демонстрации было портировано уже существующие демо приложение "KMM RSS Reader". Проведены тесты производительности.

Читать статью