Хабрахабр

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

image

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

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

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

Секция Core:

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

    • 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? (**)
    Краткий ответ

    • Строка в виде литерала сразу раскрывает пароль, плюс она всегда хранится в 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 — иммутабельный байтовый массив
    • StringBuilder — helper-класс для построения строк, не предоставляет гарантий синхронизации
    • StringBuffer — то же, что и 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 вместо WeakHashMap для кэширования чего-нибудь большого, например картинок ваших товаров, пользователей и.т.д в. Т.к ссылки на ключи сильные (strong references), значения по этим ключам будут висеть в хипе до морковкиного заговенья следующей перезагрузки jvm процесса или удаления ключа из мапы и обнуления ссылки на него. Вообще, кэширование — тема для отдельного разговора
    • Также, статья (но староватая)
  • Как вернуть псевдо-случайную последовательность целых чисел/чисел с плавающей запятой? (**)
  • В чем проблемы Random? (**)
    Краткий ответ

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

    Виды GC:

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

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

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

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

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

    Optional — интерфейс, предохраняющий пользовательский код от 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 может возникнуть, если нужной библиотеки с этим классом нет в classpath
    • NoSuchMethodError может возникнуть из-за несовместимости ваших библиотек, если зависимая библиотека 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
  • 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 из другого треда? (***)
  • ReentrantLock (**)
    Краткий ответ

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

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

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

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

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

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

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

  • Создание singleton? (**)
    Краткий ответ

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

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

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

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

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

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

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

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

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

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

    Частности ThreadPoolExecutor:

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

Секция Collections:

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

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

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

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

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

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

    • Hashtable — legacy, thread safe, методы синхронизированы, поэтому работа с Hashtable (обращение, удаление, добавление) в целом накладнее
    • HashMap — не 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, зачем он нужен (**)
    Краткий ответ

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

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

    Быть согласованным с equals()

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

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

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

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

    • Queue — коллекция, предоставляющая возможности упорядочения элементов в порядке вставки согласно принципу FIFO. Поддерживает два набора операций добавления/удаления/взятия элемента с конца — с возвращением спец. значения при исключительной ситуации (пустая или заполненная очередь), и с киданием exception'а
    • Deque — коллекция, предоставляющая возможность вставки значений в начала и в конец, позволяющая организовать очереди по принципам FIFO/LIFO. Предпочтительна для реализации стэка вместо Stack. Ниже приведен набор операций для Deque:
    • BlockingQueue — очередь, блокирующая операции чтения take при пустой очереди или операции записи put при полной очереди. Есть наборы операций и с неблокирующей семантикой. Ниже определен полный список операций чтения/записи.
    • ArrayBlockingQueue — кольцевой 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 — очередь, в которой элементы добавляются в связанный список, основанная на two-lock queue, описанного в статье Simple, Fast, and Practical Non-Blocking and Blocking Concurrent Queue Algorithms by Maged M. Michael and Michael L. Scott.

Секция IO:

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

    Далее, для краткости InputStream — is, OutputStream — os
    is — побайтное чтение из сокета/файла/строки/другого байтового массива
    os — побайтная запись в сокет/файл/другой байтовый массив
    Buffered-версии нужны для оптимизации чтения/записей через отдельный буффер

  • Зачем нужен Reader? (*)
    Краткий ответ

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

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

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

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

    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. Утечки памяти — статья на TopTal.com
  2. Частичная реализация ConcHashMap (аля Java 8) с нуля от kuptservol
  3. Структура SkipList
  4. Обзор коллекций от JournalDev
  5. Обзор коллекций от vedenin1980
  6. Обзор пакета java.util.concurrency (Java 7) от Melnosta
  7. Simple, Fast, and Practical Non-Blocking and Blocking Concurrent Queue Algorithms by Maged M. Michael and Michael L. Scott (для сильных духом)
Теги
Показать больше

Похожие статьи

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть