Java Interview Tasks
4.83K subscribers
212 photos
1 video
1 file
140 links
Реальные вопросы и задачи с собеседований.
Оригинальный авторский контент.
Актуальный материал.
Уровень вопросов от junior до supersenior.

Автор канала - @alexzelentsov

По рекламе: @alexzelentsov
Download Telegram
🔍 Ответ на задачу про Integer.MIN_VALUE: Математические странности 🧮
Диапазон int в Java — от -2,147,483,648 до 2,147,483,647. Заметьте, что отрицательных чисел на одно больше. При попытке вычислить -Integer.MIN_VALUE происходит переполнение, и число превращается... снова в Integer.MIN_VALUE!

Вывод:
Оба условия выведут true. Отрицание минимального значения int дает то же самое отрицательное число.

⚡️ Не перепутайте:
Всегда помните об асимметрии диапазона целых чисел в Java. Это частый источник багов при использовании Math.abs().

#java #int #overflow #math #basics #интервью #java_interview_tasks
❤7🔥2💯1👀1
🔍 Ответ на задачу про IdentityHashMap: Когда ссылки важнее значений 🔗

- HashMap использует equals() и hashCode() для сравнения ключей. Для "Java" и new String("Java") equals вернет true, поэтому в HashMap была бы 1 запись.

- IdentityHashMap использует оператор ==. Так как s1 и s2 — это разные объекты в памяти, мапа считает их разными ключами.

Вывод:
Размер мапы будет 2.

⚡️ Не перепутайте:
IdentityHashMap — редкий зверь. Она полезна, например, при сериализации графа объектов, чтобы не зациклиться, если два узла имеют одинаковое содержимое, но являются разными объектами.

#java #collections #hashmap #identityhashmap #internals #интервью #java_interview_tasks
🔥6👏2👍1
🔍 Ответ на задачу про Enum.values(): Скрытые аллокации 📦
Спецификация Java требует, чтобы массив, возвращаемый values(), был изменяемым (вы можете заменить в нем элементы, хотя это и плохая практика). Чтобы пользователи не могли испортить внутреннее состояние перечисления, компилятор генерирует код, который создает копию массива при каждом вызове values().

Вывод:
Каждый вызов values() — это новая аллокация памяти. В высокопроизводительном коде лучше кешировать этот массив: private static final Color[] VALUES = Color.values().

⚡️ Не перепутайте:
Если вам нужно просто получить количество элементов, используйте кешированное значение или Java 21 Enum.entries.

#java #enum #performance #jvm #memory #интервью #java_interview_tasks
👍7🔥1
🔍 Ответ на задачу про Iterator.remove(): Чистим коллекцию правильно 🧹
- Вариант A (for-each) использует итератор неявно. Если мы вызываем list.remove() напрямую, итератор об этом не знает и при следующей проверке modCount выбросит ConcurrentModificationException.
- Вариант B использует iterator.remove(). Этот метод специально спроектирован для безопасного удаления текущего элемента во время итерации.

Вывод:
Верный вариант — B. (Хотя есть исключение: в ArrayList удаление предпоследнего элемента через list.remove() в for-each может не вызвать ошибку из-за бага/особенности проверки hasNext(), но полагаться на это нельзя).

⚡️ Не перепутайте:
В Java 8+ самый простой и безопасный способ: list.removeIf(s -> s.equals("A")).

#java #collections #iterator #bug #clean_code #интервью #java_interview_tasks
👏5❤1🍌1
🔍 Ответ на задачу про LinkedHashMap: Порядок имеет значение 🔄
У LinkedHashMap есть специальный конструктор, где третий аргумент accessOrder включает режим "порядка доступа". Если он равен true, то при каждом get() или put() элемент перемещается в конец списка. Это идеальная основа для реализации LRU-кеша (Least Recently Used).

Вывод:
Так как мы обратились к ключу 2, он переместился в конец. Порядок станет: 1, 3, 2.

⚡️ Не перепутайте:
По умолчанию LinkedHashMap сохраняет порядок вставки (accessOrder = false).

#java #collections #linkedhashmap #lru #cache #интервью #java_interview_tasks
🔥8👍2👏1
🔍 Ответ на задачу про Наследование: Приватные методы не переопределяются 🛡
Приватные методы в Java не участвуют в полиморфизме. Они принадлежат только тому классу, в котором объявлены, и не могут быть переопределены (override). Когда метод test() вызывается у объекта Child, он ищется в Parent. Внутри test() вызывается print(), который в Parent помечен как private. Java связывает этот вызов статически именно с методом в Parent.

Вывод:
Напечатается "Parent". Метод print() в Child — это просто новый метод, который никак не связан с приватным методом родителя.

⚡️ Не перепутайте:
Если вы хотите, чтобы метод переопределялся, он должен быть как минимум protected.

#java #oop #inheritance #polymorphism #basics #интервью #java_interview_tasks
❤5👍3
🔍 Ответ на задачу про Static:

Статические методы привязаны к классу, а не к объекту. В Java нет полиморфизма для статики. Это называется method hiding. Какой метод вызовется, определяется типом переменной во время компиляции, а не типом объекта во время выполнения.

Вывод:
Так как переменная obj имеет тип A, вызовется A.staticMethod(). Результат: "A".

⚡️ Не перепутайте:
Никогда не вызывайте статические методы через экземпляры объектов (obj.method()). Всегда пишите ClassName.method(), чтобы не вводить в заблуждение.

#java #static #inheritance #basics #clean_code #интервью #java_interview_tasks
🔥6👍2🤔1
🔍 Ответ на задачу про Final поля: Безопасная публикация 🏗

Согласно JMM, поля final обеспечивают "гарантию заморозки". Если объект был правильно сконструирован (ссылка this не утекла во время работы конструктора), то любой поток, увидевший ссылку на этот объект, гарантированно увидит корректные значения всех его final полей.

Вывод:
При условии отсутствия "утечки" this в конструкторе , после создания объекта другой тред увидеть не может ничего кроме 5. Это одна из основ создания Immutable объектов в Java.

⚡️ Не перепутайте:
Обычные (не final) поля без синхронизации могут быть видны другим потокам в их дефолтном состоянии (например, 0 или null), даже если конструктор уже отработал.

#java #concurrency #jmm #final #multithreading #интервью #java_interview_tasks
🔥4
🔍 Ответ на задачу про Generics: Стирание типов (Type Erasure) 🧼
В Java дженерики реализованы через стирание типов. Это сделано для обратной совместимости с кодом до Java 5. Во время компиляции проверки проводятся, но в байт-коде вся информация о типах <String> и <Integer> удаляется, и оба списка превращаются в просто ArrayList (работающий с Object).

Вывод:
Оба списка принадлежат одному и тому же классу java.util.ArrayList. Результат: true.

⚡️ Не перепутайте:
Из-за стирания типов вы не можете сделать instanceof List<String> или создать массив дженериков new T[10].

#java #generics #jvm #internals #basics #интервью #java_interview_tasks
👌5👍1👏1
🔍 Ответ на задачу про Wildcards: List<Object> vs List<?> ❓
1. List<Object> не является родителем для List<String>. Несмотря на то, что String — это Object, сами коллекции инвариантны. Иначе мы могли бы положить Integer в список строк через ссылку на List<Object>.
2. List<?> (wildcard) — это родитель для любого List. Строка 2 верна.
3. В List<?> нельзя ничего добавлять (кроме null), так как мы не знаем, список какого типа там на самом деле.

Вывод:
Не скомпилируются строки 1 и 3.

⚡️ Не перепутайте:
List<Object> — это список, в который можно класть любые объекты.
List<?> — это список какого-то неизвестного типа, из него можно только читать.

#java #generics #wildcards #basics #интервью #java_interview_tasks
✍6👍4👏1
🔍 Ответ на задачу про PECS: Producer Extends, Consumer Super 🦆
Это правило PECS:
- Producer Extends: Если коллекция "производит" данные (мы из нее читаем), используйте extends. Мы гарантируем, что там лежат объекты типа T или его наследники, поэтому их безопасно приводить к T.
- Consumer Super: Если коллекция "потребляет" данные (мы в нее пишем), используйте super. Мы можем безопасно положить туда T. Но при чтении мы получим только Object, так как не знаем реального типа.

Вывод:
Верна только строка A.

⚡️ Не перепутайте:
List<? extends T> — только для чтения.
List<? super T> — в основном для записи.

#java #generics #pecs #clean_code #интервью #java_interview_tasks
🔥5
### 🧮 Задача: (7x−y)(7y−z)(7z−x) = 11, где x, y, z — целые числа

### Решение: 🚫

Ключевое наблюдение — посмотрим на чётность произведения (7x−y)(7y−z)(7z−x).

Сложим все три множителя:

(7x − y) + (7y − z) + (7z − x) = 6x + 6y + 6z = 6(x + y + z)

Сумма трёх множителей всегда чётна (кратна 6). Если сумма трёх целых чисел чётна, то среди них либо все три чётные, либо ровно два нечётных и одно чётное. В обоих случаях хотя бы один множитель — чётный. А значит, произведение (7x−y)(7y−z)(7z−x) всегда чётно при любых целых x, y, z.

Но 11 — нечётное число.

### Вывод:
Уравнение не имеет решений в целых числах.

#math #numbertheory #diophantine #интервью #java_interview_tasks
🤔6👍3🔥2
🔍 Ответ на задачу про Method References: Неоднозначность 😵‍💫
Ссылка Service::process может быть интерпретирована двумя способами:
1. Как вызов статического метода: (Service s) -> Service.process(s).
2. Как вызов обычного метода у текущего элемента: (Service s) -> s.process().
Обе интерпретации идеально подходят под сигнатуру Consumer<Service>, который ожидает forEach. Компилятор не знает, какой метод выбрать.

Вывод:
Возникает ошибка компиляции из-за неоднозначности.

⚡️ Не перепутайте:
В таких случаях используйте обычную лямбду s -> s.process(), чтобы явно указать нужный метод.

#java #lambda #methodreference #bug #интервью #java_interview_tasks
🔥5👍2👌1
🔍 Ответ на задачу про Stream.findFirst vs findAny: В чём разница? 🔍
- findFirst() жестко привязан к порядку следования (encounter order). В параллельном стриме он потратит время на то, чтобы убедиться, что вернул именно первый элемент.
- findAny() позволяет среде выполнения выбрать любой подходящий элемент. В параллельных стримах это работает гораздо быстрее, так как не нужно координировать потоки для соблюдения порядка.

Вывод:
В параллельном стриме findAny() может вернуть любой элемент, подходящий под условие. Если порядок не важен — используйте его для скорости.

⚡️ Не перепутайте:
В последовательном (sequential) стриме findAny() чаще всего тоже будет возвращать первый элемент, но спецификация этого не гарантирует.

#java #streamapi #parallel #performance #интервью #java_interview_tasks
👍6🔥1
🔍 Ответ на задачу про Stream.flatMap:
- map() превращает каждый элемент в другой элемент (1 -> 1). Если применить его здесь, мы получим стрим стримов: Stream<Stream<String>>.
- flatMap() превращает каждый элемент в стрим, а затем "склеивает" все эти стримы в один плоский Stream<String>.

Вывод:
Вместо двух вложенных списков мы получим один стрим из 3-х символов: "a", "b", "c". Результат count() — 3.

⚡️ Не перепутайте:
Используйте flatMap, когда ваш объект содержит коллекцию или Optional, и вы хотите работать с их содержимым напрямую.

#java #streamapi #flatmap #basics #интервью #java_interview_tasks
🔥2👌1
🔍 Ответ на задачу про Stream.reduce: Опасность identity 🚩
Первый аргумент reduce — это identity. Это значение, которое возвращается, если стрим пуст, и которое используется как начальное при вычислении.
Вычисление идет так: identity + element1 + element2...
В нашем случае: 10 + 1 + 2 + 3 = 16.

Вывод:
Напечатается 16. Если вы хотите просто сумму — identity должен быть 0. Если произведение — 1.

⚡️ Не перепутайте:
Identity должен быть нейтральным элементом для вашей операции. Для сложения это 0, для умножения 1, для конкатенации строк — пустая строка.

#java #streamapi #reduce #basics #интервью #java_interview_tasks
👍5❤1👌1
🔍 Ответ на задачу про LocalDate: Ловушка иммутабельности 📅
Классы из пакета java.time (LocalDate, LocalTime, etc.) — immutable (неизменяемые), как и String. Любой метод, который якобы "меняет" объект, на самом деле возвращает новый объект с измененным состоянием. Исходный объект date остается прежним.

Вывод:
Напечатается 1. Чтобы получить 11, нужно было написать date = date.plusDays(10).

⚡️ Не перепутайте:
Всегда проверяйте, что вы используете возвращаемое значение методов java.time. Это одна из самых частых ошибок при переходе со старого Calendar.

#java #datetime #immutable #bug #basics #интервью #java_interview_tasks
🔥6👏2❤1👍1