Библиотека собеса по Java | вопросы с собеседований
6.49K subscribers
412 photos
10 videos
647 links
Вопросы с собеседований по Java и ответы на них.

По рекламе: @proglib_adv

Учиться у нас: https://proglib.io/w/08c603b6

Для обратной связи: @proglibrary_feeedback_bot
Download Telegram
Расскажите о паттерне Iterator

Iterator — это поведенческий паттерн, который даёт возможность последовательно обходить элементы коллекции, не раскрывая её внутреннее устройство.

Простыми словами: вы проходите по элементам через «окошко» (hasNext / next), не зная — это массив, дерево или база данных за ним.

▪️ Пример:

Пагинация по результатам из БД: клиент обходит элементы как обычную коллекцию, а итератор незаметно подгружает следующую страницу.

class PaginatedIterator<T> implements Iterator<T> {
private final Function<Integer, List<T>> pageFetcher;
private final int pageSize;
private List<T> currentPage;
private int pageIndex = 0;
private int itemIndex = 0;

public PaginatedIterator(Function<Integer, List<T>> pageFetcher,
int pageSize) {
this.pageFetcher = pageFetcher;
this.pageSize = pageSize;
this.currentPage = pageFetcher.apply(0);
}

public boolean hasNext() {
if (itemIndex < currentPage.size()) return true;
if (currentPage.size() < pageSize) return false; // последняя страница

// Подгружаем следующую страницу
pageIndex++;
currentPage = pageFetcher.apply(pageIndex);
itemIndex = 0;
return !currentPage.isEmpty();
}

public T next() {
if (!hasNext()) throw new NoSuchElementException();
return currentPage.get(itemIndex++);
}
}

// Использование — клиент не знает про пагинацию
Iterator<User> users = new PaginatedIterator<>(
page -> userRepository.findAll(PageRequest.of(page, 50)).getContent(),
50
);

while (users.hasNext()) {
User user = users.next(); // подгрузка происходит автоматически
process(user);
}


▪️ Когда использовать

Нужен единый способ обхода для разных структур данных
Хотите скрыть сложность обхода (дерево, граф, пагинация)
В Java: все коллекции реализуют Iterable, что позволяет for-each

▪️ Минус

Для простых коллекций — избыточен; итератор может устареть при изменении коллекции (ConcurrentModificationException).

🐸 Библиотека собеса по Java

#patterns
Please open Telegram to view this post
VIEW IN TELEGRAM
👍31🔥1
Расскажите о паттерне Mediator

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

Простыми словами: диспетчер в аэропорту — самолёты не переговариваются друг с другом, а общаются через башню управления.

▪️ Пример:

Чат-комната: пользователи не отправляют сообщения друг другу напрямую — всё идёт через комнату, которая решает, кому доставить.

// Медиатор
interface ChatRoom {
void sendMessage(String message, User sender);
void addUser(User user);
}

class GroupChatRoom implements ChatRoom {
private final List<User> users = new ArrayList<>();

public void addUser(User user) {
users.add(user);
user.setChatRoom(this);
}

public void sendMessage(String message, User sender) {
users.stream()
.filter(u -> u != sender)
.forEach(u -> u.receive(message, sender.getName()));
}
}

// Коллега
class User {
private final String name;
private ChatRoom chatRoom;

public User(String name) {
this.name = name;
}

public void setChatRoom(ChatRoom room) {
this.chatRoom = room;
}

public void send(String message) {
chatRoom.sendMessage(message, this);
}

public void receive(String message, String from) {
System.out.println(name + " получил от " + from + ": " + message);
}

public String getName() { return name; }
}

// Использование
ChatRoom room = new GroupChatRoom();
User alice = new User("Alice");
User bob = new User("Bob");
User carol = new User("Carol");

room.addUser(alice);
room.addUser(bob);
room.addUser(carol);

alice.send("Привет всем!");
// Bob получил от Alice: Привет всем!
// Carol получил от Alice: Привет всем!


▪️ Когда использовать

Компоненты слишком сильно связаны друг с другом
Хотите переиспользовать компоненты в других контекстах
Примеры: Spring MVC DispatcherServlet — медиатор между контроллерами

▪️ Минус

Медиатор может стать God Object, сконцентрировав слишком много логики.

🐸 Библиотека собеса по Java

#patterns
Please open Telegram to view this post
VIEW IN TELEGRAM
👍31🔥1👏1
This media is not supported in your browser
VIEW IN TELEGRAM
Перед вами классическая визуализация одного из методов сортировки.

как считаете, какой это метод?
👍— Сортировка выбором (Selection Sort)
❤️— Сортировка слиянием (Merge Sort)
🔥— Сортировка пузырьком (Bubble Sort)

🔹 Курс «Алгоритмы и структуры данных»
🔹 Получить консультацию менеджера
🔹 Сайт Академии 🔹 Сайт Proglib

🏃‍♀️ Азбука айтишника

#магиякода
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥117👍3
Расскажите о паттерне Memento

Memento — это поведенческий паттерн, который позволяет сохранять и восстанавливать прежнее состояние объекта, не нарушая инкапсуляцию.

Простыми словами: Ctrl+Z в любом редакторе — где-то хранится снимок предыдущего состояния, к которому можно откатиться.

▪️ Пример:

Редактор конфигурации сервера: администратор меняет настройки и может откатиться к любой предыдущей версии.

// Memento — снимок состояния (immutable)
record ConfigMemento(
Map<String, String> properties,
LocalDateTime timestamp
) {
public ConfigMemento {
properties = Map.copyOf(properties); // защитная копия
}
}

// Originator — объект, чьё состояние сохраняем
class ServerConfig {
private final Map<String, String> properties = new HashMap<>();

public void set(String key, String value) {
properties.put(key, value);
}

public String get(String key) {
return properties.get(key);
}

public ConfigMemento save() {
return new ConfigMemento(properties, LocalDateTime.now());
}

public void restore(ConfigMemento memento) {
properties.clear();
properties.putAll(memento.properties());
}
}

// Caretaker — хранит историю снимков
class ConfigHistory {
private final Deque<ConfigMemento> snapshots = new ArrayDeque<>();

public void backup(ServerConfig config) {
snapshots.push(config.save());
}

public void undo(ServerConfig config) {
if (!snapshots.isEmpty()) {
config.restore(snapshots.pop());
}
}
}

// Использование
ServerConfig config = new ServerConfig();
ConfigHistory history = new ConfigHistory();

config.set("maxThreads", "200");
history.backup(config);

config.set("maxThreads", "500");
config.set("timeout", "30s");
history.backup(config);

config.set("maxThreads", "1"); // ой, ошибка
history.undo(config);

System.out.println(config.get("maxThreads")); // 500


▪️ Когда использовать

Нужна функция отмены/отката (undo)
Нужно сохранять контрольные точки состояния
Прямой доступ к полям объекта нарушил бы инкапсуляцию

▪️ Memento vs Command

— Command: хранит действие и умеет его отменить
— Memento: хранит полный снимок состояния

▪️ Минус

Может потреблять много памяти, если состояние объекта большое и снимки создаются часто.

🐸 Библиотека собеса по Java

#patterns
Please open Telegram to view this post
VIEW IN TELEGRAM
2👍2🔥1
До 31 мая можно забрать любой курс Proglib Academy со скидкой 40%

Если давно хотели прокачаться в Python, ML, алгоритмах или AI-агентах, сейчас самое время выбрать программу и начать обучение по сниженной цене.

🎁 Разработка AI-агентов от 49.000 ₽ (вместо 69.000 ₽)

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

🎁 Курс AgentOps129.000 ₽ (вместо 149.000 ₽)

Для разработчиков и LLM-инженеров, которые хотят внедрять AI-логику в бэкенд и сохранять стабильность сервиса.

🎁 Математика для разработки AI-моделей 23.990 ₽ (вместо 31.990 ₽)

Практическая база по математике для анализа данных, ML и дальнейшего развития в AI.

🎁 Математика для Data Scienceот 29.990 ₽ (вместо 39.990 ₽)

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

🎁 ML для старта в Data Science28.990 ₽ (вместо 38.990 ₽)

Разберётесь в машинном обучении: от базовых понятий и линейных моделей до ансамблей, бустинга и рекомендательных систем.

🎁 Основы IT для непрограммистов16.990 ₽ (вместо 28.990 ₽)

Курс для IT-рекрутеров, маркетологов, проджектов, продактов и всех, кто работает с IT, но не пишет код.

🎁 Архитектуры и шаблоны проектирования27.990 ₽ (вместо 37.900 ₽)

Освоите основные паттерны проектирования и прокачаете навыки архитектора программного обеспечения.

🎁 Специалист по ИИ89.000 ₽ (вместо 113.900 ₽)

Курс для тех, кто хочет получить профессию в сфере ИИ, собрать портфолио из 5 проектов и научиться разрабатывать сложных AI-агентов.

🎁 Алгоритмы и структуры данных 33.990 ₽ (вместо 57.990 ₽)

Подготовитесь к алгоритмическим собеседованиям, разберёте структуры данных и научитесь писать более эффективный код.

🎁 Программирование на языке Python27.990 ₽ (вместо 47.390 ₽)

Освоите Python на практике: без сухой теории, с пошаговой прокачкой навыков и итоговым проектом в портфолио.

🙌 Выбирайте курс по ссылке, оставляйте заявку, и менеджер поможет подобрать программу под ваши цели — https://clc.to/SALE40
Расскажите о паттерне Visitor

Visitor — это поведенческий паттерн, который позволяет добавлять новые операции к объектам, не изменяя их классы.

Простыми словами: налоговый инспектор (visitor) приходит в разные компании и выполняет проверку — компании не меняются, а новые виды проверок добавляются легко.

▪️ Пример:

Система документооборота: есть разные типы документов, и нужно добавлять операции (экспорт, валидация, подсчёт статистики) без изменения классов документов.

// Visitor
interface DocumentVisitor {
void visit(Invoice invoice);
void visit(Contract contract);
void visit(Report report);
}

// Элементы
interface Document {
void accept(DocumentVisitor visitor);
}

class Invoice implements Document {
private final BigDecimal amount;
public Invoice(BigDecimal amount) { this.amount = amount; }
public BigDecimal getAmount() { return amount; }

public void accept(DocumentVisitor visitor) {
visitor.visit(this); // double dispatch
}
}

class Contract implements Document {
private final LocalDate expiryDate;
public Contract(LocalDate expiryDate) { this.expiryDate = expiryDate; }
public LocalDate getExpiryDate() { return expiryDate; }

public void accept(DocumentVisitor visitor) {
visitor.visit(this);
}
}

class Report implements Document {
private final int pageCount;
public Report(int pageCount) { this.pageCount = pageCount; }
public int getPageCount() { return pageCount; }

public void accept(DocumentVisitor visitor) {
visitor.visit(this);
}
}

// Конкретный visitor — новая операция без изменения документов
class ExportVisitor implements DocumentVisitor {
public void visit(Invoice invoice) {
System.out.println("Экспорт счёта: " + invoice.getAmount() + " ₽");
}
public void visit(Contract contract) {
System.out.println("Экспорт договора до " + contract.getExpiryDate());
}
public void visit(Report report) {
System.out.println("Экспорт отчёта: " + report.getPageCount() + " стр.");
}
}

// Использование
List<Document> docs = List.of(
new Invoice(new BigDecimal("150000")),
new Contract(LocalDate.of(2027, 1, 1)),
new Report(42)
);

DocumentVisitor exporter = new ExportVisitor();
docs.forEach(doc -> doc.accept(exporter));


▪️ Когда использовать

Нужно выполнить операцию над группой разнородных объектов
Новые операции добавляются часто, а новые типы элементов — редко
Пример из JDK: java.nio.file.FileVisitor

▪️ Минус

Visitor нужно обновлять при добавлении нового типа элемента — нарушается Open/Closed Principle для элементов.

🐸 Библиотека собеса по Java

#patterns
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1🔥1👏1
Расскажите о паттерне Interpreter

Interpreter — это поведенческий паттерн, который определяет грамматику простого языка и интерпретатор для его предложений.

Простыми словами: вы описываете правила «мини-языка» в виде классов, и каждый класс умеет вычислить свою часть выражения. Как калькулятор, который разбирает «3 + 5 * 2».

▪️ Пример:

Движок фильтрации пользователей по правилам: «возраст > 18 AND город = Москва». Каждое условие — узел дерева выражений.

// Абстрактное выражение
interface Expression {
boolean interpret(Map<String, String> context);
}

// Терминальное выражение — проверка одного поля
class Equals implements Expression {
private final String key;
private final String value;

public Equals(String key, String value) {
this.key = key;
this.value = value;
}

public boolean interpret(Map<String, String> context) {
return value.equals(context.get(key));
}
}

class GreaterThan implements Expression {
private final String key;
private final int threshold;

public GreaterThan(String key, int threshold) {
this.key = key;
this.threshold = threshold;
}

public boolean interpret(Map<String, String> context) {
return Integer.parseInt(context.getOrDefault(key, "0")) > threshold;
}
}

// Нетерминальные выражения — комбинаторы
class And implements Expression {
private final Expression left, right;

public And(Expression left, Expression right) {
this.left = left;
this.right = right;
}

public boolean interpret(Map<String, String> context) {
return left.interpret(context) && right.interpret(context);
}
}

class Or implements Expression {
private final Expression left, right;

public Or(Expression left, Expression right) {
this.left = left;
this.right = right;
}

public boolean interpret(Map<String, String> context) {
return left.interpret(context) || right.interpret(context);
}
}

// Использование: возраст > 18 AND город = Москва
Expression rule = new And(
new GreaterThan("age", 18),
new Equals("city", "Москва")
);

Map<String, String> user1 = Map.of("age", "25", "city", "Москва");
Map<String, String> user2 = Map.of("age", "16", "city", "Москва");

System.out.println(rule.interpret(user1)); // true
System.out.println(rule.interpret(user2)); // false


▪️ Когда использовать

Есть простой язык или набор правил, которые нужно интерпретировать
Грамматика стабильна, но выражений — много
Пример: SpEL (Spring Expression Language), регулярные выражения

▪️ Минус

Для сложных грамматик дерево классов разрастается и становится неуправляемым — лучше использовать парсер-генераторы (ANTLR).

🐸 Библиотека собеса по Java

#patterns
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2🔥1
💬 Обратная связь

Текущий уровень сложности вопросов?

🔥 — Слишком просто, хочу сложнее
👍🏼 — В самый раз
❤️ — Иногда сложновато
😁 — Часто не понимаю

🐸 Библиотека собеса по Java
Please open Telegram to view this post
VIEW IN TELEGRAM
👍123🔥2😁2
Что происходит с объектом, когда на него не осталось ссылок?

Объект становится кандидатом на сборку мусора, но память освобождается не сразу.

GC ориентируется на достижимость от GC roots (стек потоков, статические поля, JNI-ссылки, активные локальные переменные). Пока объект достижим хотя бы по одной цепочке — он живой. Как только он перестаёт быть достижимым, он помечается недостижимым и память освобождается при ближайшем цикле сборки.

Если у объекта есть finalize() или он зарегистрирован в Cleaner/PhantomReference, освобождение откладывается на дополнительный цикл.

🐸 Библиотека собеса по Java

#core
Please open Telegram to view this post
VIEW IN TELEGRAM
👍41🔥1
Что такое escape analysis и какие оптимизации он даёт?

Это анализ JIT-компилятора, который определяет, «убегает» ли объект за пределы метода или потока.

Если объект создаётся и используется только локально и наружу не уходит, JVM может:

→ Scalar replacement — вообще не создавать объект в куче, а разложить его на отдельные поля в регистрах/на стеке. Это снимает нагрузку на GC.
→ Lock elision — убрать синхронизацию, если объект гарантированно не виден другим потокам.


🐸 Библиотека собеса по Java

#jvm
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥41👍1
Возможна ли утечка памяти, несмотря на сборщик мусора?

Да, возможна. GC удаляет только недостижимые объекты. Утечка — это когда объекты остаются достижимыми, но больше не нужны, и память не освобождается.

Типичные источники:

неограниченные кеши и статические коллекции (static Map), которые растут без удаления;
незакрытые ресурсы (соединения, стримы);
слушатели/колбэки без отписки;
ThreadLocal в пуле потоков, где значение не очищается через remove() (поток переиспользуется и не умирает);
утечка класслоадеров при горячей перезагрузке.

🐸 Библиотека собеса по Java

#core
Please open Telegram to view this post
VIEW IN TELEGRAM
5👍2🔥1
⚡️ Продолжаем знакомить вас с экспертами курса AgentOps!

Сергей Нотевский расскажет, как выстроить FinOps для AI-продуктов: оптимизировать затраты на разработку и продакшен, внедрить model routing, semantic cache и систему алертов для контроля расходов
Эмиль Сатаев разберет Context Engineering: управление контекстом, защиту от prompt injection, работу с длинными контекстами и построение безопасного пайплайна входа для AI-систем
Михаил Бондаревский покажет, как подготовить инфраструктуру для AI-агентов: Docker, sandboxing, streaming, docker-compose и воспроизводимое окружение для разработки и продакшена
Мурат Хажгериев расскажет про Enterprise Integrations & MCP: когда MCP действительно нужен, как подключать внешние сервисы и реализовывать интеграции с OAuth2 delegation
Герман Сабиров разберет Governance & Compliance для AI-систем: data flow, audit logs, требования 152-ФЗ, локализацию данных и построение compliance-подхода на уровне архитектуры

Курс для backend-разработчиков, тимлидов и LLM инженеров о том, как внедрять AI-логику в бэкенд IT-продуктов и сохранять стабильность сервиса.

👉 Изучить обновленную программу AgentOps и занять место.
Что такое type erasure и какие ограничения он накладывает на дженерики?

generics дают типобезопасность на этапе компиляции, но в рантайме информация о типовых параметрах стирается: List<String> превращается в обычный List, а компилятор сам вставляет приведения типов. Сделано ради обратной совместимости со старым кодом.

Из-за стирания нельзя:

создать new T() или new T[];
использовать instanceof List<String>;
иметь статические поля типа T;
объявить два метода, отличающиеся только параметром типа (после стирания их сигнатуры совпадут).

Частичная информация о дженериках сохраняется в сигнатурах полей и методов и доступна через рефлексию, но не на уровне конкретных экземпляров.

🐸 Библиотека собеса по Java

#core
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1🔥1👏1