Java | Вопросы собесов
11.5K subscribers
34 photos
2 videos
1.38K links
Download Telegram
🤔 Как из Spring-приложения обратиться к другому сервису?

Есть несколько способов:
- RestTemplate — синхронный вызов HTTP-запросов (устаревающий).
- WebClient (из Spring WebFlux) — асинхронный и реактивный подход.
- Feign (через Spring Cloud OpenFeign) — декларативный HTTP-клиент, автоматически связывает интерфейсы с REST-эндпоинтами.
- gRPC, Kafka, AMQP — для межсервисного общения в распределённых системах.
Чаще всего REST-взаимодействие строится через WebClient или Feign.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
👍7🔥2
🤔 Что такое функциональный интерфейс?

Функциональный интерфейс —это интерфейс, который содержит только один абстрактный метод. Это позволяет использовать лямбда-выражения для создания его анонимных реализаций, делая код более лаконичным и читаемым. Функциональные интерфейсы являются основой для лямбда-выражений и методов ссылок, начиная с версии 8.

Примером этого может служить интерфейс java.util.function.Predicate<T> который принимает объект типа T и возвращает значение типа boolean. Вот пример использования:
Predicate<String> isNotEmpty = s -> !s.isEmpty();
System.out.println(isNotEmpty.test("Hello")); // Выведет true
System.out.println(isNotEmpty.test("")); // Выведет false


Чтобы явно указать, что интерфейс предназначен для использования как функциональный, используется аннотация @FunctionalInterface. Эта аннотация не обязательна (компилятор может определить функциональный интерфейс и без неё), но она помогает в документировании кода и обеспечивает проверку времени компиляции, гарантируя, что интерфейс содержит только один абстрактный метод.
@FunctionalInterface
public interface SimpleFunction {
int apply(int value);
}

// Использование
SimpleFunction triple = value -> value * 3;
System.out.println(triple.apply(5)); // Выведет 15


Ставь 👍 и забирай 📚 Базу знаний
👍9
🤔 Зачем нужна программа, которая работает в нескольких потоках, а не в одном?

Многопоточность нужна, чтобы:
- Выполнять несколько задач параллельно (например, UI + загрузка данных).
- Улучшать производительность на многоядерных процессорах.
- Повышать отзывчивость (асинхронная обработка).
- Разделять задачи (производитель-потребитель, слушатели, обработчики событий).


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
👍7🔥1
🤔 Что такое сигнатура?

Сигнатура метода – это его уникальная идентификация в классе. Она включает:
Имя метода
Список параметров (их типы и порядок)
class Example {
void print(String text) {} // Сигнатура: print(String)
void print(int number) {} // Сигнатура: print(int)
int print(String text, int number) { return 0; } // Сигнатура: print(String, int)
}


🚩Почему сигнатура важна?

🟠Перегрузка методов (Method Overloading)
В одном классе можно создавать методы с одинаковыми именами, но разными сигнатурами.
class MathUtils {
int sum(int a, int b) { return a + b; } // sum(int, int)
double sum(double a, double b) { return a + b; } // sum(double, double)
}


🟠Переопределение методов (Method Overriding)
При переопределении метода (в наследовании) сигнатура ДОЛЖНА быть такой же.
class Parent {
void show() {} // Сигнатура: show()
}

class Child extends Parent {
@Override
void show() {} // Сигнатура совпадает, корректное переопределение
}


🚩Ошибки, связанные с сигнатурой

Ошибка: Возвращаемый тип НЕ влияет на сигнатуру
class Test {
int method(int x) { return x; }
double method(int x) { return x; } // Ошибка! Сигнатура совпадает
}


Ставь 👍 и забирай 📚 Базу знаний
👍9
🤔 В чем разница между Spring аннотациями Component, Repository и Service?

-
@Component — базовая аннотация для любого компонента;
-
@Service — специализированная аннотация для бизнес-логики;
-
@Repository — специализированная аннотация для слоя доступа к данным и обработки SQL-исключений.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
👍10🔥5💊3
🤔 В чем смысл ограничений?

Ограничения (constraints) – это правила, которые ограничивают возможные значения данных или ограничивают поведение системы.

🟠Ограничения в базах данных (SQL Constraints)
В SQL ограничения гарантируют корректность данных в таблицах.
CREATE TABLE Users (
id INT PRIMARY KEY,
email VARCHAR(255) UNIQUE NOT NULL,
age INT CHECK (age > 0),
country VARCHAR(50) DEFAULT 'Unknown'
);


🟠Ограничения в Java Generics (`<T extends ...>`)
Ограничения в Generics позволяют задавать допустимые типы.
class Box<T> {
T value;
public Box(T value) { this.value = value; }
}
Box<String> strBox = new Box<>("Hello");
Box<Integer> intBox = new Box<>(10);

class NumberBox<T extends Number> { // Ограничение: T должно быть числом
T value;
public NumberBox(T value) { this.value = value; }

public double square() {
return value.doubleValue() * value.doubleValue();
}
}


🟠Ограничения в потоках (synchronized, volatile, join)
В многопоточности ограничения помогают избежать гонок потоков.
class Counter {
private int count = 0;

public synchronized void increment() { // Только один поток может изменять count одновременно
count++;
}
}


Ставь 👍 и забирай 📚 Базу знаний
👍5💊4
🤔 Почему Vue?

- Прост в изучении;
- Подходит как для SPA, так и для встраивания в страницы;
- Реактивность и декларативный шаблонный синтаксис;
- Хорошая документация;
- Отлично интегрируется с TypeScript, Vue Router, Vuex/Pinia.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
💊23
🤔 Расскажи про процесс от пуша кода до продакшена

Когда разработчик пушит код, он проходит несколько этапов перед развертыванием в продакшене. Этот процесс автоматизируется с помощью CI/CD (Continuous Integration / Continuous Deployment).

🚩Этапы CI/CD

🟠Разработчик пушит код в Git-репозиторий
- Код отправляется в GitHub, GitLab, Bitbucket или другой репозиторий.
- Открывается Pull Request (PR) для ревью.
git add .
git commit -m "Добавлена новая фича"
git push origin feature-branch


🟠CI (Continuous Integration) – Автоматическая сборка и тестирование
После пуша CI-сервер (Jenkins, GitHub Actions, GitLab CI/CD, CircleCI)** запускает автоматические тесты и сборку.
Клонирование репозитория.
Сборка проекта (например, mvn package для Java).
Запуск юнит-тестов (JUnit, Mockito).
Запуск интеграционных тестов (например, TestContainers).
Анализ кода (SonarQube).
name: CI Pipeline

on:
push:
branches:
- main
- develop

jobs:
build:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v3

- name: Setup Java
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'

- name: Build project
run: mvn clean package

- name: Run tests
run: mvn test


🟠CD (Continuous Deployment) – Развёртывание на Staging
После успешного CI код автоматически разворачивается в стейджинг (staging) – это тестовая среда, похожая на продакшен.
Развёртывание может происходить с помощью:
Docker + Kubernetes (K8s)
AWS CodeDeploy, GitLab CD
Terraform + Ansible
FROM openjdk:17
COPY target/app.jar /app.jar
CMD ["java", "-jar", "/app.jar"]


🟠Код проходит код-ревью и одобряется
Проверяется чистота кода, читаемость и ошибки.
В некоторых компаниях код проходит Security Review
git merge feature-branch
git push origin main


🟠CD (Continuous Deployment) – Развёртывание в продакшен
Blue-Green Deployment – новый код разворачивается на отдельном сервере, затем трафик переключается.
Canary Release – новый код деплоится на 5-10% пользователей, если всё хорошо – на всех.
Rolling Deployment – обновление происходит поэтапно, без даунтайма.
deploy:
stage: deploy
script:
- kubectl apply -f deployment.yaml
only:
- main


Ставь 👍 и забирай 📚 Базу знаний
👍14🔥1
🤔 Что такое интерфейсы Comparable?

Интерфейс для естественной сортировки объектов через реализацию метода compareTo().

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
👍6
🤔 Расскажи про транзитивность

Транзитивность — это математическое и логическое свойство отношений, означающее, что если A связано с B, а B связано с C, то A связано с C.

🚩Транзитивность в отношении эквивалентности (`equals`)

Согласно контракту метода equals(), он должен быть транзитивным
class Person {
String name;

Person(String name) {
this.name = name;
}

@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Person person = (Person) obj;
return name.equals(person.name);
}
}

public class Main {
public static void main(String[] args) {
Person p1 = new Person("Иван");
Person p2 = new Person("Иван");
Person p3 = new Person("Иван");

System.out.println(p1.equals(p2)); // true
System.out.println(p2.equals(p3)); // true
System.out.println(p1.equals(p3)); // true (транзитивность)
}
}


🚩Транзитивность в сравнении (`compareTo` из `Comparable`)

Метод compareTo() должен соблюдать транзитивность:
class Student implements Comparable<Student> {
int age;

Student(int age) {
this.age = age;
}

@Override
public int compareTo(Student other) {
return Integer.compare(this.age, other.age);
}
}

public class Main {
public static void main(String[] args) {
Student s1 = new Student(25);
Student s2 = new Student(20);
Student s3 = new Student(15);

System.out.println(s1.compareTo(s2)); // > 0 (s1 > s2)
System.out.println(s2.compareTo(s3)); // > 0 (s2 > s3)
System.out.println(s1.compareTo(s3)); // > 0 (s1 > s3) (транзитивность)
}
}


🚩Транзитивность в наследовании (`extends` / `implements`)

В Java классы могут наследоваться транзитивно
class Animal {}
class Mammal extends Animal {}
class Dog extends Mammal {}


Ставь 👍 и забирай 📚 Базу знаний
👍4
🤔 Перечисли основные агрегатные функции.

- COUNT() — количество строк;
- SUM() — сумма значений;
- AVG() — среднее значение;
- MAX() — максимум;
- MIN() — минимум.
Эти функции применяются к группам строк или ко всему набору данных.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
👍12💊2🔥1
🤔 Как остановить поток?

Остановить поток в Java можно несколькими способами, но важно помнить, что принудительная остановка потока – плохая практика. Java предлагает безопасные методы управления потоком, чтобы избежать неожиданных ошибок и некорректного поведения программы.

🚩Плохие способы (НЕ рекомендуется)

Раньше использовался метод Thread.stop(), но он был устаревшим и удалённым из-за того, что мог оставить программу в неконсистентном состоянии.
Thread thread = new Thread(() -> {
while (true) {
System.out.println("Работаю...");
}
});

thread.start();
thread.stop(); // ОПАСНО! Может привести к некорректному завершению работы.


🚩Флаг завершения работы (рекомендуемый способ)
Самый безопасный способ – это использование флага (volatile boolean).
class MyTask implements Runnable {
private volatile boolean running = true;

public void run() {
while (running) {
System.out.println("Работаю...");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // Важно восстанавливать флаг прерывания
}
}
System.out.println("Поток остановлен.");
}

public void stop() {
running = false;
}
}

public class Main {
public static void main(String[] args) throws InterruptedException {
MyTask task = new MyTask();
Thread thread = new Thread(task);
thread.start();

Thread.sleep(2000);
task.stop(); // Корректно останавливаем поток
}
}


🚩Прерывание потока (`interrupt()`)

Этот способ удобен для потоков, которые ждут (sleep(), wait(), join()), потому что прерывание выбрасывает InterruptedException.
class MyTask implements Runnable {
public void run() {
try {
while (!Thread.currentThread().isInterrupted()) {
System.out.println("Работаю...");
Thread.sleep(500);
}
} catch (InterruptedException e) {
System.out.println("Поток прерван.");
}
}
}

public class Main {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new MyTask());
thread.start();

Thread.sleep(2000);
thread.interrupt(); // Прерывание потока
}
}


Ставь 👍 и забирай 📚 Базу знаний
👍10
🤔 Какое основное призвание интерфейса Map?

Основное назначение Map — хранение, поиск и управление данными по ключу. Это обеспечивает быстрый доступ к значениям, используя уникальные ключи, и позволяет решать задачи по работе с кэшами, индексами, словарями.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
👍9
🤔 Что такое HQL?

HQL (Hibernate Query Language) – это язык запросов, используемый в Hibernate (фреймворке для работы с базами данных в Java), который похож на SQL, но оперирует не таблицами и столбцами, а объектами и их свойствами.

🚩Зачем нужен HQL?

Когда мы работаем с базами данных в Hibernate, мы используем объектно-реляционное отображение (ORM), где каждая таблица представляется как класс, а строки – как объекты. Однако иногда нам нужно делать запросы к базе данных, например:
Получить список объектов, соответствующих определённому критерию
Отфильтровать, отсортировать или объединить данные
Выполнить массовое обновление или удаление

Можно, конечно, использовать чистый SQL, но тогда мы потеряем преимущества ORM, такие как переносимость кода между разными базами данных. HQL решает эту проблему, позволяя писать запросы в объектных терминах, а Hibernate сам преобразует их в правильный SQL для конкретной базы данных.

🚩Как выглядит HQL?

HQL очень похож на SQL, но вместо таблиц и столбцов мы используем имена классов и их полей.

🟠Пример 1: Получение списка объектов
Допустим, у нас есть класс User, связанный с таблицей users:
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private String name;
private int age;

// Геттеры и сеттеры
}


Теперь напишем HQL-запрос, чтобы получить всех пользователей старше 18 ле
String hql = "FROM User WHERE age > 18";
List<User> users = session.createQuery(hql, User.class).getResultList();


Выборка только имен пользователей
String hql = "SELECT u.name FROM User u";
List<String> names = session.createQuery(hql, String.class).getResultList();


Запрос с параметрами (предотвращает SQL-инъекции)
String hql = "FROM User WHERE name = :name";
Query<User> query = session.createQuery(hql, User.class);
query.setParameter("name", "Иван");
List<User> users = query.getResultList();


🚩Плюсы

Независимость от СУБД
HQL автоматически адаптируется под MySQL, PostgreSQL, Oracle и другие базы.
Оперирование объектами
вместо таблиц и столбцов мы работаем с сущностями (классами Java).
Безопасность
использование параметров (setParameter()) предотвращает SQL-инъекции.
Гибкость
поддержка JOIN, GROUP BY, ORDER BY и других SQL-конструкций.

Ставь 👍 и забирай 📚 Базу знаний
👍8
🤔 Какие участки памяти в JVM знаешь?

JVM использует несколько участков памяти: Heap, Stack, Method Area и Metaspace. Heap хранит объекты и динамически выделяемую память, Stack — локальные переменные, а Metaspace содержит метаданные классов. Method Area хранит байт-код, а также информацию о методах и полях классов.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
👍8💊3
🤔 Какие весовые рамки у integer?

В Java тип int занимает 4 байта (32 бита) и имеет диапазон:
-2^{31} \text{ до } 2^{31} - 1

🚩Точный диапазон `int`

🟠Минимальное значение
Integer.MIN_VALUE = -2,147,483,648
🟠Максимальное значение
Integer.MAX_VALUE = 2,147,483,647

public class Main {
public static void main(String[] args) {
System.out.println("Минимальный int: " + Integer.MIN_VALUE);
System.out.println("Максимальный int: " + Integer.MAX_VALUE);
}
}


Вывод:
Минимальный int: -2147483648  
Максимальный int: 2147483647


🚩Почему именно такой диапазон?

4 байта (32 бита) означают, что у нас 2³² возможных значений.
Поскольку int знаковый (поддерживает отрицательные и положительные числа), половина значений отводится подотрицательные числа.
Один бит используется для знака (0 – положительное число, 1 – отрицательное).
\text{Диапазон} = - (2^{31}) \text{ до } (2^{31} - 1)

🚩Что будет, если выйти за пределы `int`?
Если сложить два максимальных значения int, произойдёт переполнение (overflow)
int a = Integer.MAX_VALUE;
int b = 1;
int c = a + b;
System.out.println(c); // Выведет -2147483648 (переполнение!)


🟠Как работать с числами больше `int`?
Использовать `long` (8 байт, диапазон от -2^63 до 2^63 - 1):
long bigNumber = 2_147_483_648L;  // Обязательно добавлять "L" в конце


Использовать BigInteger (неограниченный размер):
BigInteger bigNum = new BigInteger("999999999999999999999999");


Ставь 👍 и забирай 📚 Базу знаний
👍6
🤔 В чём отличие Supplier'а от Consumer'а?

Supplier — это функциональный интерфейс, который возвращает объект, но не принимает аргументов (T get()). Consumer принимает объект в качестве входного параметра, но ничего не возвращает (void accept(T t)). Первый используется для генерации данных, а второй — для их обработки.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
👍6
🤔 Как ты можешь описать абстракцию?

Это принцип объектно-ориентированного программирования (ООП), который скрывает детали реализации объекта и показывает только его наиболее важные характеристики. Она позволяет сосредоточиться на сущности объекта, игнорируя его внутреннюю сложность.

🚩Абстракция

В Java абстракция достигается через:
Абстрактные классы
Интерфейсы

🟠Абстрактные классы
Абстрактный класс — это класс, который не может быть создан напрямую, но может содержать:
Абстрактные методы (без реализации, только сигнатуры);
Обычные методы (с реализацией).
Используется, если вы хотите описать общее поведение для группы классов, но часть поведения оставить на усмотрение конкретных подклассов.
abstract class Animal {
// Абстрактный метод — реализуется в подклассах
abstract void makeSound();

// Обычный метод
void eat() {
System.out.println("This animal eats food.");
}
}

class Dog extends Animal {
@Override
void makeSound() {
System.out.println("Woof!");
}
}

class Cat extends Animal {
@Override
void makeSound() {
System.out.println("Meow!");
}
}

public class Main {
public static void main(String[] args) {
Animal dog = new Dog();
dog.makeSound(); // Woof!
dog.eat(); // This animal eats food.

Animal cat = new Cat();
cat.makeSound(); // Meow!
}
}


🟠Интерфейсы
Интерфейс — это чистый контракт, который определяет набор методов, которые класс должен реализовать.
В отличие от абстрактного класса:
Интерфейс не может содержать полей (кроме static final).
Класс может реализовать несколько интерфейсов (множественное наследование).
interface Vehicle {
void start(); // метод без реализации
void stop();
}

class Car implements Vehicle {
@Override
public void start() {
System.out.println("Car is starting.");
}

@Override
public void stop() {
System.out.println("Car is stopping.");
}
}

class Bike implements Vehicle {
@Override
public void start() {
System.out.println("Bike is starting.");
}

@Override
public void stop() {
System.out.println("Bike is stopping.");
}
}

public class Main {
public static void main(String[] args) {
Vehicle car = new Car();
car.start(); // Car is starting.
car.stop(); // Car is stopping.

Vehicle bike = new Bike();
bike.start(); // Bike is starting.
bike.stop(); // Bike is stopping.
}
}


🚩Почему важна абстракция?

🟠Скрытие сложностей
Программистам не нужно знать все детали реализации объекта. Они работают только с его интерфейсом.
🟠Упрощение понимания
Код становится понятным и модульным, так как мы сосредоточиваемся на важной логике.
🟠Повторное использование
Абстракция позволяет использовать один и тот же код для разных объектов.
🟠Гибкость и поддержка
Если нужно изменить реализацию, это не затронет остальную часть программы (если она работает через абстрактный контракт).

Ставь 👍 и забирай 📚 Базу знаний
👍5
🤔 Для чего нужны функциональные интерфейсы ObjDoubleConsumer<T>, ObjIntConsumer<T>, ObjLongConsumer<T>?

Они позволяют выполнять действие над объектом типа T и примитивом (double, int или long). Используются, когда нужно избежать автоупаковки примитива, например, при работе с парами "объект и число".


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
🔥7👍2💊1
🤔 В чём заключается разница между методами start() и run()?

🚩`start()` – создаёт новый поток

Метод start() создаёт новый поток и вызывает run() внутри него.
class MyThread extends Thread {
@Override
public void run() {
System.out.println("Работает поток: " + Thread.currentThread().getName());
}
}

public class Main {
public static void main(String[] args) {
MyThread thread = new MyThread();
thread.start(); // Запускаем новый поток

System.out.println("Работает поток: " + Thread.currentThread().getName());
}
}


Вывод (разные потоки работают параллельно)
Работает поток: main
Работает поток: Thread-0


🚩`run()` – выполняется в ТЕКУЩЕМ потоке (без создания нового)

Если вызвать run() напрямую, код просто выполнится как обычный метод, а не в новом потоке.
public class Main {
public static void main(String[] args) {
MyThread thread = new MyThread();
thread.run(); // Ошибка! Работает в главном потоке

System.out.println("Работает поток: " + Thread.currentThread().getName());
}
}


Вывод (run() работает в главном потоке, а не в новом)
Работает поток: main
Работает поток: main


Ставь 👍 и забирай 📚 Базу знаний
👍6
🤔 От скольки классов может наследоваться класс?

Класс может наследоваться только от одного класса (одинарное наследование). Это ограничение компенсируется возможностью реализации нескольких интерфейсов.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
👍14