Skip to content

Instantly share code, notes, and snippets.

@vitkidd
Created December 10, 2020 12:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vitkidd/353e123959dbcf2239a3dd6657f1bd8a to your computer and use it in GitHub Desktop.
Save vitkidd/353e123959dbcf2239a3dd6657f1bd8a to your computer and use it in GitHub Desktop.

Скрининг

Перед собеседованием HR проводит небольшой телефонный скрининг: https://forms.gle/GJFp2aii2sTaTLZc9

Методы класса Object в Java

Вопросы:

  • Какие методы класса Object ты знаешь и зачем они нужны?

Грейды:

  • Junior: Не знает.
  • Middle: Знает про equals, hashCode, toString
  • Senior: Знает про все методы.

Подсказка:

  • equals(Object obj) - определяет, равен ли один объект другому.
  • hashCode() - возвращает хэш-код, связанный с вызывающим объектом.
  • toString() - возвращает символьную строку, описывающую объект.
  • clone() - создает новый объект, не отличающийся от клонируемого.
  • finalize() - вызывается перед удалением неиспользуемого объекта.
  • getClass() - получает класс объекта во время выполнения.
  • notify() - возобновляет исполнение потока, ожидающего вызывающего объекта.
  • notifyAll() - возобновляет исполнение всех потоков, ожидающих вызывающего объекта.
  • wait() - ожидает другого потока исполнения.
  • wait(long timeout) - ожидает другого потока исполнения.
  • wait(long timeout, int nanos) - ожидает другого потока исполнения.

Коллекции

Вопросы:

  • Можно задавать вопросы напрямую: какие коллекции ты знаешь?
  • Можно сформулировать вопрос на обсуждение: Необходимо добавить 1млн. элементов, какую структуру вы используете?
  • Дополнительно можно спросить про отличия между HashSet, TreeSet, LinkedHashSet и между HashMap, TreeMap, LinkedHashMap.

Грейды:

  • Junior: Может назвать отличия ArrayList, LinkedList, HashMap, HashSet.
  • Middle: Может рассказать как работают ArrayList, HashMap, HashSet.
  • Senior: Может рассказать про TreeSet, LinkedHashSet, TreeMap, LinkedHashMap, WeakHashMap.

Подсказка:

ArrayList — является реализацией динамического массива объектов. Позволяет хранить любые данные, включая null в качестве элемента. Как можно догадаться из названия, его реализация основана на обычном массиве. Данную реализацию следует применять, если в процессе работы с коллекцией предплагается частое обращение к элементам по индексу. Из-за особенностей реализации поиндексное обращение к элементам выполняется за константное время O(1). Но данную коллекцию рекомендуется избегать, если требуется частое удаление/добавление элементов в середину коллекции.

LinkedList — позволяет хранить любые данные, включая null. Особенностью реализации данной коллекции является то, что в её основе лежит двунаправленный связный список (каждый элемент имеет ссылку на предыдущий и следующий). Благодаря этому, добавление и удаление из середины, доступ по индексу, значению происходит за линейное время O(n), а из начала и конца за константное O(1). Так же, ввиду реализации, данную коллекцию можно использовать как стек или очередь. Для этого в ней реализованы соответствующие методы.

HashMap — не синхронизирована и позволяет использовать null как в качестве ключа, так и значения. Данная коллекция не является упорядоченной: порядок хранения элементов зависит от хэш-функции. Добавление элемента выполняется за константное время O(1), но время удаления, получения зависит от распределения хэш-функции. В идеале является константным, но может быть и линейным O(n).

LinkedHashMap — это упорядоченная реализация хэш-таблицы. Здесь, в отличии от HashMap, порядок итерирования равен порядку добавления элементов. Данная особенность достигается благодаря двунаправленным связям между элементами (аналогично LinkedList). Но это преимущество имеет также и недостаток — увеличение памяти, которое занимет коллекция.

TreeMap — реализация Map основанная на красно-чёрных деревьях. Как и LinkedHashMap является упорядоченной. По-умолчанию, коллекция сортируется по ключам с использованием принципа "natural ordering", но это поведение может быть настроено под конкретную задачу при помощи объекта Comparator, который указывается в качестве параметра при создании объекта TreeMap.

WeakHashMap — реализация хэш-таблицы, которая организована с использованием weak references. Другими словами, Garbage Collector автоматически удалит элемент из коллекции при следующей сборке мусора, если на ключ этого элеметна нет жёстких ссылок.

HashSet — реализация интерфейса Set, базирующаяся на HashMap. Внутри использует объект HashMap для хранения данных. В качестве ключа используется добавляемый элемент, а в качестве значения — объект-пустышка (new Object()). Из-за особенностей реализации порядок элементов не гарантируется при добавлении.

LinkedHashSet — отличается от HashSet только тем, что в основе лежит LinkedHashMap вместо HashMap. Благодаря этому отличию порядок элементов при обходе коллекции является идентичным порядку добавления элементов.

TreeSet — аналогично другим классам-реализациям интерфейса Set содержит в себе объект NavigableMap, что и обуславливает его поведение. Предоставляет возможность управлять порядком элементов в коллекции при помощи объекта Comparator, либо сохраняет элементы с использованием "natural ordering".

Контракт equals и hashCode

Вопросы:

  • Расскажите основные правила контракта.

Грейды:

  • Junior: Не знает.
  • Middle: Знает частично.
  • Senior: Может полностью рассказать контракт.

Подсказка:

equals():

  • Для любого объекта x x.equals(x) должен возвращать true.
  • Для любых двух объектов x и y x.equals(y) должен возвращать true тогда и только тогда, когда y.equals(x) возвращает true.
  • Для нескольких объектов x, y и z, если x.equals(y) возвращает true, а y.equals (z) возвращает true, то x.equals(z) должен возвращать true.
  • Множественные вызовы x.equals(y) должны возвращать один и тот же результат, если не изменено какое-либо из свойств объекта, которые используются в реализации метода equals().
  • Для любого объекта x x.equals(null) должен возвращать false.

hashCode():

  • Вызов метода hashCode один и более раз над одним и тем же объектом должен возвращать одно и то же хэш-значение, при условии что поля объекта, участвующие в вычислении значения, не изменялись.
  • Вызов метода hashCode над двумя объектами должен всегда возвращать одно и то же число, если эти объекты равны (вызов метода equals для этих объектов возвращает true).
  • Вызов метода hashCode над двумя неравными между собой объектами должен возвращать разные хэш-значения. Хотя это требование и не является обязательным, следует учитывать, что его выполнение положительно повлияет на производительность работы хэш-таблиц.

String, StringBuffer и StringBuilder

Вопросы:

  • В чём отличия String, StringBuffer и StringBuilder, почему не хватило только String?

Грейды:

  • Junior: Не знает отличия.
  • Middle: Использовал.
  • Senior: Может полностью рассказать отличия.

Подсказка:

Строки в Java реализованы в виде объектов класса String. Они финализированы и неизменяемы, вследствие этого при любых манипуляциях с ними всегда создается новая строка, что делает работу со строками весьма ресурсоёмким процессом. Если строки необходимо часто менять, то для этого есть StringBuffer и StringBuilder.

  • String – неизменяемая строка.
  • StringBuffer — потокобезопасная изменяемая строка.
  • StringBuilder – изменяемая строка с высокой производительностью, но без синхронизации.

Типы ссылок

Вопросы:

  • Про типы ссылок должны были спрашивать на скрининге. Здесь стоит спросить чем они отличаются.

Грейды:

  • Junior: Strong
  • Middle: + Weak, Soft
  • Senior: + Phantom

Подсказка:

  • Любой объект что имеет strong ссылку запрещен для удаления сборщиком мусора.
  • Когда на объект указывают ссылки WeakReferences, то удаление объекта может произойти в любой момент.
  • Когда на объект указывают ссылки SoftReferences, то удаление объекта происходит, когда JVM сильно нуждается в памяти.
  • PhantomReference может быть собрана сборщиком мусора, если на объект нет сильных (Strong), слабых ссылок (WeakReference) или мягких (SoftReference). PhantomReference может использоваться в ситуациях, когда использование finalize() не имеет смысла. Этот ссылочный тип отличается от других типов, поскольку он не предназначен для доступа к объекту. Он является сигналом о том, что объект уже финализирован и сборщик мусора готов вернуть свою память. Для этого сборщик мусора помещает его в специальный ReferenceQueue для последующей обработки. ReferenceQueue — это место, куда помещаются ссылки на объекты для освобождение памяти.

Процесс выделения и освобождения памяти в Java

Вопросы:

  • Расскажите примерно как работает GC.
  • Что такое куча и стэк?
  • Какие бывают GC roots?

Грейды:

  • Junior: Примерно знает как работает GC.
  • Middle: Может рассказать про Heap и Stack (куча и стэк).
  • Senior: Может рассказать про GC Root.

Подсказка:

  • Heap (куча) используется всеми частями приложения, а Stack используется только одним потоком исполнения программы.
  • Новый объект создается в Heap, а в памяти Stack'a размещается ссылка на него. В памяти стека также размещаются локальные переменные примитивных типов.
  • Объекты в куче доступны из любого места программы, в то время, как стековая память не доступна для других потоков.
  • Если память стека полностью занята, то Java Runtime вызывает исключение java.lang.StackOverflowError, а если память кучи заполнена, то вызывается исключение java.lang.OutOfMemoryError: Java Heap Space. -Размер памяти стека, как правило, намного меньше памяти в куче. Из-за простоты распределения памяти (LIFO), стековая память работает намного быстрее кучи.

Основа работы следующая: GC помечает объекты, на которые больше не ссылаются другие объекты для их удаления. Затем на одном из проходов помеченные объекты удаляются.

GC roots:

  • Основной Java поток.
  • Локальные переменные в основном методе.
  • Статические переменные основного класса.

Многопоточность

Вопросы:

  • Что такое synchronized?
  • Что произойдет если добавить модификатор synchronized к static методу?
  • Что такое DeadLock, Race Condition?
  • Для чего нужен volatile?

Грейды:

  • Junior: Знает про synchronized блоки и методы.
  • Middle: Может рассказать про static synchronized, Atomic примитивы.
  • Senior: Может рассказать про Concurrent Collections, volatile, DeadLock, Race Condition.

Подсказка:

Race Condition - с несколькими потоками, при работе с одними данными, в результате чего сами данные становятся непредсказуемыми и зависят от порядка выполнения потоков.

DeadLock - ситуация в многопоточной системе, при которой несколько потоков находятся в состоянии бесконечного ожидания ресурсов, занятых самими этими потоками

Синхронизация достигается в Java использованием зарезервированного слова synchronized. Вы можете использовать его в своих классах, определяя синхронизированные методы или блоки. Вы не сможете использовать synchronized в переменных или атрибутах в определении класса.

Блокировка на уровне объекта-это механизм, когда требуется синхронизировать нестатический метод или нестатический блок кода таким образом, чтобы только один поток мог выполнить блок кода на данном экземпляре класса. Это всегда должно быть сделано, чтобы сделать потокобезопасными данные уровня экземпляра.

Блокировка уровня класса предотвращает ввод нескольких потоков в синхронизированный блок в любом из всех доступных экземпляров во время выполнения. Это означает, что если во время выполнения есть 100 экземпляров DemoClass, то только один поток сможет выполнить demoMethod() в любом из экземпляров одновременно, а все остальные экземпляры будут заблокированы для других потоков.

Volatile запрещает помещать значение переменной в кэш. Ключевое слово volatile указывается для поля для того, чтобы указать компилятору, что все операции присвоения этой переменной и все операции чтения из неё должны быть атомарными. Более того, присвоение значения этой переменной имеет связь happens-before (произошло-до) для последующих чтений из этой переменной для любых потоков, то есть после присвоения нового значения переменной все потоки увидят это новое значение.

Дело в том, что Java позволяет потокам в целях производительности сохранять локальные копии переменной для каждого потока, который её использует (например в кешах или регистрах процессора). В таком случае после записи другим потоком нового значения в исходную переменную, первый поток будет видеть свою локальную копию со старым значением.

Использование ключевого слова volatile гарантирует, что все потоки всегда будут использовать общее, исходное значение, и они будут видеть изменения этого исходного значения другими потоками сразу же. Аналогично все изменения переменных, произошедшие внутри sychronized-методов и synchronized-блоков, а также блоков с другими блокировками вроде реализаций интерфейса java.util.concurrent.locks.Lock после выхода из блокировки будут гарантировано видны любым другим потокам после взятия блокировки над тем же самым объектом, но если более сложные блокировки не нужны, то можно использовать volatile.

