- PVSM.RU - https://www.pvsm.ru -

Вопросы к собеседованию Java-backend, Java core (60 вопросов)

image

Добрый день! Представляю вашему вниманию список вопросов к собеседованию Java Backend, которые я оформлял на протяжении около 2х лет.

Вопросы разбиты по темам: core, collections, concurrency, io, exceptions, которые задают основные направления хода технического собеседования. Звездочками отмечен субъективный (с точки зрения автора) уровень сложности вопроса, в сноске спойлера — краткий ответ на вопрос. Ответ представляет для интервьювера правильное направления развития мысли кандидата.

Опросник не претендует на роль исчерпывающего средства оценки технических навыков кандидата, это скорее еще одна компиляция вопросов и тем по Java и сопуствующим технологиям, принципам и концепциям разработки, коих в сети десятки. Она преследует цель собрать большое число технических вопросов, возникающих на собеседованиях, в удобном для читателей Хабра формате. Некоторые ответы следует воспринимать как мнемоники, «размечивающие» пространство поиска, так что глубже копать нужно уже в документации.
Также не стоит обращать внимание на слишком большое кол-во списков, так как это все-таки не вольное переложение авторских знаний с примесью литературной экспреcсии (что на хабре котируется и собирает аудиторию, особенно в пятницу). Этот список я составил для самого себя как способ структурировать основные тематики и типичные вопросы с собеседований, так что все дополнения и правки только приветствуются.
Это также не руководство к действию — не надо закидывать бедных кандидатов всеми вопросами из списка.

Секция Core:

  • Назвать методы Object [1]. (*)
    Краткий ответ

    • toString()
    • equals()
    • hashCode()
    • wait()
    • notify()
    • notifyAll()
    • finalize() — deprecated в Java 9+
    • getClass()

    Про toString(), equals(), hashCode() и их контракт знать нужно обязательно

  • Что такое string-pool? В чем отличие cоздания строки через new от литерала? Что такое String.intern()? (*)
    Краткий ответ

    string-pool — структура в памяти, хранящая массив всех строк-литералов программы.
    String.intern(), соотвественно, вернет строку из пула, при наличии таковой. Полезно при сравнениях вида:

    new String("hello").intern() == new String("hello").intern()

    Т.к без интернирования пришлось бы сравнивать строки через equals, что может быть медленнее при наличии длинных строк. В данном случае возвращается ссылка на один и тот же объект строки из пула, и проверка проходит с true.

  • Почему хранить пароль предпочтительнее в char[]/byte[], а не в String [2]? (**)
    Краткий ответ

    • Строка в виде литерала сразу раскрывает пароль, плюс она всегда хранится в string-пуле
    • byte[]/char[] возможно сбросить после использования, и удалить все ссылки на него
  • Привести пример плохой реализации hashCode() (*)
    Краткий ответ

    Метод, возвращающий константу, или значения хэшкодов с неравномерным распределением, приводящим к коллизиям
  • Примитивы, врапперы. Package/unpackage (boxing/unboxing). (*)
    Краткий ответ

    • Типы примитивы не создаются в куче, их жизненный цикл ограничен жизненным циклом стек-фрейма
    • Package — создание типа-обертки в хипе для аналогичного типа-примитива, например при объявлении аргумента как Integer, и при передаче int в качестве аргумента. Unpackage — обратная операция
  • Сравнение по == и по equals (*)
    Краткий ответ

    • Сравнение по "==" — сравнение по ссылкам
    • Сравнение по «equals» — если переопределен equals, то это сравнение эквивалентности объектов по их полям, если нет — по ссылкам на объекты
  • Свойства, которым должен удовлетворять equals (**)
    Краткий ответ

    • Рефлексивность: a==a
    • Симметричность: a==b, b==a
    • Транзитивность: a==b, b==c, a==c
    • Консистентность: Множественные вызовы equals должны возвращать один и тот же результат
  • Отличия String/StringBuilder/StringBuffer (**)
    Краткий ответ

    • String [2] — иммутабельный байтовый массив
    • StringBuilder [3] — helper-класс для построения строк, не предоставляет гарантий синхронизации
    • StringBuffer [4] — то же, что и StringBuilder, с synchronized методами
  • Приведите пример нарушения симметрии equals (**)
    Краткий ответ

    1. Создать класс Point2D c полями x,y: double
    2. Унаследовать от него класс ColoredPoint2D c доп. полем color
    3. a: Point2D
    4. b: ColoredPoint2D
    5. a.equals(b), !b.equals(a)
  • Interface vs Abstract Class. (*)
    Краткий ответ

    • Интерфейс есть средство наследования API, абстрактный класс — средство наследования реализации
    • Через интерфейсы возможно осуществлять множественное наследование, абстрактный класс можно наследовать в одном экземпляре.
    • В интерфейсе нет возможности определить поля и конструкторы
  • override vs overload (*)
    Краткий ответ

    • override — возможность переопределениия поведения метода в типах-потомках
    • overload — возможность переопределять метод с одним именем, но разным набором аргументов
  • Как в Java сделать утечку памяти? (**)
    Краткий ответ

    • Используя самописный класс стека, при выполнении операции pop() не присваивать предыдущей ссылке значение null.
    • Также можно неверно использовать HashMap [5] вместо WeakHashMap [6] для кэширования чего-нибудь большого, например картинок ваших товаров, пользователей и.т.д в. Т.к ссылки на ключи сильные (strong references), значения по этим ключам будут висеть в хипе до морковкиного заговенья следующей перезагрузки jvm процесса или удаления ключа из мапы и обнуления ссылки на него. Вообще, кэширование — тема для отдельного разговора
    • Также, статья [7] (но староватая)
  • Как вернуть псевдо-случайную последовательность целых чисел/чисел с плавающей запятой? (**)
    Краткий ответ

  • В чем проблемы Random [8]? (**)
    Краткий ответ

    Random [8] возвращает псевдо-случайную числовую последовательность, основанную на линейном конгруэнтном методе и seed'е, основанном на timestamp'е создания j.u.Random.
    Соотвественно, зная время создания, можно предсказать такую последовательность. Такой генератор является детерминированным, и криптографически нестойким. Для исправления этого лучше использовать SecureRandom [9]
  • GC и различные его виды в JVM. Какой объект считать достижимым. Как происходит сборка мусора (своими словами).(**)
    Краткий ответ

    Виды GC:

    • Serial Stop the World
    • Parallel
    • CMS (В чем недостаток по сравнению с Parallel?)
    • G1 (Назвать отличие от CMS)
    • Shenandoah

    Если объект является достижимым из стека или статической области, то он не поддается сборке мусора

  • Java 8: стримы, функциональные интерфейсы, Optional [10] (**)
    Краткий ответ

    Stream [11] — интерфейс, предоставляющий функциональные возможности обработки коллекций (filter, map, reduce, peek)
    Операции на стримах делятся на терминальные и нетерминальные. Нетерминальные операции модифицируют pipeline операций над коллекцией, при этом не изменяя саму коллекцию, терминальные (например, collect) — проводят действия pipeline'а, возвращают результат и закрывают Stream [11].

    FunctionalInterface [12] — аннотация, предоставляющая возможность использовать лямбды на месте интерфейсов (например, при передаче лямбды в качестве аргумента в метод)

    Optional [10] — интерфейс, предохраняющий пользовательский код от nullable ссылок. Оборачивает исходный nullable объект, и предоставляет возможность понять, хранит ли non-nullable объект или нет.

  • Java 8: Что такое capturing/non-capturing lambda (**)
    Краткий ответ

    • capturing lambda захватывает локальные переменные/аргументы/поля объекта из внешнего скоупа
    • non-capturing lambda — не захватывает контекст внешнего скоупа, не инстанцируется каждый раз при использовании
  • Новые возможности Java 9 — 11 (**)
    Краткий ответ

    • Новые методы в String
    • Java 9: Модульность
    • Java 9: Методы в Objects: requireNonNullElse() и requireNonNullElseGet()
    • Java 9: List.of(), Set.of(), Map.of(), Map.ofEntries()
    • Java 9: Optional.ifPresentOrElse(), Optional.stream()
    • Java 10: var type-inference
    • Java 11: Files.readString(), Files.writeString()
    • Java 11: Local-Variable Syntax for Lambda Parameters — выведение типов у var-аргументов в лямбда-параметрах
    • Java 11: JEP 321: HTTP Client

    Можно как бонус назвать какие-нибудь:

    • JEP 328: Flight Recorder
    • JEP 335: Deprecate the Nashorn JavaScript Engine
    • JEP 320: Remove the Java EE and CORBA Modules

    но это совершенно необязательно, покажет лишь вашу въедливость при чтении JDK'шных Release Notes :)

  • Swing: рассказать про EDT, как им пользоваться (**)
    Краткий ответ

    EDT — тред в котором производится обработка пользовательских действий на UI: движение курсора, нажатие клавиш, скролл, drag'n'drop и.т.д. Соотвественно, все «тяжелые» по времени и ресурсам операции нужно выносить в отдельный worker-тред (SwingUtils.invokeLater(...)), чтобы не фризить EDT.
  • Swing: перечислить все виды Layout, которые знаете (**)
    Краткий ответ

  • Generics: В чем преимущество, как работают? Что такое type-erasure? В чем отличие от шаблонов C++? (**)
    Краткий ответ

    • Типы дженерики обеспечивают параметрический полиморфизм, т.е выполнение идентичного кода для различных типов. Типичный пример — коллекции, итераторы
    • type-erasure — это стирание информации о типе-параметре в runtime. Таким образом, в байт-коде мы увидим List, Set вместо List<Integer>, Set<Integer>, ну и type-cast'ы при необходимости
    • В отличие от дженериков в Java, в С++ шаблоны в итоге приводят к компиляции метода или типа для каждого специфицированного типа параметра (специализация шаблона). Да простят меня здесь адепты С++.
  • Generics: Метод принимает ссылку на List<Parent>. Child наследуется от Parent. Можно ли в метод передать List<Child>? (**)
    Краткий ответ

    В типе аргумента нужно указать List<? extends Parent>
  • Generics: Ковариантность/контравариантность. Спросить про принцип PECS как бонус
    Краткий ответ

    • Ковариантность — List<? extends T>, если B extends T, то и List<B> extends List<T>
    • Контраваринтность — List<? super T>, если B super T, то и List<B> super List<T>
    • PECS — Producer-Extends-Consumer-Super, метод отдаёт ковариантный тип, принимает контравариантный (прим. автора — последнее интуитивно не очень понятно)

  • Регионы памяти в JVM (**)
    Краткий ответ

    Java 8: Metaspace, Old Generation, Young Generation (Eden Space/Survivor Space), Stack, Constant Pool, Code Cache, GC Area.
  • Hard-references, weak references, soft-references, phantom-references (***)
    Краткий ответ

    • Hard-references — стандартные ссылки на объекты, которые становится eligible for collection после недостижимости из root set
    • Weak-references — объекты могут быть удалены при наличии слабой ссылки на него в любое время
    • Soft-references — объекты могут удалятся GC при недостатке памяти
    • Phantom-references — объекты не доступны напрямую по ссылкам, перед удалением помещаются в очередь на удаление. Нужны для более безопасной финализации ссылок (вместо finalize)
  • Рассказать про classloader'ы и их иерархию. Из за чего, например, может возникать NoClassDefFoundError, NoSuchMethodError? (***)
    Краткий ответ

    Иерархия classloader'ов

    1. Bootstrap
    2. System
    3. Application

    • NoClassDefFoundError [17] может возникнуть, если нужной библиотеки с этим классом нет в classpath
    • NoSuchMethodError [18] может возникнуть из-за несовместимости ваших библиотек, если зависимая библиотека A вызывает метод из старой версии библиотеки B, но в classpath есть более новая версия библиотеки B, c другой сигнатурой этого метода

  • Какими способами можно сконструировать объект в Java? (**)
    Краткий ответ

    • Через конструктор
    • Через статический factory-method
    • Через паттерн Builder

  • Как идентифицируется класс в Java? (**)
    Краткий ответ

    По его FQDN и classloader'у
  • Bytecode: назовите какие-нибудь инструкции и опишите их (**).
    Краткий ответ

    Здесь только краткий список команд:

    • aload
    • aconst
    • astore

    * Попросить описать принцип действия стековой машины, как бонус. Допустим, на примере вызова метода.

  • Bytecode: invokevirtual, invokestatic, invokespecial — когда используются?
    Краткий ответ

    • invokevirtual — вызовы методов (в Java все методы виртуальные)
    • invokestatic — вызовы статических методов
    • invokespecial — вызовы конструкторов и приватных методов

Секция Concurrency:

  • synchronized. wait/notify/notifyAll. Как есть примитивы аналоги из пакета j.u.c? (**)
    Краткий ответ

    Дальше тезисы:

    • synchronized — ключевое слово, обозначающее скоуп критической секции. Можно ставить напротив объявления метода, или в виде блока в коде.
    • wait() — ожидание треда до тех пор, пока он не будет разбужен другим тредом через notify/notifyAll.
    • У wait() есть перегруженные версии с таймаутами.
    • Тред ставится в wait-set на объекте
    • Перед вызовом wait() нужно захватить монитор на данном объекте (через synchronized)
    • Магия wait() — он отпускает лок на мониторе объекта после вызова, так чтобы в дальнейшем другой тред мог захватить монитор и вызвать notify/notifyAll
    • notify() — будит один из ожидающих тредов, но Важно! — лок на объекте не отпускает, т.е ожидающий тред разбужен будет, но с ожиданием входа в критическую секцию объекта (т.к как будто остановился на synchronized). Так что если после notify есть тяжелые операции, это затормозит ожидающий тред, т.к тред с notify еще не отпустил монитор
    • notifyAll() — будут разбужены все треды в wait-set, но при этом далее между тредами происходит contention («сражение») за монитор
    • Тред на wait() может быть разбужен также через interrupt, или через spurious wake-up, или по таймауту
    • Так что условие выполнения, которого ожидает тред, проверяется в цикле while, а не в if
    • Примитив-аналог — Condition [19]
  • volatile. happens-before. (**)
    Краткий ответ

    • Ключевое слово volatile устанавливает отношение happens-before над операциями записи-чтения на поле
    • Таким образом, операции чтения из читающих тредов будут видеть эффекты записи пишущих тредов.
    • В частности, решается проблема double checked locking. Для double/long типов есть проблема атомарности, она решается через атомики
  • AtomicInteger, AtomicLong, AtomicBoolean, AtomicDouble (**)
    Краткий ответ

    • Атомики предоставляют возможность изменения переменной в нескольких потоках без эффекта гонок.
    • Например, 10 тредов инкрементят AtomicInt = 0, основной тред ждет их выполнения через countdown-latch, далее проверка атомика должна показать 10.
    • Основной механизм под капотом атомиков — цикл cas (compare-and-set). На примере increment:
      1. Читаем старое значение
      2. Перед set'ом проверяем старое значение, если оно не изменилось, сетаем старое + 1
      3. Если изменилось, в след. итерации получаем «новое» старое, далее см. п. 1

  • Редкий вопрос — как поймать exception из другого треда? (***)
    Краткий ответ

    Зарегистрировать Thread.UncaughExceptionHandler [20]
  • ReentrantLock [21] (**)
    Краткий ответ

    Примитив синхронизации, с помощью которого можно установить границы критической секции. Тред, перед входом в критическую секцию должен сделать захват c операцией lock(), после выхода из крит. секции — сделать unlock(). Другой тред в это время ожидает на lock'е (можно указывать таймаут ожидания), либо может проверить доступность через tryLock().

    ReentrantLock [21] обязательно нужно освобождать (такое кол-во раз, сколько раз он был захвачен), в противном случае будет thread starvation у других тредов, ожидающих у границы критической секции.
    ReentrantLock [21] может быть «честным» (fairness = true), тогда приоритет отдается тредам, ждущих на нем наибольшее кол-во времени, но это вроде как уменьшает производительность

    
    lock.lock();  // block until condition holds
    try {
    	// ... method body
    } finally { 
    	lock.unlock()
    }
    			
  • Countdown Latch [22]/Cyclic Barrier [23] (**)
    Краткий ответ

    CountdownLatch («защелка») — примитив синхронизации, с помощью которого, например, основной thread может ожидать выполнения работы остальных N тредов. Треды, выполняющие работу, выполняют countDown() на защелке, основной тред ожидает на операции await(). Когда счетчик достигает нуля, основной тред продолжает работу.

    Для синхронизации N тредов (все ждут всех) и переиспользования используется CyclicBarrier [23], ему также можно указывать действие (через Runnable), выполняемое после синхронизации всех-со-всеми

  • ThreadLocal [24] (**)
    Краткий ответ

    Класс, предоставляющий доступ к операциям get/set в области видимости треда. Под капотом содержит кастомную реализацию мапы со слабыми ссылками на ключи-треды. Каждый тред имеет доступ только к своим данным.
  • Создание singleton? (**)
    Краткий ответ

    • Наивным способом, с проверкой на null статического поля
    • Double checked locking [25] (объяснить проблемы double checked locking)
    • Простой — инициализация статического поля, или через enum, т.к ленивая инициализация thread-safe по-умолчанию
  • Способы запустить поток? (***)
    Краткий ответ

    • Переопределить Thread#run(), запустить через Thread#start()
    • new Thread(Runnable).start()
    • Через ExecutorService [26], используя utility-класс Executors [27]
  • ConcurrentHashMap [28] (**)
    Краткий ответ

    ConcurrentHashMap [28] имеет разные реализации в 1.7 и 1.8 (что стало для меня неожиданностью).
    Раньше параллелизм основывался на идее сегментирования хэштаблицы на основе заданного уровня параллелизма.
    Начиная с Java 8 — это единый массив бакетов с lock-free (локинг на первой ноде бакета с cas-циклом) и конкурентным ресайзингом.
    Частичная реализация ConcHashMap (аля Java 8) с нуля [29] от kuptservol [30]
  • ConcurrentSkipListMap [31]
    Краткий ответ

    Lock-free структура данных, хранящая упорядоченный набор элементов, с O(log N) временем доступа/удаления/вставки и weakly-consistent итераторами. Под капотом содержит структуру SkipList, предоставляющую собой слои связных списков, от верхнего к нижнему, элементы верхнего списка ссылаются на элементы нижнего списка под ними. Вероятность попадания элемента при вставке в самый нижний список — 1.0, далее она равняется p (либо 1/2, либо 1/4 как правило) — вероятности попадания элемента из нижнего списка в верхний. Таким образом, на самом верхнем будет вставлено минимальное кол-во элементов. Skiplist — вероятностная структура данных. Подробнее и доходчиво про skiplist описано здесь [32]. Полезна, если стоит задача отсортировать поток событий, одновременно читаемый несколькими тредами, которым нужно делать срез по временному интервалу. Более медленные операции по сравнению с ConcurrentHashMap [28]
  • Thread states (**)
    Краткий ответ

    • NEW
    • RUNNABLE
    • BLOCKED(monitor lock)
    • WAITING(Thread.join)
    • TERMINATED
  • Deadlocks, условия наступления, как избежать: (***)
    Краткий ответ

    • Условия наступления — эксклюзивность доступа к ресурсам, наличие циклов в графе ожиданий ресурсов, отсуствие таймаутов на ожидание
    • Как избежать — задать порядок доступа к ресурсам. Всегда обращение в порядке либо Thread1->Thread2, либо Thread2->Thread1
  • ThreadPoolExecutor [33] — описать механизм работы, св-ва, частности (fixed threadpool, scheduled, single thread executor) (***)
    Краткий ответ

    ThreadPoolExecutor [33] — средство контроля исполнения параллельных задач, задействует один из свободных тредов в общем пуле, или ставит задание в очередь, если таковых нет, или достигнуты определенные условия (ниже)

    Основными св-вами ThreadPoolExecutor [33] являются corePoolSize и maxPoolSize. Если текущее количество тредов в пуле < corePoolSize — новый тред будет создаваться в независимости от того, есть ли в пуле незанятые треды. В промежутке между corePoolSize и maxPoolSize тред будет создаваться в том случае, если заполнена очередь задач, и удаляться спустя keepAliveTime. Если кол-во тредов стало >= maxPoolSize — новые треды не создаются, а задачи ставятся в очередь.

    Есть возможность регулировать поведение очереди:

    • Direct handoffs: немедленная передача задачи тредпулу. Нет понятия очереди задачи. Если свободных тредов нет — кидается exception. Применимо при неограниченных maxPoolSize, но нужно понимать проблему при быстрых записях и медленных чтениях, что может спровоцировать непомерное потребление ресурсов
    • Unbounded queues: очередь без ограничений. Задачи будут добавляться в нее при превышении corePoolSize, при этом maxPoolSize будет игнорироваться. Unbounded queues имеют проблемы потребления ресурсов при больших нагрузках, но сглаживают рост тредов при пиках.
    • Bounded queues: очередь с ограничениями. Задачи будут добавляться в очередь до достижения некоего capacity. Для достижения наилучшей производительности нужно понимать размеры corePoolSize и самой очереди и чем можно пожертвовать — перфомансом (малый corePoolSize и большая очередь), или же памятью (ограниченная очередь, большой corePoolSize)

    Частности ThreadPoolExecutor [33]:

    • ScheduleThreadPoolExecutor [34] — применяется для периодичных по времени задач
    • fixed thread pool — частность ScheduleThreadPoolExecutor'а [33] с настроенным corePoolSize и unbounded queue
    • single thread executor — тредпулл, c сorePoolSize = 1, гарантирующий последовательное выполнение задач из очереди

Секция Collections:

  • Рассказать про java.util.collection. (*)
    Краткий ответ

    • Iterable [35] — реализуют коллекции, по которым можно проитерироваться
    • Сollection [36] — общий интерфейс для коллекций
    • List [37] (стандартная реализация ArrayList [38]) — список с массивом элементов, с возможностью случайного доступа элемента по индексу за O(1), вставкой/удалением со сложностью O(n)
    • Set [39] (стандартная реализация HashSet [40]) — мн-во элементов без дубликатов. Нет возможности доступа по индексу, есть вставка и удаление за O(1)
    • Map [41] (стандартная реализация HashMap [5]) — мн-во пар элементов «ключ-значение». Доступ по ключу/добавление/удаление за O(1) при оптимальном случае, O(n) — при вырожденном

    Обзор по коллекциям от JournalDev [42]

  • Устройство ArrayList [38], LinkedList [43], HashMap [5], HashSet [40]. Когда следует использовать. Контракт equals/hashcode для Map, Set (*)
    Краткий ответ

    Обзор по коллекциям от JournalDev [42]
  • Итератор по коллекции, его св-ва и интерфейс (*)
    Краткий ответ

    • Может только один раз проходить по коллекции. Для прохождения в двух направлениях есть ListIterator [44]
    • Если в foreach цикле структурно модифицировать коллекцию, при последующем обращению к элементу (неявно через итератор) получим ConcurrentModificationException [45] (fail-fast)
    • hasNext(), next() — основные методы
  • Hashtable [46] vs HashMap [5] (*)
    Краткий ответ

    • Hashtable [46] — legacy, thread safe, методы синхронизированы, поэтому работа с Hashtable (обращение, удаление, добавление) в целом накладнее
    • HashMap [5] — не thread-safe
  • Java 8,11: новые методы в Map (**)
    Краткий ответ

    • Java 8: compute
    • Java 8: computeIfAbsent
    • Java 8: computeIfPresent
    • Java 8: forEach
    • Java 8: putIfAbsent
    • Java 11: factory-методы of()
  • LinkedHashMap [47], зачем он нужен (**)
    Краткий ответ

    • Позволяет сохранять порядок вставки пар key-value в Map
    • Каждый entry содержит помимо hash, value, next (следующий элемент в бакете) также поля, указывающие на предыдущий и следующий элементы относительно порядка вставки
  • Устройство TreeMap [48] (**)
    Краткий ответ

    • Cбалансированное красно-черное дерево
    • Реализует интерфейс NavigableMap [49], что позволяет возвращать из него элементы, больше (меньше) указанного, либо range элементов, находящийся в определенных границах
  • Какой контракт Comparator [50] должен соблюдать?
    Краткий ответ

    Быть согласованным с equals()
  • Есть ли способ сделать enum ключом Map? (**)
    Краткий ответ

    EnumMap [51] — массив, по размеру соотвествующий кол-ву элементов в enum'е. Индекс элемента массива соотвествуют ordinal'у из enum'а
  • Расскажите про CopyOnWriteArrayList/CopyOnWriteHashSet [52] (**)
    Краткий ответ

    • СopyOnWriteArrayList [52] — иммутабельный list, при добавлении/апдейте/удалении элементов из которого пользователь получает новую модифицированную копию данного списка
    • СopyOnWriteHashSet [53] — иммутабельный set, при добавлении/апдейте/удалении элементов из которого пользователь получает новую модифицированную копию данного set'а
  • IdentityHashMap [54] — когда используется? (**)
    Краткий ответ

    IdentityHashMap [54] — используется, только если нужно проверять идентичность двух ссылок, а не эквивалентность двух объектов по ним. Например, если нужно отслеживать уже посешенные ноды в графе, или строить карту объекты-прокси. IdentityHashMap представляет из себя не классическую хэштаблицу со связанными списками, это linear probing map (бонус за объяснение работы linear probing)
  • Интерфейсы Queue [55]/Deque [56] и их реализации (***)
    Краткий ответ

    • Queue [55] — коллекция, предоставляющая возможности упорядочения элементов в порядке вставки согласно принципу FIFO. Поддерживает два набора операций добавления/удаления/взятия элемента с конца — с возвращением спец. значения при исключительной ситуации (пустая или заполненная очередь), и с киданием exception'а
    • Deque [56] — коллекция, предоставляющая возможность вставки значений в начала и в конец, позволяющая организовать очереди по принципам FIFO/LIFO. Предпочтительна для реализации стэка вместо Stack [57]. Ниже приведен набор операций для Deque:
      Вопросы к собеседованию Java-backend, Java core (60 вопросов) - 2
    • BlockingQueue [58] — очередь, блокирующая операции чтения take при пустой очереди или операции записи put при полной очереди. Есть наборы операций и с неблокирующей семантикой. Ниже определен полный список операций чтения/записи.
      Вопросы к собеседованию Java-backend, Java core (60 вопросов) - 3
    • ArrayBlockingQueue [59] — кольцевой bounded-buffer с внутренним capacity и fairness policy. Все операции чтения и записи защищены внутренним lock'ом (j.u.c.l.ReentrantLock), неявно связанным с двумя condition'ами — notFull, notEmpty. Соотвественно, если пишущий тред, захвативший общий lock, застрял на condition'е notFull, он неявно освобождает lock, чтобы читающий тред мог освободить очередь, и сигнализировать producer'у о том, что можно продолжать. Ровно и наоборот, читающий тред также захватывает общий lock, застревает на notEmpty, неявно освобождает lock, чтобы пишущий тред мог положить новый элемент и просигналить о непустой очереди. Т.е семантика такая же, как и у synchronized/wait/notify/notifyAll. Fairness = true позволяет предотвратить ситуации thread starvation для консьюмеров и продюсеров, но снизит производительность.
    • LinkedBlockingQueue [60] — очередь, в которой элементы добавляются в связанный список, основанная на two-lock queue, описанного в статье Simple, Fast, and Practical Non-Blocking and Blocking Concurrent Queue Algorithms by Maged M. Michael and Michael L. Scott.

Секция IO:

  • InputStream [61], OutputStream [62] и их buffered версии (*)
    Краткий ответ

    Далее, для краткости InputStream — is, OutputStream — os
    is — побайтное чтение из сокета/файла/строки/другого байтового массива
    os — побайтная запись в сокет/файл/другой байтовый массив
    Buffered-версии нужны для оптимизации чтения/записей через отдельный буффер
  • Зачем нужен Reader [63]? (*)
    Краткий ответ

    Reader позволяет указать Charset [64] при чтении
  • Serializable [65], serialVersionUID (*)
    Краткий ответ

    Классы, чьи объекты подвергаются сериализации/десериализации должны реализовывать marker интерфейс Serializable (и иметь статическое поле serialVersionUID для указании при сериализации, с какой версией класса данный объект был сериализован. Если serialVersionUID из сериализованного представления не совпадает c serialVersionUID класса «на том конце провода» — то кидается exception)

    На практике, уже довольно редко используется, т.к тем же Jackson/GSON не обязательно наличие данного интерфейса для сериализации

  • try-with-resources. AutoCloseable [66] (*)
    Краткий ответ

    try-with-resources — краткая замена стандартному try..catch..finally. Закрывает ресурс после выхода из секции try-with-resources. Ресурс должен имплементить интерфейс AutoCloseable.

    «Ресурс» в данном контексте — это класс, представляющий cобой соединение/cокет/файл/поток

    
    try (InputStream is = new FileInputStream("/path/to/file.txt")) {
    	...
    }
    			

Секция Exceptions:

  • Отличие checked-exception/unchecked-exception. Error, Exception, RuntimeException (*)
    Краткий ответ

    • Checked exceptions (проверяемые исключения). В JDK представлены классом Exception. Исключения, которые нельзя проигнорировать, их обязательно нужно обрабатывать, либо специфицировать в сигнатуре метода, для обработки выше. Как правило, считаются дурным тоном, т.к код со мн-вом конструкций try..catch плохо читабелен, к тому же добавление новых пробрасываемых исключений в сигнатуре метода может сломать контракт вызова у пользователей данного метода.
    • Unchecked exceptions (непроверяемые исключения). В JDK это класс RuntimeException. Можно игнорировать, не требуют обработки через try..catch, или указания в сигнатуре через throws. Минус такого подхода — у вызывающей стороны нет никакого понимания, как обрабатывать ситуацию, когда под капотом «рванет»
    • Error — ошибки, кидаемые JVM в результате нехватки памяти (OutOfMemoryError), переполнения стэка (StackOverflowError) и.т.д

Полезные ссылки:

  1. Утечки памяти [7] — статья на TopTal.com
  2. Частичная реализация ConcHashMap [29] (аля Java 8) с нуля от kuptservol [30]
  3. Структура SkipList [32]
  4. Обзор коллекций [42] от JournalDev
  5. Обзор коллекций [67] от vedenin1980 [68]
  6. Обзор [69] пакета java.util.concurrency (Java 7) от Melnosta [70]
  7. Simple, Fast, and Practical Non-Blocking and Blocking Concurrent Queue Algorithms by Maged M. Michael and Michael L. Scott (для сильных духом)

Автор: Олег

Источник [71]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/java/349010

Ссылки в тексте:

[1] Object: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/Object.html

[2] String: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/String.html

[3] StringBuilder: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/StringBuilder.html

[4] StringBuffer: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/StringBuffer.html

[5] HashMap: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/HashMap.html

[6] WeakHashMap: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/WeakHashMap.html

[7] статья: https://www.toptal.com/java/hunting-memory-leaks-in-java

[8] java.util.Random: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Random.html

[9] SecureRandom: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/security/SecureRandom.html

[10] Optional: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Optional.html

[11] Stream: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/stream/Stream.html

[12] FunctionalInterface: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/FunctionalInterface.html

[13] FlowLayout: https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/java/awt/FlowLayout.html

[14] GridLayout: https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/java/awt/GridLayout.html

[15] BoxLayout: https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/swing/BoxLayout.html

[16] BorderLayout: https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/java/awt/BorderLayout.html

[17] NoClassDefFoundError: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/NoClassDefFoundError.html

[18] NoSuchMethodError: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/NoSuchMethodError.html

[19] Condition: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/concurrent/locks/Condition.html

[20] Thread.UncaughExceptionHandler: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/Thread.UncaughtExceptionHandler.html

[21] ReentrantLock: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/concurrent/locks/ReentrantLock.html

[22] Countdown Latch: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/concurrent/CountDownLatch.html

[23] Cyclic Barrier: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/concurrent/CyclicBarrier.html

[24] ThreadLocal: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/ThreadLocal.html

[25] Double checked locking: https://ru.wikipedia.org/wiki/%D0%91%D0%BB%D0%BE%D0%BA%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0_%D1%81_%D0%B4%D0%B2%D0%BE%D0%B9%D0%BD%D0%BE%D0%B9_%D0%BF%D1%80%D0%BE%D0%B2%D0%B5%D1%80%D0%BA%D0%BE%D0%B9

[26] ExecutorService: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/concurrent/ExecutorService.html

[27] Executors: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/concurrent/Executors.html

[28] ConcurrentHashMap: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/concurrent/ConcurrentHashMap.html

[29] Частичная реализация ConcHashMap (аля Java 8) с нуля: https://habr.com/ru/post/327186/

[30] kuptservol: https://habr.com/ru/users/kuptservol/

[31] ConcurrentSkipListMap: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/concurrent/ConcurrentSkipListMap.html

[32] здесь: https://habr.com/ru/post/139870/

[33] ThreadPoolExecutor: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/concurrent/ThreadPoolExecutor.html

[34] ScheduleThreadPoolExecutor: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/concurrent/ScheduledThreadPoolExecutor.html

[35] Iterable: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/Iterable.html

[36] Сollection: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Collection.html

[37] List: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/List.html

[38] ArrayList: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/ArrayList.html

[39] Set: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Set.html

[40] HashSet: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/HashSet.html

[41] Map: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Map.html

[42] JournalDev: https://www.journaldev.com/1260/collections-in-java-tutorial

[43] LinkedList: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/LinkedList.html

[44] ListIterator: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/ListIterator.html

[45] ConcurrentModificationException: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/ConcurrentModificationException.html

[46] Hashtable: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Hashtable.html

[47] LinkedHashMap: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/LinkedHashMap.html

[48] TreeMap: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/TreeMap.html

[49] NavigableMap: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/NavigableMap.html

[50] Comparator: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Comparator.html

[51] EnumMap: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/EnumMap.html

[52] CopyOnWriteArrayList/CopyOnWriteHashSet: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/concurrent/CopyOnWriteArrayList.html

[53] СopyOnWriteHashSet: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/concurrent/CopyOnWriteHashSet.html

[54] IdentityHashMap: https://docs.oracle.com/javase/7/docs/api/java/util/IdentityHashMap.html

[55] Queue: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Queue.html

[56] Deque: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Deque.html

[57] Stack: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Stack.html

[58] BlockingQueue: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/BlockingQueue.html

[59] ArrayBlockingQueue: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ArrayBlockingQueue.html

[60] LinkedBlockingQueue: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/LinkedBlockingQueue.html

[61] InputStream: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/io/InputStream.html

[62] OutputStream: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/io/OutputStream.html

[63] Reader: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/io/Reader.html

[64] Charset: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/nio/charset/Charset.html

[65] Serializable: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/io/Serializable.html

[66] AutoCloseable: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/AutoCloseable.html

[67] Обзор коллекций: https://habr.com/ru/company/luxoft/blog/256877/

[68] vedenin1980: https://habr.com/ru/users/vedenin1980/

[69] Обзор: https://habr.com/ru/company/luxoft/blog/157273/

[70] Melnosta: https://habr.com/ru/users/melnosta/

[71] Источник: https://habr.com/ru/post/485678/?utm_source=habrahabr&utm_medium=rss&utm_campaign=485678