Kotlin | Вопросы собесов
2.56K subscribers
27 photos
957 links
Download Telegram
📌 Какой тип у лямбды в Java?

💬 Спрашивают в 7% собеседований

В Java лямбда-выражения имеют тип, который называется функциональным интерфейсом. Функциональный интерфейс — это интерфейс, который содержит только один абстрактный метод. Этот интерфейс может также содержать статические и по умолчанию (default) методы, но он должен иметь только один абстрактный метод, который определяет тип лямбда-выражения.

🤔 Пример функционального интерфейса

Java предоставляет несколько стандартных функциональных интерфейсов в пакете java.util.function, таких как Function, Consumer, Supplier, и Predicate. Вы также можете создать свой собственный функциональный интерфейс.

🤔 Стандартные функциональные интерфейсы

1️⃣ Function:
Используется для преобразования одного типа в другой.
Абстрактный метод: R apply(T t)

    Function<String, Integer> stringLength = s -> s.length();


2️⃣Consumer:
Принимает один аргумент и не возвращает результата.
Абстрактный метод: void accept(T t)

    Consumer<String> print = s -> System.out.println(s);


3️⃣ Supplier:
Не принимает аргументов и возвращает результат.
Абстрактный метод: T get()

    Supplier<Double> randomValue = () -> Math.random();


4️⃣ Predicate:
Принимает один аргумент и возвращает логическое значение.
Абстрактный метод: boolean test(T t)

    Predicate<Integer> isEven = i -> i % 2 == 0;


🤔 Пользовательский функциональный интерфейс

Вы можете создать свой собственный функциональный интерфейс, используя аннотацию @FunctionalInterface (необязательно, но рекомендуется):
@FunctionalInterface
public interface MyFunctionalInterface {
void myMethod();
}

public class Main {
public static void main(String[] args) {
MyFunctionalInterface myFunction = () -> System.out.println("Hello, World!");
myFunction.myMethod(); // Вывод: Hello, World!
}
}


🤔 Как это работает

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

Например, в следующем коде лямбда-выражение соответствует методу apply интерфейса Function:
Function<String, Integer> stringLength = s -> s.length();


🤔 Пример использования

Рассмотрим более полный пример с использованием функционального интерфейса Function:
import java.util.function.Function;

public class Main {
public static void main(String[] args) {
Function<String, Integer> stringLength = s -> s.length();
String testString = "Hello, World!";
Integer length = stringLength.apply(testString);
System.out.println("Length of the string: " + length); // Вывод: Length of the string: 13
}
}


🤔 Кратко:

Лямбда-выражения в Java имеют тип, называемый функциональным интерфейсом, который содержит только один абстрактный метод. Функциональные интерфейсы предоставляют способ описания сигнатуры лямбда-выражений и являются основой для работы с лямбдами в Java.

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1👀1
🤔 Какой тип возвращает функция без тела и с ключевым словом = run?
Anonymous Quiz
61%
Unit
15%
Any
11%
Nothing
13%
Lambda
📌 Какие есть опасности в Kotlin при передаче лямбды в метод из Java?

💬 Спрашивают в 7% собеседований

При передаче лямбда-выражений из Java в методы, написанные на Kotlin, существуют несколько потенциальных опасностей и проблем, которые необходимо учитывать. Некоторые из них включают:

1️⃣ Неправильная обработка `null`

В Kotlin строгая система типов, которая различает nullable и non-nullable типы. Java, в свою очередь, не имеет этой особенности, что может привести к проблемам при передаче лямбда-выражений.

Пример:
Kotlin:
fun performAction(action: () -> Unit) {
action()
}

Java:
public class Main {
public static void main(String[] args) {
MainKt.performAction(null); // NullPointerException
}
}


В этом примере, если передать null в метод performAction, это вызовет NullPointerException, так как Kotlin ожидает, что параметр action не будет null.

2️⃣ Ошибки времени компиляции

Java компилятор может не поймать все ошибки, которые Kotlin компилятор обнаружил бы при использовании лямбда-выражений.

Пример:

Kotlin:
fun transformData(transform: (String) -> Int): Int {
return transform("Kotlin")
}

Java:
public class Main {
public static void main(String[] args) {
// Ошибка не будет обнаружена компилятором Java
int result = MainKt.transformData(str -> str.length()); // Ошибка при выполнении, если str будет null
}
}


3️⃣ Интероперабельность и типы

При использовании функциональных интерфейсов необходимо убедиться, что типы параметров и возвращаемые типы лямбда-выражений совпадают с ожидаемыми типами в Kotlin.

Пример:

Kotlin:
fun executeOperation(operation: (Int, Int) -> Int): Int {
return operation(3, 4)
}

Java:
public class Main {
public static void main(String[] args) {
// Типы должны совпадать с ожидаемыми в Kotlin
int result = MainKt.executeOperation((a, b) -> a + b);
}
}


4️⃣ Отсутствие проверок на стороне Java

Кotlin предоставляет более строгую систему проверок типов, и отсутствие этих проверок в Java может привести к потенциальным ошибкам времени выполнения.

Пример:

Kotlin:
fun processData(processor: (String) -> String) {
val result = processor("Kotlin")
println(result)
}

Java:
public class Main {
public static void main(String[] args) {
// Неверное приведение типов не будет обнаружено компилятором Java
MainKt.processData(str -> (String) str.toUpperCase()); // ClassCastException при выполнении, если str будет null
}
}


5️⃣ Неверные соглашения по nullability

В Java отсутствуют аннотации на уровне типов, указывающие, может ли параметр или возвращаемое значение быть null. Это может привести к ошибкам в Kotlin, где такие соглашения строго соблюдаются.

Пример:

Kotlin:
fun processString(processor: (String) -> String?) {
val result = processor("Kotlin")
println(result?.length)
}

Java:
public class Main {
public static void main(String[] args) {
MainKt.processString(str -> null); // Возможный NPE, если Kotlin не учтет возможность null
}
}


Заключение

При передаче лямбда-выражений из Java в Kotlin нужно быть внимательным к:

1️⃣Проверкам на null.
2️⃣ Совпадению типов параметров и возвращаемых значений.
3️⃣Возможным ошибкам времени выполнения, которые могут не обнаруживаться компилятором Java.
4️⃣Интероперабельности и различиям в системе типов Java и Kotlin.

🤔 Кратко:

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

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
🤔 Какой результат выполнения выражения 10 / 3 в Kotlin?
Anonymous Quiz
12%
3.33
13%
3.0
73%
3
2%
Исключение
📌 Как в архитектурных компонентах андроид сохранить состояние view модели?

💬 Спрашивают в 7% собеседований

В архитектурных компонентах Android для сохранения состояния ViewModel используется специальный класс SavedStateHandle. Этот класс позволяет сохранить и восстановить состояние ViewModel при изменении конфигурации (например, при повороте экрана) или при пересоздании активности или фрагмента.

🤔 Как использовать SavedStateHandle

1️⃣Добавление зависимости:

Убедитесь, что в вашем проекте добавлена зависимость на архитектурные компоненты Android:

    implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:2.3.1"


2️⃣ Создание ViewModel с SavedStateHandle:

Для использования SavedStateHandle в вашей ViewModel, убедитесь, что ваш ViewModel принимает его в конструкторе. Это можно сделать, используя фабрику ViewModel при создании ViewModel.

    import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel

class MyViewModel(private val state: SavedStateHandle) : ViewModel() {

// Ключ для сохранения и восстановления состояния
private val MY_STATE_KEY = "my_state_key"

// Получение значения из SavedStateHandle
var myValue: String?
get() = state.get(MY_STATE_KEY)
set(value) {
state.set(MY_STATE_KEY, value)
}

// Инициализация состояния
init {
if (!state.contains(MY_STATE_KEY)) {
myValue = "Initial Value"
}
}
}


🤔 И в Activity или Fragment:
import android.os.Bundle
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider

class MainActivity : AppCompatActivity() {

private val myViewModel: MyViewModel by viewModels {
object : ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
return MyViewModel(defaultSavedStateHandle) as T
}
}
}

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

myViewModel.myLiveData.observe(this, { value ->
println("Observed value: $value")
})

// Установка нового значения
myViewModel.updateValue("New LiveData Value")
}
}


🤔 Кратко:

Для сохранения состояния ViewModel в архитектурных компонентах Android используется класс SavedStateHandle. Он позволяет сохранять и восстанавливать состояние при изменениях конфигурации. Создайте ViewModel с SavedStateHandle и используйте его для сохранения данных. Используйте ViewModelProvider.Factory для правильного создания ViewModel с SavedStateHandle.

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3🤔1
🤔 Какой оператор используется для проверки равенства ссылок в Kotlin?
Anonymous Quiz
19%
==
72%
===
8%
equals
1%
!==
📌 Как объединить несколько коммитов в один в Git?

💬 Спрашивают в 7% собеседований

Объединение нескольких коммитов в один в Git — это процесс, известный как "squash" коммитов. Существует несколько способов выполнения этой операции, в зависимости от вашего сценария. Наиболее распространенные способы включают использование интерактивного rebase или создание нового коммита, объединяющего изменения, а затем перезапись истории.

🤔 Способ 1️⃣: Интерактивный rebase

1️⃣ Откройте терминал и перейдите в ваш репозиторий Git.

2️⃣ Запустите интерактивный rebase:
    git rebase -i HEAD~n

где n — это количество коммитов, которые вы хотите объединить. Например, если вы хотите объединить последние 3 коммита, используйте HEAD~3.

3️⃣ Вы увидите текстовый редактор с чем-то подобным:

pick e5b7e1a Commit message 1
pick d6f8f2b Commit message 2
pick f3a7a3c Commit message 3


4️⃣ Измените "pick" на "squash" (или просто "s") для всех коммитов, кроме самого первого:

pick e5b7e1a Commit message 1
squash d6f8f2b Commit message 2
squash f3a7a3c Commit message 3


5️⃣ Сохраните и закройте редактор.

6️⃣ Вы увидите новый редактор для объединения сообщений коммитов:

# This is a combination of 3 commits.
# The first commit's message is:
Commit message 1

# This is the 2nd commit message:

Commit message 2

# This is the 3rd commit message:

Commit message 3


7️⃣ Измените сообщение на то, которое вы хотите для объединенного коммита, и сохраните изменения.

8️⃣ Git выполнит rebase и объединит ваши коммиты в один.

Способ 2️⃣: Объединение и создание нового коммита

1️⃣Создайте новую ветку из текущей:
    git checkout -b temp-branch


2️⃣ Сделайте soft reset до точки, перед которой вы хотите объединить коммиты:
    git reset --soft HEAD~n


где n — это количество коммитов, которые вы хотите объединить.

3️⃣ Создайте новый коммит со всеми изменениями:
    git commit -m "New combined commit message"


4️⃣ Переключитесь обратно на вашу основную ветку:
    git checkout main


5️⃣ Перепишите историю, используя ваш новый коммит:
    git reset --hard temp-branch


6️⃣Удалите временную ветку:
    git branch -D temp-branch


🤔 Кратко:

1️⃣ Используйте git rebase -i HEAD~n для интерактивного ребейза и объединения коммитов.
2️⃣ Измените "pick" на "squash" для коммитов, которые хотите объединить.
3️⃣ Сохраните изменения и объедините сообщения коммитов.
4️⃣Альтернативно, используйте git reset --soft HEAD~n и создайте новый коммит со всеми изменениями.

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
🤔 Какое ключевое слово используется для объявления параметров конструктора в Kotlin?
Anonymous Quiz
18%
param
10%
var
52%
val
20%
this
😁6👍1🔥1
📌 Как реализовать безопасную и надежную загрузку видео в общих чертах?

💬 Спрашивают в 7% собеседований

Реализация безопасной и надежной загрузки видео в приложении требует соблюдения нескольких ключевых принципов. Важно учитывать не только технические аспекты, но и вопросы безопасности, производительности и пользовательского опыта.

Вот общие шаги и рекомендации для создания такой системы:

1️⃣ Клиентская часть

Выбор видео
1️⃣Интерфейс выбора видео: Предоставьте пользователю удобный интерфейс для выбора видео из галереи или записи нового видео.
2️⃣ Проверка формата и размера: Убедитесь, что видео соответствует допустимым форматам (например, MP4) и размерам.

Подготовка видео к загрузке
1️⃣ Сжатие видео: Если возможно, сожмите видео перед загрузкой, чтобы уменьшить размер файла и сократить время загрузки.
2️⃣ Разделение на части: Для больших файлов используйте метод разбивки на части (chunking). Это позволяет загружать видео частями и восстанавливать загрузку в случае сбоя.

Загрузка видео
1️⃣ HTTP/HTTPS: Используйте безопасный протокол HTTPS для передачи данных.
2️⃣Библиотеки для загрузки: Используйте надежные библиотеки для загрузки файлов, такие как Retrofit с OkHttp, или другие специализированные библиотеки.


2️⃣ Серверная часть

Прием и обработка видео
1️⃣ Аутентификация и авторизация: Убедитесь, что только авторизованные пользователи могут загружать видео. Используйте токены доступа (например, JWT).
2️⃣ Ограничение размера файлов: Установите ограничения на размер загружаемых файлов.
3️⃣ Проверка файлов: Проверяйте загруженные файлы на соответствие допустимым форматам и содержимому, чтобы предотвратить загрузку вредоносных файлов.

Хранение видео
1️⃣ Файловая система или облако: Решите, где хранить видео: локально на сервере или в облачном хранилище (например, Amazon S3, Google Cloud Storage).
2️⃣ Резервное копирование и дублирование: Убедитесь, что у вас есть стратегия резервного копирования и дублирования для защиты данных.

Безопасность
1️⃣ Защита данных: Используйте шифрование для хранения и передачи видео.
2️⃣ Ограничение доступа: Контролируйте доступ к загруженным видео на уровне файловой системы и базы данных.

3️⃣ Обратная связь для пользователя

Индикация процесса загрузки
1️⃣Прогресс-бар: Показывайте прогресс загрузки, чтобы пользователи знали, что процесс идет.
2️⃣ Обработка ошибок: Обрабатывайте возможные ошибки (например, потеря соединения) и предоставляйте пользователю соответствующую информацию и возможность повторной попытки.

4️⃣ Дополнительные рекомендации

Оптимизация производительности
1️⃣ Кэширование: Используйте кэширование для уменьшения нагрузки на сервер и ускорения повторных загрузок.
2️⃣ CDN: Используйте Content Delivery Network (CDN) для ускорения доставки видео пользователям по всему миру.

Тестирование и мониторинг
1️⃣ Тестирование: Тщательно тестируйте систему загрузки видео в различных сценариях и условиях.
2️⃣ Мониторинг: Внедрите мониторинг для отслеживания производительности и состояния системы.

🤔 Кратко:

Для безопасной и надежной загрузки видео в Android приложении используйте:
HTTPS для безопасной передачи данных.
Надежные библиотеки (например, Retrofit) для загрузки.
Аутентификацию и проверку файлов на сервере.
Облачное хранилище и стратегии резервного копирования.
Прогресс-бары и обработку ошибок для лучшего пользовательского опыта.
Кэширование и CDN для оптимизации производительности.

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
🤔 Какой результат выполнения выражения "Hello".getOrElse(10) { '!' }?
Anonymous Quiz
4%
o
4%
H
22%
null
71%
!
📌 Какой UI архитектурой доставляются и рисуются данные?

💬 Спрашивают в 7% собеседований

Для доставки и рисования данных в пользовательском интерфейсе (UI) Android, используется несколько архитектурных подходов, которые обеспечивают эффективное и организованное управление данными и состоянием UI. Основные архитектуры включают:

1️⃣ MVC (Model-View-Controller):
Model: Содержит данные и бизнес-логику.
View: Отвечает за отображение данных и взаимодействие с пользователем.
Controller: Управляет связью между Model и View, обрабатывая пользовательские действия и обновляя View на основе изменений в Model.
Пример:
     // Model
public class User {
private String name;
// Геттеры и сеттеры
}

// View
public class UserView {
public void showUser(User user) {
// Код для отображения данных пользователя
}
}

// Controller
public class UserController {
private User model;
private UserView view;

public UserController(User model, UserView view) {
this.model = model;
this.view = view;
}

public void updateUser(String name) {
model.setName(name);
view.showUser(model);
}
}


2️⃣ MVP (Model-View-Presenter):
Model: Содержит данные и бизнес-логику.
View: Интерфейс, который реализуется Activity или Fragment для отображения данных.
Presenter: Логика, которая обрабатывает действия пользователя и взаимодействует с Model для обновления View.
- Пример:
     // Model
public class User {
private String name;
// Геттеры и сеттеры
}

// View
public interface UserView {
void showUser(User user);
}

// Presenter
public class UserPresenter {
private User model;
private UserView view;

public UserPresenter(User model, UserView view) {
this.model = model;
this.view = view;
}

public void updateUser(String name) {
model.setName(name);
view.showUser(model);
}
}


3️⃣ MVVM (Model-View-ViewModel):
Model: Содержит данные и бизнес-логику.
View: Активность или фрагмент, отвечающие за отображение данных.
ViewModel: Управляет данными UI и бизнес-логикой, взаимодействует с Model и предоставляет данные для View.
Использует LiveData или другие реактивные компоненты для обновления UI.
Пример:
     // Model
public class User {
private String name;
// Геттеры и сеттеры
}

// ViewModel
public class UserViewModel extends ViewModel {
private MutableLiveData<User> user = new MutableLiveData<>();

public LiveData<User> getUser() {
return user;
}

public void updateUser(String name) {
User newUser = new User();
newUser.setName(name);
user.setValue(newUser);
}
}

// View (Activity или Fragment)
public class UserActivity extends AppCompatActivity {
private UserViewModel userViewModel;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_user);

userViewModel = new ViewModelProvider(this).get(UserViewModel.class);
userViewModel.getUser().observe(this, user -> {
// Обновление UI
});

// Пример обновления пользователя
userViewModel.updateUser("New User");
}
}


🤔 Резюме
Для доставки и рисования данных в UI Android, используются архитектуры MVC, MVP и MVVM. Они помогают организовать код, управлять состоянием данных и обеспечивать эффективное обновление интерфейса.

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
🤔 Какой результат выполнения выражения val result = (1..5).reduce { acc, i -> acc * i }?
Anonymous Quiz
7%
15
75%
120
14%
60
4%
30
👍1
📌 Какие асинхронные примитивы используют для обработки данных?

💬 Спрашивают в 7% собеседований

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

1️⃣ AsyncTask:
Используется для выполнения кратковременных задач.
Состоит из трех методов: doInBackground(), onPreExecute(), и onPostExecute().
Пример:

     private class DownloadTask extends AsyncTask<String, Void, String> {
@Override
protected void onPreExecute() {
super.onPreExecute();
// Подготовка перед началом задачи
}

@Override
protected String doInBackground(String... urls) {
// Фоновая работа
return downloadData(urls[0]);
}

@Override
protected void onPostExecute(String result) {
// Обновление UI после завершения задачи
}
}


2️⃣ Handler and Looper:
Handler используется для отправки и обработки сообщений и Runnable объектов.
Looper управляет циклом обработки сообщений.
Пример:

     Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
@Override
public void run() {
// Выполнение кода в основном потоке
}
});


3️⃣ExecutorService и Future:
ExecutorService управляет пулом потоков и позволяет выполнять задачи асинхронно.
Future используется для получения результата выполнения задачи.
Пример:

     ExecutorService executorService = Executors.newFixedThreadPool(2);
Future<String> future = executorService.submit(new Callable<String>() {
@Override
public String call() throws Exception {
return downloadData("https://example.com");
}
});

try {
String result = future.get();
// Обработка результата
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}


4️⃣RxJava:
Библиотека для реализации реактивного программирования.
Позволяет управлять потоками данных и операциями над ними.
Пример:

     Observable.fromCallable(() -> downloadData("https://example.com"))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
// Обновление UI
}, Throwable::printStackTrace);


5️⃣Coroutine (Kotlin):
Легковесные потоки для выполнения асинхронных задач.
Используется вместе с suspend функциями.
- Пример:

     GlobalScope.launch(Dispatchers.Main) {
val result = withContext(Dispatchers.IO) {
downloadData("https://example.com")
}
// Обновление UI
}


🤔 Резюме
Асинхронные примитивы, такие как AsyncTask, Handler и Looper, ExecutorService, RxJava и Coroutines, позволяют выполнять фоновые задачи, чтобы основной поток приложения не блокировался. Это делает приложения более отзывчивыми и плавными.

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
2👍1
🤔 Какое ключевое слово используется для создания однопоточного канала в Kotlin?
Anonymous Quiz
44%
channel
19%
single
6%
broadcast
31%
flow
📌 Что делать, кроме UI тестов, для проверки кода на наличие багов?

💬 Спрашивают в 7% собеседований

Для проверки кода на наличие багов в Android-приложениях, кроме UI тестов, применяются различные виды тестирования и инструменты. Эти методы помогают обнаружить ошибки на разных уровнях и стадиях разработки.

1️⃣Модульное тестирование (Unit Testing):
Проверяет отдельные модули или компоненты приложения.
- Использует фреймворки, такие как JUnit и Mockito.
Пример:
     public class Calculator {
public int add(int a, int b) {
return a + b;
}
}

public class CalculatorTest {
private Calculator calculator;

@Before
public void setUp() {
calculator = new Calculator();
}

@Test
public void testAdd() {
assertEquals(5, calculator.add(2, 3));
}
}


2️⃣Интеграционное тестирование (Integration Testing):
Проверяет взаимодействие между различными модулями приложения.
- Использует инструменты, такие как Espresso и Robolectric.
Пример:
     @RunWith(AndroidJUnit4.class)
public class MainActivityTest {
@Rule
public ActivityTestRule<MainActivity> activityRule = new ActivityTestRule<>(MainActivity.class);

@Test
public void testButtonClick() {
onView(withId(R.id.button)).perform(click());
onView(withId(R.id.textView)).check(matches(withText("Hello, World!")));
}
}


3️⃣ Регрессионное тестирование (Regression Testing):
Обеспечивает, что новые изменения в коде не приводят к появлению новых багов.
Автоматизация регрессионных тестов помогает быстро проверять весь проект после изменений.
Использует инструменты, такие как JUnit, Espresso, и UI Automator.

4️⃣ Тестирование производительности (Performance Testing):
Оценивает производительность приложения под разной нагрузкой.
Использует инструменты, такие как Android Profiler и Firebase Performance Monitoring.
Пример:
     public void startCpuProfiling() {
Debug.startMethodTracing("cpu_trace");
// Ваш код для тестирования
Debug.stopMethodTracing();
}


5️⃣ Статический анализ кода (Static Code Analysis):
Анализирует исходный код без выполнения программы.
Использует инструменты, такие как Lint, SonarQube и Checkstyle.
Пример использования Lint:
     <lint>
<issue id="UnusedResources" severity="warning" />
</lint>


6️⃣Тестирование безопасности (Security Testing):
Проверяет уязвимости приложения.
Использует инструменты, такие как OWASP ZAP и ProGuard для минимизации рисков.
Пример конфигурации ProGuard:
     -keep class com.example.** { *; }
-dontwarn com.example.**


7️⃣ Тестирование на различных устройствах и версиях ОС (Compatibility Testing):
Обеспечивает корректную работу приложения на разных устройствах и версиях Android.
Использует Firebase Test Lab и другие эмуляторы и устройства.

🤔 Резюме
Для проверки кода на наличие багов в Android-приложениях используются различные методы, включая модульное, интеграционное, регрессионное, производственное и безопасность тестирование, статический анализ кода и тестирование совместимости. Эти методы помогают выявить и устранить баги на разных стадиях разработки.

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
🤔 Какой результат выполнения выражения listOf(1, 2, 3, 4).fold(0) { acc, i -> acc + i }?
Anonymous Quiz
22%
0
65%
10
11%
9
2%
6
🎉1
📌 Как Extension применяются в Java?

💬 Спрашивают в 7% собеседований

В Java нет прямой поддержки расширений (extension), как это есть, например, в Kotlin. Однако, можно реализовать аналогичную функциональность через утилитные методы (Utility Methods). Это позволяет добавлять функциональные возможности к существующим классам без изменения их исходного кода.

🤔 Пример использования утилитных методов

Рассмотрим пример, где добавляем утилитные методы для работы со строками.

1️⃣ Создание утилитного класса:
Создайте класс, который будет содержать статические методы. Эти методы будут выполнять действия, которые вы хотите добавить к существующим классам.

public class StringUtils {

// Пример утилитного метода, который проверяет, пустая ли строка
public static boolean isEmpty(String str) {
return str == null || str.isEmpty();
}

// Пример утилитного метода, который обращает строку
public static String reverse(String str) {
if (str == null) {
return null;
}
return new StringBuilder(str).reverse().toString();
}
}


2️⃣Использование утилитных методов:
Используйте методы из утилитного класса так, как будто они являются расширениями класса String.

public class Main {
public static void main(String[] args) {
String text = "Hello, World!";

// Использование утилитных методов
boolean isEmpty = StringUtils.isEmpty(text);
System.out.println("Is empty: " + isEmpty);

String reversed = StringUtils.reverse(text);
System.out.println("Reversed: " + reversed);
}
}


🤔 Более сложный пример

Создадим утилитный класс для работы с коллекциями:

public class CollectionUtils {

// Пример утилитного метода, который объединяет два списка
public static <T> List<T> merge(List<T> list1, List<T> list2) {
List<T> result = new ArrayList<>(list1);
result.addAll(list2);
return result;
}

// Пример утилитного метода, который находит пересечение двух списков
public static <T> List<T> intersection(List<T> list1, List<T> list2) {
List<T> result = new ArrayList<>(list1);
result.retainAll(list2);
return result;
}
}


Использование утилитных методов:

public class Main {
public static void main(String[] args) {
List<String> list1 = Arrays.asList("a", "b", "c");
List<String> list2 = Arrays.asList("b", "c", "d");

// Объединение списков
List<String> merged = CollectionUtils.merge(list1, list2);
System.out.println("Merged: " + merged);

// Пересечение списков
List<String> intersected = CollectionUtils.intersection(list1, list2);
System.out.println("Intersection: " + intersected);
}
}


🤔 Резюме

В Java расширения реализуются через утилитные методы, создаваемые в отдельных классах. Эти методы могут быть статическими и добавляют функциональность к существующим классам без их модификации. Например, класс StringUtils может содержать методы для работы со строками, а CollectionUtils — для работы с коллекциями.

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
📌 Какие проблемы есть у Dagger?

💬 Спрашивают в 7% собеседований

Dagger – это популярный инструмент для внедрения зависимостей в Android-приложениях. Несмотря на его преимущества, существуют некоторые проблемы и недостатки, которые могут возникнуть при его использовании.

1️⃣Сложность конфигурации и обучения:
Dagger имеет крутой порог входа, особенно для разработчиков, которые не знакомы с концепциями Dependency Injection (DI) и аннотациями в Java. Понимание работы аннотаций @Inject, @Module, @Component и других может быть сложным для новичков.

2️⃣ Длинные времена компиляции:
Dagger использует генерацию кода на этапе компиляции. В больших проектах это может существенно замедлить процесс компиляции, особенно когда изменяются классы, участвующие в DI.

3️⃣ Отладка и обработка ошибок:
Ошибки Dagger могут быть сложны для отладки. Сообщения об ошибках компиляции часто неочевидны и требуют глубокого понимания внутренней работы Dagger для их интерпретации.

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

5️⃣ Избыточность кода:
Использование Dagger может привести к значительному увеличению количества кода из-за необходимости создания модулей, компонентов и написания аннотаций. Это делает код менее читабельным и более сложным для поддержки.

6️⃣ Сложности с тестированием:
Несмотря на то, что Dagger упрощает внедрение зависимостей для тестирования, создание и настройка тестовых компонентов и модулей может быть трудоемким процессом. Это требует дополнительных усилий и времени для правильной настройки тестовой среды.