Java Generics

Вопросы:

  • Что ты знаешь про дженерики, зачем они нужны?
  • Что такое Стирание типов?
  • Что такое Wildcard?

Грейды:

  • Junior: Может объяснить как использовать generics.
  • Middle: Знает концепцию Type Erasure.
  • Senior: Знает Wildcard.

Подсказка:

После компиляции какая-либо информация о дженериках стирается. Это называется "Стирание типов" или "Type Erasure". Стирание типов и дженерики сделаны так, чтобы обеспечить обратную совместимость со старыми версиями JDK, но при этом дать возможность помогать компилятору с определением типа в новых версиях Java.

Wildcard:

  • Upper Bounded Wildcards - <? extends Number>
  • Unbounded Wildcards - <?>
  • Lower Bounded Wildcards - <? super Integer>

Очень объёмная тема, советую прочитать статью

Kotlin

Вопросы:

  • Какие преимущества для тебя предоставляет Kotlin?
  • Что ты знаешь про open, object, extension, data class, sealed class.
  • Как происходит работа с коллекциями? Есть ли накладные расходы? Зачем придумали Sequence?

Грейды:

  • Junior: Может рассказать что нравится.
  • Middle: Может рассказать про open, object, extension, data class.
  • Senior: Может рассказать про sealed class, Collection/Sequence.

Подсказка:

Модификатор open: По умолчанию класс всегда наследуется от Any (аналог Object в Java) и является закрытым (final) (в Java по умолчанию открыты). В этом случае нельзя наследоваться от него. Но мы можем наследоваться от другого конкретного класса, который явно объявлен как open или abstract.Также добавьте модификатор open ко всем свойствам и методам, которые можно переопределять.

Data классы с дефолтными значениями аргументов. Больше не нужны громадные классы-модели. Просто описываете конструктор и всё — toString, getter/setter, equals/hashCode будут сгенерированы автоматически и невидимо.

Модификатор object С его помощью можно реализовать шаблон “Одиночка». Ключевое слово object одновременно объявляет класс и создаёт его экземпляр. Также можно реализовать объект-компаньон, содержащий лишь фабричные методы, а также методы, связанные с классом, но не требующие обращения к его экземпляру. К членам такого объекта можно обращаться просто по имени класса. Ещё можно использовать для записи объекта-выражения в качестве замены анонимного внутреннего класса.

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

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

Kotlin Coroutines

Вопросы:

  • Что такое корутины?
  • Расскажи про основные составляющие?
  • Как работает корутина под капотом?

Грейды:

  • Junior: Может примерно рассказать про корутины.
  • Middle: Может рассказать про CoroutineScope, CoroutineContext, Job, Dispatchers, обработка ошибок.
  • Senior: Может рассказать про жизненный цикл Job, SupervisorJob, как отменить корутину.

Подробнее: coroutines-overview

Context

Вопросы:

  • Какие виды Context знаешь, в чём отличия?

Грейды:

  • Junior: Может в общем рассказать.
  • Middle: Знает отличия Application Context и Activity Context.
  • Senior: Знает про BaseContext.

Подсказка:

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

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

BaseContext: связан с ContextWrapper, который создается вокруг существующего контекста и позволяет нам изменять его поведение. С помощью getBaseContext () мы можем получить существующий контекст внутри класса ContextWrapper. + для декорирования UI

Fragment

Вопросы:

  • Что такое Fragment и чем отличается от Activity?
  • Расскажи про жизненный цикл Fragment.
  • Расскажи как фрагмент сохраняется в FragmentManager. Как происходит восстановление фрагмента после смены конфигурации.

Грейды:

  • Junior: Может немного рассказать про жизненный цикл.
  • Middle: Понимает жизненный цикл. Может рассказать про Retain фрагменты.
  • Senior: Может рассказать как фрагмент сохраняется в FragmentManager. Как происходит восстановление фрагмента после смены конфигурации.

Подсказка:

onAttach(), onCreate(), onCreateView(), onActivityCreated() , onStart(), onResume(), onPause(), onStop(), onDestroyView(), onDestroy(), onDetach()

