Kotlin | Вопросы собесов
2.56K subscribers
30 photos
970 links
Download Telegram
Forwarded from easyoffer
Официальный релиз easyoffer 2.0 состоится уже в течение нескольких дней.

Напоминаю, что в честь релиза запускаем акцию.

Первые 500 покупателей получат:

🚀 Скидку 50% на PRO тариф на 1 год
🎁 Подарок ценностью 5000₽ для тех, кто подписан на этот канал

🔔 Подпишитесь на этот канал: https://t.iss.one/+b2fZN17A9OQ3ZmJi
В нем мы опубликуем сообщение о релизе в первую очередь
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔1
🤔 Swich в котлине?

В Kotlin нет switch, но его заменяет более мощный оператор when.

Простой пример (аналог switch-case)
fun getDayName(day: Int): String {
return when (day) {
1 -> "Понедельник"
2 -> "Вторник"
3 -> "Среда"
4 -> "Четверг"
5 -> "Пятница"
6 -> "Суббота"
7 -> "Воскресенье"
else -> "Некорректный день"
}
}

fun main() {
println(getDayName(3)) // Среда
}


when без else (если учтены все случаи)
fun getStatus(code: Int): String = when (code) {
200 -> "OK"
404 -> "Not Found"
500 -> "Server Error"
}


Несколько значений в одном case
fun isWeekend(day: Int): Boolean {
return when (day) {
6, 7 -> true // Оба значения работают как один case
else -> false
}
}


🚩`when` как альтернатива `if-else`

Можно проверять логические выражения, а не просто числа.
fun checkNumber(x: Int): String {
return when {
x < 0 -> "Отрицательное число"
x == 0 -> "Ноль"
x > 0 -> "Положительное число"
else -> "Ошибка"
}
}


Использование when без аргумента
fun describe(obj: Any): String {
return when {
obj is String -> "Это строка"
obj is Int -> "Это число"
obj is Boolean -> "Это логический тип"
else -> "Неизвестный тип"
}
}


🚩`when` в качестве выражения

when можно использовать как выражение, возвращая результат:
val message = when (val code = 404) {
200 -> "OK"
404 -> "Not Found"
else -> "Unknown"
}
println(message) // Not Found


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7💊2
🤔 У нас нет устройства, чтобы профилировать приложение. Что будешь делать, чтобы проверить код?

– Использовать эмулятор и встроенные инструменты Android Studio (Logcat, Profiler),
– Добавить ручные замеры времени,
– Использовать Unit и Instrumented тесты,
– Использовать StrictMode и LeakCanary.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1🤔1
🤔 Что такое SharedFlow и чем он отличается от StateFlow?

В Kotlin Flow есть два специальных вида потоков для управления состоянием и передачей данных:
StateFlow — используется для хранения и отслеживания состояния.
SharedFlow — используется для многократной отправки данных нескольким подписчикам.
Теперь разберёмся в деталях.

🚩Что такое SharedFlow?

SharedFlow — это горячий (hot) поток, который можно использовать для передачи данных нескольким подписчикам. Он не хранит состояние и просто раздаёт значения подписчикам в реальном времени.

🚩Как работает SharedFlow?

- Позволяет многим подписчикам получать одни и те же данные.
- Может буферизировать значения (хранить их для новых подписчиков).
- Может повторять последние значения (replay) для новых подписчиков.
- Может накапливать данные и работать как очередь событий.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*

fun main() = runBlocking {
val sharedFlow = MutableSharedFlow<Int>(replay = 2) // Будет повторять последние 2 значения для новых подписчиков

launch {
for (i in 1..5) {
sharedFlow.emit(i)
delay(100)
}
}

launch {
delay(150) // Подписываемся чуть позже
sharedFlow.collect { println("Первый подписчик получил: $it") }
}

launch {
delay(300) // Подписываемся ещё позже
sharedFlow.collect { println("Второй подписчик получил: $it") }
}
}


🚩Что такое StateFlow?

StateFlow — это поток, который всегда хранит одно последнее значениЕ. Он идеально подходит для представления состояния (например, UI-состояния в MVVM).
- Всегда содержит одно актуальное значение.
- Если новое значение не отличается от текущего, оно не отправляется подписчикам.
- Новый подписчик сразу получает текущее значение.
- Можно думать о StateFlow как о LiveData, но для корутин.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*

fun main() = runBlocking {
val stateFlow = MutableStateFlow(0) // Начальное состояние

launch {
delay(200) // Подписываемся позже
stateFlow.collect { println("Подписчик получил: $it") }
}

delay(100)
stateFlow.value = 1 // Меняем состояние
stateFlow.value = 2 // Меняем состояние
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
🤔 Откуда приходит и куда уходит Bundle?

Bundle передаётся через Intent или setArguments, и доступен при запуске Activity/Fragment или в методе onSaveInstanceState. Он используется как для передачи данных, так и для восстановления состояния.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2
🤔 Что такое px, dp, sp?

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

🚩`px` (пиксели) – физические точки экрана

px (pixel) – это самая маленькая единица изображения на экране.
Не зависит от плотности экрана → на разных устройствах элементы могут выглядеть слишком маленькими или большими.
<TextView
android:layout_width="100px"
android:layout_height="50px"/>


🚩`dp` (density-independent pixels) – независимые от плотности пиксели

dp (density-independent pixel) – это абстрактная единица измерения, которая адаптируется под плотность экрана (dpi).
Рекомендуется для всех размеров UI, чтобы интерфейс выглядел одинаково на разных устройствах.
<TextView
android:layout_width="100dp"
android:layout_height="50dp"/>


Пример в Kotlin
val sizeInPx = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, 100f, resources.displayMetrics
)


🚩`sp` (scale-independent pixels) – масштабируемые пиксели (для текста)

sp (scale-independent pixel) – как dp, но ещё учитывает настройки шрифта пользователя. Используется только для размеров шрифтов.
<TextView
android:text="Привет, мир!"
android:textSize="16sp"/>


Пример в Kotlin
val textSizeInPx = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_SP, 16f, resources.displayMetrics
)


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
🤔 Как интегрировать в проект тесты?

1. Настроить инфраструктуру для юнит-тестирования (JUnit, Mockito) и интеграционного тестирования (Espresso).
2. Начать с написания тестов для ключевых частей функциональности, например, бизнес-логики.
3. Использовать инструментальные тесты для проверки работы интерфейса.
4. Постепенно увеличивать покрытие тестами, анализируя результаты через CI/CD.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2
🤔 Как в Ретрофите изменять все запросы?

В Retrofit можно изменять все запросы глобально с помощью Interceptor (перехватчика) в OkHttp. Это позволяет добавлять или изменять заголовки, параметры запроса, авторизацию, логирование и многое другое.

🟠Изменение всех запросов с помощью `Interceptor`
Перехватчик (Interceptor) позволяет модифицировать запрос перед его отправкой.
class AuthInterceptor(private val tokenProvider: TokenProvider) : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request().newBuilder()
.addHeader("Authorization", "Bearer ${tokenProvider.getToken()}")
.addHeader("Accept", "application/json")
.build()
return chain.proceed(request)
}
}


Добавляем перехватчик в OkHttpClient:
val okHttpClient = OkHttpClient.Builder()
.addInterceptor(AuthInterceptor(tokenProvider))
.build()

val retrofit = Retrofit.Builder()
.baseUrl("https://api.example.com/")
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.build()


🟠Добавление общих Query параметров
Иногда нужно добавлять общие GET-параметры (например, API-ключ).
class QueryInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val originalRequest = chain.request()
val originalUrl = originalRequest.url

val newUrl = originalUrl.newBuilder()
.addQueryParameter("api_key", "YOUR_API_KEY")
.build()

val newRequest = originalRequest.newBuilder()
.url(newUrl)
.build()

return chain.proceed(newRequest)
}
}


Добавляем в OkHttpClient:
val okHttpClient = OkHttpClient.Builder()
.addInterceptor(QueryInterceptor())
.build()


🟠Автоматическая повторная авторизация (Refresh Token)
Если сервер возвращает 401 Unauthorized, можно обновить токен и повторить запрос.
class AuthenticatorInterceptor(private val tokenProvider: TokenProvider) : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
var request = chain.request()
var response = chain.proceed(request)

if (response.code == 401) {
// Получаем новый токен
val newToken = tokenProvider.refreshToken()

// Делаем новый запрос с обновлённым токеном
val newRequest = request.newBuilder()
.header("Authorization", "Bearer $newToken")
.build()

response.close() // Закрываем старый ответ
response = chain.proceed(newRequest) // Повторяем запрос
}

return response
}
}


Добавляем в OkHttpClient:
val okHttpClient = OkHttpClient.Builder()
.addInterceptor(AuthenticatorInterceptor(tokenProvider))
.build()


🟠Логирование всех запросов
Для отладки удобно логировать все запросы и ответы.
val loggingInterceptor = HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.BODY
}

val okHttpClient = OkHttpClient.Builder()
.addInterceptor(loggingInterceptor)
.build()


🟠Полностью менять `baseUrl` (динамический URL)
Если в приложении нужно менять baseUrl, можно изменять его перед каждым запросом.
class BaseUrlInterceptor(private val urlProvider: UrlProvider) : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val originalRequest = chain.request()
val newUrl = urlProvider.getBaseUrl() + originalRequest.url.encodedPath

val newRequest = originalRequest.newBuilder()
.url(newUrl)
.build()

return chain.proceed(newRequest)
}
}


Используем в OkHttpClient:
val okHttpClient = OkHttpClient.Builder()
.addInterceptor(BaseUrlInterceptor(urlProvider))
.build()


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
🤔 Как эффективно изменить данные в списке, состоящем из большого количества View?

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

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2
🤔 Расскажи все типы данных в Java/Kotlin?

В Java и Kotlin существуют различные типы данных, которые можно разделить на две основные категории:
Примитивные типы данных (primitive types)
Ссылочные типы данных (reference types)

🚩Типы данных в Java

🟠Ссылочные типы данных (Reference Types)
Ссылочные типы данных указывают на объекты. Они хранятся в куче (heap) и содержат ссылку (адрес) на объект.
Примеры ссылочных типов

🟠Строки (`String`)
String str = "Hello";

🟠Классы и объекты
MyClass obj = new MyClass();

🟠Массивы
int[] arr = {1, 2, 3};

🟠Интерфейсы
List<Integer> list = new ArrayList<>();

🚩Типы данных в Kotlin

В Kotlin типы данных делятся на nullable и non-nullable (значения, которые могут быть null, и те, которые не могут). Kotlin избегает примитивных типов напрямую, но на уровне JVM использует их для оптимизации.

🟠Примитивные типы данных (на уровне JVM)
Kotlin предоставляет высокоуровневые обёртки для примитивных типов. Например:
Int вместо int
Double вместо double

🟠Ссылочные типы данных (Reference Types)
В Kotlin все данные — объекты.
Сюда входят:
Строки (String): val str: String = "Hello"
Коллекции: val list: List<Int> = listOf(1, 2, 3)
Классы: val obj = MyClass()
Nullable-типизация: В Kotlin можно указать, что переменная может быть null. Для этого используется ?.
  val nullableString: String? = null
val nonNullableString: String = "Hello"


Интерфейсы и абстракции: Kotlin поддерживает классы, интерфейсы и их реализации, например
  interface Animal {
fun makeSound()
}

class Dog : Animal {
override fun makeSound() {
println("Woof!")
}
}


🟠Тип Unit и Nothing
Kotlin добавляет уникальные типы, которые отсутствуют в Java:
Unit
Эквивалент void в Java, но является объектом.
Используется, когда функция ничего не возвращает:
  fun printMessage(message: String): Unit {
println(message)
}


Nothing
Представляет значение, которое никогда не будет существовать (например, функция всегда бросает исключение):
  fun fail(message: String): Nothing {
throw IllegalArgumentException(message)
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
🤔 Почему main activity отличается от activity при просмотре фото или метрик?

MainActivity — обычно центральная точка входа с навигацией. Специализированные активити, такие как просмотр фото или метрик, имеют ограниченную функциональность и могут иметь другой жизненный цикл или быть настроены как noHistory, чтобы не сохраняться в бэкстеке.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2
🤔 Что такое UI tred и Worker tred?

В Android есть два основных типа потоков:
1. UI Thread (главный поток) → отвечает за интерфейс и обработку событий.
2. Worker Thread (фоновый поток) → используется для долгих операций (запросы в сеть, работа с БД).

🚩`UI Thread` – главный поток

- Отвечает за отрисовку интерфейса (Activity, Fragment, View).
- Обрабатывает нажатия, свайпы, анимации.
- Все setText(), setImageResource() и другие UI-методы работают только здесь. Если делать тяжёлые операции в UI Thread, приложение зависнет (ANR - Application Not Responding)!
val url = URL("https://example.com")
val connection = url.openConnection() as HttpURLConnection // Ошибка!


🚩`Worker Thread` – фоновый поток

- Выполняет долгие операции, не блокируя UI:
Запросы в сеть (Retrofit, OkHttp)
Чтение/запись в БД (Room, SQLite)
Обработку файлов, JSON, XML
Любые тяжёлые вычисления
CoroutineScope(Dispatchers.IO).launch {
val url = URL("https://example.com")
val connection = url.openConnection() as HttpURLConnection // Работает!
}


🚩Как переключаться между `UI Thread` и `Worker Thread`?
Способ 1: Coroutines (лучший вариант)
CoroutineScope(Dispatchers.IO).launch {
val data = fetchData() // Работает в `Worker Thread`

withContext(Dispatchers.Main) {
textView.text = data // Назад в `UI Thread`
}
}


Способ 2: Handler + Thread (старый вариант)
val handler = Handler(Looper.getMainLooper())

Thread {
val data = fetchData() // Работает в `Worker Thread`

handler.post {
textView.text = data // Назад в `UI Thread`
}
}.start()


Способ 3: AsyncTask (УСТАРЕЛ, НЕ ИСПОЛЬЗОВАТЬ!)
class MyTask : AsyncTask<Void, Void, String>() {
override fun doInBackground(vararg params: Void?): String {
return fetchData() // `Worker Thread`
}

override fun onPostExecute(result: String) {
textView.text = result // `UI Thread`
}
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
💊2👍1
🤔 Как остановить сервис?

В зависимости от типа сервиса:
- Для обычного (started) сервиса:
- Внутри самого сервиса:
Для bound service — вызывается unbindService().


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
💊2🔥1🤔1
Forwarded from easyoffer
Ура, друзья! Изиоффер переходит в публичное бета-тестирование!

🎉 Что нового:
🟢Анализ IT собеседований на основе 4500+ реальных интервью
🟢Вопросы из собеседований с вероятностью встречи
🟢Видео-примеры ответов на вопросы от Senior, Middle, Junior грейдов
🟢Пример лучшего ответа
🟢Задачи из собеседований
🟢Тестовые задания
🟢Примеры собеседований
🟢Фильтрация всего контента по грейдам, компаниям
🟢Тренажер подготовки к собеседованию на основе интервальных повторений и флеш карточек
🟡Тренажер "Реальное собеседование" с сценарием вопросов из реальных собеседований (скоро)
🟢Автоотклики на HeadHunter
🟢Закрытое сообщество easyoffer


💎 Акция в честь открытия для первых 500 покупателей:
🚀 Скидка 50% на PRO тариф на 1 год (15000₽ → 7500₽)

🔥 Акция уже стартовала! 👉 https://easyoffer.ru/pro
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔 Что такое софткод?

Софткод (Softcode, Soft Coding) — это подход к программированию, при котором логика программы хранится в конфигурационных файлах, базе данных или других внешних источниках, а не жёстко (hardcoded) прописана в коде.

🚩Разница между Hardcode и Softcode

Пример Hardcode (жёстко зашито в коде)
val apiUrl = "https://api.example.com" //  Если URL изменится, надо менять код


Пример Softcode (гибко через конфигурацию)
val apiUrl = Config.get("api_url") //  Загружается из настроек


🚩Где используется софткод?

Конфигурационные файлы (config.json, .properties, .xml).
База данных (логика, настройки, права пользователей).
API и сервер (получение UI-элементов, бизнес-логики с сервера).
Скриптовые языки (скрипты загружаются динамически).

🚩Примеры использования Softcode в Android

Softcode через SharedPreferences (конфигурация в памяти)
val sharedPrefs = context.getSharedPreferences("settings", Context.MODE_PRIVATE)
val theme = sharedPrefs.getString("app_theme", "light") // Загружаем тему из настроек


Softcode через remoteConfig (Firebase Remote Config)
val minVersion = Firebase.remoteConfig.getInt("min_supported_version")


Softcode через JSON-файл (читаем конфиг из assets)
fun getConfigValue(context: Context, key: String): String {
val json = context.assets.open("config.json").bufferedReader().use { it.readText() }
val jsonObject = JSONObject(json)
return jsonObject.getString(key) // Получаем значение из JSON
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
🤔 Разница между git pull и git fetch?

- git fetch — загружает изменения из удалённого репозитория, но не сливает их. Используется для предварительного обзора.
- git pull = fetch + merge — загружает и сразу применяет изменения к текущей ветке.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2👍1
🤔 Как расшифровывается xml?

XML — это eXtensible Markup Language (Расширяемый язык разметки).

🚩Что означает расшифровка?

eXtensible → Расширяемый (можно создавать свои теги).
Markup → Разметка (использует теги <tag> для структурирования данных).
Language → Язык (формат хранения и передачи данных).

🚩Где используется XML?

В Android:
Разметка UI (activity_main.xml).
Конфигурация (AndroidManifest.xml).
Ресурсы (strings.xml, colors.xml).

В веб-разработке:
Конфигурации (.xml файлы в серверных приложениях).
Форматы обмена данными (SOAP, RSS, SVG).

Пример XML-кода
<user>
<name>Алиса</name>
<age>25</age>
</user>


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
🤔 Как добавить контекст в метод из Dagger Hilt?

Hilt позволяет внедрять контекст с помощью аннотаций
@ApplicationContext или @ActivityContext, чтобы точно указать, какой именно контекст требуется для зависимости.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1
🤔 Можно ли создать анонимный класс внутри inline функции?

Анонимный класс внутри inline-функции будет инстанцироваться при каждом вызове функции, что ломает цель inline — избавляться от накладных расходов на объекты.

🚩Что такое анонимный класс в Kotlin?

Анонимный класс — это класс без имени, который можно создать с помощью object : Interface {}.
interface ClickListener {
fun onClick()
}

fun main() {
val listener = object : ClickListener {
override fun onClick() {
println("Кнопка нажата!")
}
}

listener.onClick()
}


🚩Анонимный класс в `inline`-функции

Если мы создадим анонимный класс внутри inline-функции, он будет создаваться каждый раз при вызове функции!
inline fun setClickListener(action: () -> Unit) {
val listener = object : ClickListener {
override fun onClick() {
action()
}
}
listener.onClick()
}

fun main() {
setClickListener { println("Нажато!") }
}


Ошибка компиляции
Inline function cannot contain object expressions


🚩Как обойти ограничение?

Если нужно использовать inline, можно передавать лямбду вместо анонимного класса.
Рабочий вариант
inline fun setClickListener(noinline action: () -> Unit): ClickListener {
return object : ClickListener {
override fun onClick() {
action()
}
}
}

fun main() {
val listener = setClickListener { println("Нажато!") }
listener.onClick()
}


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
🤔 Что известно про heap pollution (загрязнение heap-а)?

Это ситуация, когда в куче (heap) оказывается объект неправильного типа из-за неправильного использования дженериков. Это может привести к ClassCastException во время выполнения.
Причины загрязнения:
- Использование необработанных типов (raw types), например List вместо List<String>.
- Нарушение type safety при кастах ((List<Integer>) obj).
- Использование varargs с дженериками (List<T>... args).


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4
🤔 Какие знаешь особенности системы типов в Kotlin ?

🟠Null Safety (Безопасность null)
Переменные по умолчанию не могут быть null, что предотвращает NullPointerException.
var a: String = "abc"
var b: String? = "abc"
b = null // Допустимо


🟠Коллекции (Collections)
Разделение на изменяемые и неизменяемые коллекции.
val list: List<String> = listOf("a", "b", "c")  // Неизменяемый список
val mutableList: MutableList<String> = mutableListOf("a", "b", "c") // Изменяемый список


🟠Data Classes (Классы данных)
Автоматическое создание методов equals(), hashCode(), и toString().
data class User(val name: String, val age: Int)   


🟠Smart Casts (Умные приведения типов)
Автоматическое приведение типа после проверки с помощью is.
fun demo(x: Any) {
if (x is String) {
println(x.length)
}
}


🟠Sealed Classes (Запечатанные классы)
Упрощают обработку ограниченных иерархий классов.
sealed class Expr
data class Const(val number: Double) : Expr()


🟠Выведение типов (Type Inference)
Kotlin автоматически определяет тип переменной.
val x = 10  // Int


Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2