🤔 Пример:
Допустим, у нас есть класс UserRepository, который зависит от ApiService и DatabaseService. С использованием Dagger это может выглядеть следующим образом:
public class UserRepository {
private final ApiService apiService;
private final DatabaseService databaseService;

@Inject
public UserRepository(ApiService apiService, DatabaseService databaseService) {
this.apiService = apiService;
this.databaseService = databaseService;
}
}

@Module
public class AppModule {
@Provides
public ApiService provideApiService() {
return new ApiServiceImpl();
}

@Provides
public DatabaseService provideDatabaseService() {
return new DatabaseServiceImpl();
}
}

@Component(modules = AppModule.class)
public interface AppComponent {
void inject(MainActivity mainActivity);
}


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

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

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
🤔 Какое значение будет у переменной val x = listOf(1, 2, 3).firstOrNull { it > 1 } ?: 0?
Anonymous Quiz
6%
1
70%
2
2%
3
22%
0
📌 Как минимизировать влияние Dagger на время сборки?

💬 Спрашивают в 7% собеседований

Для минимизации влияния Dagger на время сборки можно воспользоваться несколькими стратегиями и практиками, которые помогут оптимизировать процесс компиляции:

1️⃣ Разделение модулей и компонентов:
Разделяйте большие модули на несколько меньших, логически связанных. Это позволит Dagger более эффективно обрабатывать изменения и сократит время компиляции.
Используйте компоненты с подкомпонентами или дочерними компонентами, чтобы изолировать изменения в разных частях приложения.

2️⃣Использование Dagger’s Hilt:
Hilt – это библиотека, созданная на основе Dagger, которая упрощает внедрение зависимостей и уменьшает количество шаблонного кода. Она также может помочь сократить время сборки за счет автоматического создания необходимых компонентов и модулей.

3️⃣Ограничение количества зависимостей в одном компоненте:
Избегайте создания компонентов с большим количеством зависимостей. Это может замедлить генерацию кода Dagger. Разделение зависимостей на несколько компонентов или модулей поможет улучшить производительность.

4️⃣ Использование Dagger Android Processors только там, где это необходимо:
Убедитесь, что Dagger использует только необходимые процессоры аннотаций. Проверьте и отключите ненужные процессоры, чтобы сократить время компиляции.

5️⃣ Оптимизация кода модулей и компонентов:
Убедитесь, что в модулях и компонентах используется как можно меньше шаблонного и избыточного кода. Это поможет уменьшить количество генерируемого кода и сократить время компиляции.

6️⃣ Включение параллельной компиляции:
Настройте проект так, чтобы компиляция происходила параллельно, что позволяет сократить общее время сборки. В Gradle это можно сделать с помощью настройки org.gradle.parallel=true в gradle.properties.

7️⃣ Кэширование сборки:
Включите кэширование сборки в Gradle. Это позволит использовать уже скомпилированные артефакты, уменьшая время повторной компиляции. Настройка для этого: org.gradle.caching=true.

8️⃣ Использование Kapt Incremental Annotation Processing:
Если вы используете Kotlin, убедитесь, что включена инкрементальная обработка аннотаций для Kapt (Kotlin Annotation Processing Tool). Это уменьшит количество повторно компилируемых классов при изменениях. Включить эту опцию можно, добавив kapt { incremental = true } в build.gradle.

🤔 Пример настройки Gradle:
// Включение параллельной компиляции и кэширования сборки в gradle.properties
org.gradle.parallel=true
org.gradle.caching=true

// Включение инкрементальной обработки аннотаций для Kapt в build.gradle
kapt {
incremental = true
}


🤔 Краткий вывод:
Чтобы минимизировать влияние Dagger на время сборки, разделяйте модули и компоненты, используйте Hilt, ограничивайте количество зависимостей в компонентах, оптимизируйте код модулей и компонентов, включайте параллельную компиляцию и кэширование сборки, а также используйте инкрементальную обработку аннотаций в Kapt.

🔥 ТОП ВОПРОСОВ С СОБЕСОВ

🔒 База собесов | 🔒 База тестовых
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3