При вызове setRetainInstance(true) фрагмент не уничтожается вместе с его хостом и передается новому Activity в не измененном виде. При сохранении фрагмента можно рассчитывать на то, что все его поля (включая View) сохранят прежние значения.

Подробнее про Fragment

Кастомные View

Вопросы:

  • Как создавать кастомные View?
  • В чём отличия View и ViewGroup?
  • Что такое RenderScript?

Грейды:

  • Junior: Знает, что нужно отнаследоваться от View.
  • Middle: Знает цикл вызова элементов при изменении контента View; отличия View и ViewGroup; как добавить кастомные атрибуты.
  • Senior: RenderScript

Подсказка:

Статья про кастомные View

Средства асинхронной работы в Android

Вопросы:

  • Какие средства асинхронной работы в Android ты знаешь?
  • Что такое Service? В чём отличия от IntentService?
  • Как связаны Thread и ThreadPool?

Грейды:

  • Junior: AsyncTask, RxJava, Kotlin Coroutines
  • Middle: Thread, Loader, Service
  • Senior: ThreadPool, ExecutorService, AsyncTask (должен знать что на все таски исп. 1 поток), IntentService (должен знать про 1 поток), Ограничения сервисов в android 8

Подсказка:

Рекомендую цикл статей по фоновой работе: Часть1 Часть2 Часть3 Часть4 Часть5

Способы сохранения данных

Вопросы:

  • Что такое SharedPreferences?
  • Что такое ContentProvider?
  • Какие ORM и NoSQL решения ты знаешь? Плюсы/минусы?

Грейды:

  • Junior: Может в общих чертах рассказать про SharedPreferences (+как выглядят на диске) и SQLite.
  • Middle: Может рассказать про ContentProvider; может что-нибудь рассказать про ORM или NoSQL.
  • Senior: Имеет аргументированное мнение по поводу различных ORM и NoSQL.

Подсказка:

Shared Preferences - относительно постоянное хранилище данных, которое позволяет хранить пары ключ – значение. Представляет собой xml файл, в котором можно хранить такие типы как: float, int, long, boolean, String, множество, параметризованное по String.

ContentProvider – сущность, позволяющая инкапсулировать хранилище данных. Используются для организации шаринга между приложениями.

Можно накинуть про ORMLite, GreenDAO, Room, Realm, в целом, что кандидат думает про SQLite

Тестирование приложений

Вопросы:

  • Тестируешь код? Как?

Грейды:

  • Junior: Что-то слышал, знает что надо, но сам не тестировал.
  • Middle: Писал unit тесты. Может рассказать тестировать RxJava/KotlinCoroutines.
  • Senior: Писал UI тесты. Может рассказать про разные фреймворки.

Подсказка:

  • RxJava: через RxJavaPlugins установить все Schedulers как trampoline(), использовать test()
  • Coroutines: Переопределить Dispatchers и использовать runBlocking Подробнее UI: Espresso, UI Automator, Kakao, Kaspresso

Serializable и Parcelable

Вопросы:

  • В чём отличия и зачем придумали Parcelable?

Грейды:

  • Junior: Знает что для какой платформы.
  • Middle: Может рассказать подробнее.
  • Senior: Имеет аргументированное мнение, что лучше использовать. Может рассказать про Parcelize.

Подсказка:

Serializable — интерфейс стандартной Java библиотеки. Его очень просто имплементировать, но он бьёт по скорости, так как использует рефлексию и создаёт большое количество временных объектов.

Parcelable явно описывает процесс сериализации без использования рефлексии. В добавок было проведено немало оптимизаций кода, чтобы повысить производительность. Но необходимо писать большое количество boilerplate кода.

На маленьких объектах можно забить на Parcelable и использовать Serializable, т.к. выигрыша в скорости не видно. Но есть котлин плагин android-extentions. Подробнее про @Parcelize

Архитектура приложения

Вопросы:

  • Расскажи какие архитектуры знаешь, плюсы/минусы.

Грейды:

  • Junior: Всё на Activity.
  • Middle: MVC, MVP, MVVM.
  • Senior: Понимает различия, имеет аргументированное мнение.

Подсказка:

Model View Controller — Model получает входные данные от контроллера и решает, какие данные необходимы для выполнения запроса, выданного контроллером. Модель также может выполнять транзакции с базами данных или другим постоянным хранилищем по мере необходимости. Как только он собирает необходимую информацию, он информирует представление (через контроллер) о новых данных, вызывая соответствующие события. View содержит элементы управления пользовательского интерфейса, необходимые конечному пользователю для� взаимодействия с приложением. Его задача — отслеживать жесты конечного пользователя и передавать его контроллеру для дальнейшей обработки. View обрабатывает уведомление о событии, полученное от Модели, и может запрашивать любые новые данные, необходимые для его отображения на экране. Однако в некоторых вариантах контроллер может быть назначен для получения набора данных из модели, форматирования и отправки его в представление. Здесь задача View состоит в том, чтобы визуализировать данные без какой-либо другой обработки. Контроллер можно представить как расширение или личный помощник View, все события, происходящие из View, обрабатываются контроллером. Контроллер также проинформирует Model от имени View о том, что в представлении произошло какое-то событие и могут потребоваться некоторые новые данные.

Model-View-Presenter — Каждое View должно реализовывать соответствующий интерфейс. Интерфейс IView определяет набор функций и событий, необходимых для взаимодействия с пользователем (например, IView.ShowErrorMessage(string msg)). Презентер должен иметь ссылку на реализацию соответствующего интерфейса, которую обычно передают в конструкторе. Логика представления должна иметь ссылку на экземпляр презентера. Все события представления передаются для обработки в презентер и практически никогда не обрабатываются логикой View (в т.ч. создания других View).

Model-View-View Model — Данный подход позволяет связывать элементы View со свойствами и событиями View-модели. Можно утверждать, что каждый слой этого паттерна не знает о существовании другого слоя. View-модель — это абстракция View. Обычно означает, что свойства View совпадают со свойствами View-модели. View-модель не имеет ссылки на интерфейс представления (IView). Изменение состояния View-модели автоматически изменяет View и наоборот, поскольку используется механизм связывания данных (Bindings).

Model-View-Intent — Это такой шаблон проектирования, в котором Модель (Model) является активным компонентом, принимающим на вход Намерения (Intents) и производящая Состояния (State). Представление (View) в свою очередь принимает Модели Представления (View Model) и производит те самые Намерения. Состояние преобразуется в Модель Представления при помощи функции-трансформера (View Model Mapper).

Советую небольшую статью с архитектурами.

Clean Architecture

Вопросы:

  • Что это такое?
  • Какие слои выделишь?

Грейды:

  • Junior: Знает какие слои есть
  • Middle: Постоянно использует в работе, может рассказать зачем это всё.
  • Senior: Имеет мнение про маппинг между слоями, может подробно рассказать как обработать ошибку при REST запросе.

Подсказка:

Data, Domain, View - по классике. Можно спросить про UseCase и Interactor.

Принципы SOLID

Вопросы:

  • Что такое Принципы SOLID?
  • Можешь рассказать про них?

Грейды:

  • Junior: Знает, что они есть.
  • Middle: Может расшифровать аббревиатуру и сказать пару слов.
  • Senior: Отлетает от зубов. Рассказ переходит в мини лекцию по архитектуре.

Подсказка:

  • S - Принцип единственной ответственности (single responsibility principle) Для каждого класса должно быть определено единственное назначение. Все ресурсы, необходимые для его осуществления, должны быть инкапсулированы в этот класс и подчинены только этой задаче.
  • O - Принцип открытости/закрытости (open–closed principle) «программные сущности … должны быть открыты для расширения, но закрыты для модификации»
  • L - Принцип подстановки Лисков (Liskov substitution principle) «объекты в программе должны быть заменяемыми на экземпляры их подтипов без изменения правильности выполнения программы». См. также контрактное программирование. Производный класс должен быть взаимозаменяем с родительским классом.
  • I - Принцип разделения интерфейса (interface segregation principle) «много интерфейсов, специально предназначенных для клиентов, лучше, чем один интерфейс общего назначения».
  • D - Принцип инверсии зависимостей (dependency inversion principle) «Зависимость на Абстракциях. Нет зависимости на что-то конкретное».

Dependency Injection

Вопросы:

  • Что такое Dependency Injection?
  • Каким способом мы можем внедрить зависимость?
  • Расскажи про фреймворки, плюсы/минусы.

Грейды:

  • Junior: Знает про концепцию, но толком рассказать не может.
  • Middle: Может рассказать про injection через конструктор, сеттеры.
  • Senior: Может аргументированно рассказать разные фреймворки. Может порассуждать о "кодогенерация против Reflection в Runtime".

Подсказка:

Можно спросить, что кандидат думает про Dagger2, Koin, Kodein. Dagger2 очень громоздкий, но позволяет проверять граф зависимостей на этапе компиляции. Koin и Kodein легкие и "Kotlin-style" фреймворки, но граф проверяется в рантайме.

RxJava

Вопросы:

  • Какие виды Observable бывают? В чём отличия?
  • Что такое Subject? Какие бывают?
  • Отличия map(), flatMap(), concatMap(), switchMap?

Грейды:

  • Junior: Знает отличия Observable и Single.
  • Middle: Знает отличия Observable, Flowable, Single, Completable, Maybe.
  • Senior: Может рассказать про типы Subject; отличия map(), flatMap(), concatMap(), switchMap.

Подсказка:

Completable фактически является Rx-аналогом Runnable. Он представляет собой операцию, которая может быть выполнена или нет. Если проводить аналогию с Kotlin, то это fun completable() из мира Rx. Соответственно, для подписки на него необходимо реализовать onComplete и onError. Он не может быть создан из значения (Observable#just, ...), потому что не рассчитан на это.

Single — реактивный Callable, потому что тут появляется возможность вернуть результат операции. Продолжая сравнение с Kotlin, можно сказать, что Single — это fun single(): T { }. Таким образом, чтобы подписаться на него, необходимо реализовать onSuccess(T) и onError.

Maybe — нечто среднее между Single и Completable, потому что поддерживает одно значение, отсутствие значений и ошибку. Тут сложнее провести однозначную параллель с методами, но я думаю, что Maybe — это fun maybe(): T? { }, которая возвращает null, когда результата нет. Несложно догадаться, что для подписки потребуется определить onSuccess(T), onComplete и onError.

Observable — наиболее часто встречающийся источник, что обусловлено его универсальностью. Он умеет как не производить события вообще, так и генерировать множество таковых, поэтому его можно использовать всегда, когда не подходят остальные варианты. Несмотря на это, у Observable есть недостаток — он совершенно не умеет обрабатывать backpressure. Для подписки на него нужны onNext(T), onError и onComplete.

Flowable — источник, предоставляющий дополнительные операторы для обработки backpressure. Когда требуется обрабатывать более 10000 событий, происходящих быстро одно за другим, рекомендуется использовать его вместо Observable.

AsyncSubject держит последнее событие до корректного завершения потока, после чего отдаёт его подписчикам. При возникновении ошибки никакие события проброшены не будут.

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

BehaviorSubject работает аналогично PublishSubject, но при подписке возвращает последнее событие, если оно есть и если Subject не перешёл в терминальное состояние.

ReplaySubject— BehaviourSubject на стероидах. Возвращает не одно последнее событие, а сколько душе угодно. Если подписаться на завершённый ReplaySubject или ReplayProcessor, то будут получены все накопленные данные.

  • Map к каждому излучаемому элементу применяет функцию и возвращает ее результат.
  • FlatMap так же применяет функцию к каждому излучаемому элементу, но эта функция функция возвращает тип Observable. Т.е. 1 излучаемый элемент может через flatMap породить множество излучаемых элементов или не одного.
  • SwitchMap Как flatMap, но он будет испускать только элементы из нового наблюдаемого, пока очередное новое событие не будет испущено из источника наблюдаемого.
  • ConcatMap также подписывается на внутренний Observable. Но в отличие от switchMap, который отписывается от текущего Observable, если появляется новый Observable, concatMap не будет подписываться на следующий Observable, пока не завершится текущий.

Задачи

  • Написать функцию которая считает факториал числа передаваемого в качестве параметра.
  • Написать функцию которая проверяет является ли число простым. Простое число - число которое делится без остатка только на себя и на единицу(напр. “3”, “11”, “29”).
  • Бинарный поиск числа в упорядоченном массиве.
  • Вывести n-ое число из последовательности Фибоначчи.
  • Написать функцию которая проверяет является ли слово палиндромом. (Палиндром - слово которое читаеся в обе стороны, напр. “шалаш”).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment