Java for Beginner
778 subscribers
749 photos
220 videos
12 files
1.27K links
Канал от новичков для новичков!
Изучайте Java вместе с нами!
Здесь мы обмениваемся опытом и постоянно изучаем что-то новое!

Наш YouTube канал - https://www.youtube.com/@Java_Beginner-Dev

Наш канал на RUTube - https://rutube.ru/channel/37896292/
Download Telegram
Что выведет код?

import java.util.List;

public class Task251125 {
public static void main(String[] args) {
var list = List.of(1, 2, 3);
var number = 10;
var result = process(list, number);
System.out.println(result);
}

static var process(List<Integer> list, int n) {
var sum = 0;
for (var item : list) {
sum += item;
}
return sum * n;
}
}


#Tasks
👍2
Вопрос с собеседований

Разница между deep copy и shallow copy? 🤓


Ответ:

Shallow copy
копирует только верхний уровень объекта, оставляя вложенные ссылки общими.

Deep copy создает полную независимую структуру.

Первый быстрее, второй безопаснее, если требуется изоляция состояния. Выбор зависит от структуры данных и логики приложения.



#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
История IT-технологий сегодня — 26 ноября


ℹ️ Кто родился в этот день

Но́рберт Ви́нер (англ. Norbert Wiener; 26 ноября 1894, США, штат Миссури, США — 18 марта 1964, Стокгольм, Швеция)американский математик и учёный, основатель кибернетики, внёс фундаментальный вклад в теорию управления, вычислительных систем и автоматического регулирования.


🌐 Знаковые события

2018 — аппарат миссии НАСА InSight совершил посадку на Марс.


#Biography #Birth_Date #Events #26Ноября
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Глава 2. List — списки

Метод add

Философия добавления элементов в List

Добавление элемента в List — это не просто механическое помещение объекта в коллекцию, а сложный процесс, который должен балансировать между несколькими competing требованиями: эффективностью операций вставки, оптимальным использованием памяти, производительностью случайного доступа и минимизацией затрат на структурные изменения. Каждая реализация List находит свой уникальный компромисс между этими требованиями, что определяет ее применимость в различных сценариях.


ArrayList: динамический массив

ArrayList представляет собой реализацию списка на основе динамического массива. Его внутренняя структура построена вокруг массива Object[], который служит хранилищем элементов.

Ключевыми характеристиками этой архитектуры являются:
Прямой доступ по индексу за O(1) время
Необходимость периодического расширения массива при достижении предела емкости
Высокая пространственная локальность данных, благоприятная для кэширования процессора
Эффективность последовательного доступа при итерации



Процесс добавления в конец списка

Когда вызывается метод add(element) для добавления элемента в конец ArrayList, происходит следующая последовательность действий:


1. Проверка емкости:
Система сначала проверяет, достаточно ли места в внутреннем массиве для размещения нового элемента. Эта проверка включает сравнение текущего размера списка (количество фактически содержащихся элементов) с емкостью массива (его физической длиной).

2. Расширение массива при необходимости:

Если массив заполнен, запускается процесс расширения — одна из самых затратных операций в ArrayList:
Создается новый массив большего размера (обычно в 1.5 раза больше текущего)
Все существующие элементы копируются из старого массива в новый
Старый массив становится доступным для сборки мусор
Ссылка на внутренний массив обновляется на новый массив


3. Непосредственное добавление элемента:
Новый элемент помещается в первую свободную позицию массива (индекс, равный текущему размеру списка).

4. Обновление метаданных:
Увеличивается счетчик размера списка и инкрементируется счетчик модификаций (modCount) для поддержки fail-fast итераторов.


Механизм расширения емкости

Процесс расширения массива следует стратегии геометрического роста, которая обеспечивает амортизированную постоянную стоимость операций добавления:
// Упрощенная логика расширения
private void ensureCapacity(int minCapacity) {
if (minCapacity > elementData.length) {
int newCapacity = elementData.length + (elementData.length >> 1); // Увеличение на 50%
if (newCapacity < minCapacity) {
newCapacity = minCapacity;
}
elementData = Arrays.copyOf(elementData, newCapacity);
}
}
Эта стратегия гарантирует, что хотя отдельные операции добавления могут быть дорогими (при необходимости расширения), средняя стоимость большого количества операций добавления остается O(1).



#Java #для_новичков #beginner #List #ArrayList #LinkedList #add
👍1
Процесс добавления по индексу

Вставка в произвольную позицию
Метод add(index, element) реализует более сложный сценарий — вставку элемента в конкретную позицию списка:

1. Валидация индекса:
Проверяется, что указанный индекс находится в допустимом диапазоне (от 0 до текущего размера списка включительно).

2. Проверка и обеспечение емкости:
Аналогично простому добавлению, проверяется достаточность емкости массива и при необходимости выполняется расширение.

3. Сдвиг элементов:
Все элементы, начиная с указанной позиции, сдвигаются на одну позицию вправо.

Эта операция требует копирования части массива:
System.arraycopy(elementData, index, elementData, index + 1, size - index);


4. Вставка нового элемента:
Новый элемент помещается в освободившуюся позицию.

5. Обновление метаданных:
Увеличивается размер списка и обновляется счетчик модификаций.

Вставка в произвольную позицию имеет временную сложность O(n) в худшем случае, поскольку требует сдвига в среднем n/2 элементов. Стоимость операции максимальна при вставке в начало списка и минимальна при вставке в конец.


Оптимизации и особенности реализации

Ленивая инициализация

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

Стратегии начальной емкости
Разработчики могут указать начальную емкость через конструктор ArrayList(int initialCapacity).

Правильный выбор начальной емкости может значительно уменьшить количество операций расширения:
Слишком маленькая емкость приводит к частым расширениям и копированиям
Слишком большая емкость приводит к неэффективному использованию памяти
Оптимальная емкость зависит от ожидаемого конечного размера коллекции



Обработка больших массивов

При работе с очень большими ArrayList могут возникать дополнительные considerations:

Ограничения размера массива (Integer.MAX_VALUE - 8 в стандартных реализациях)
Проблемы фрагментации памяти кучи
Влияние на паузы сборки мусора



Сравнительный анализ ArrayList и LinkedList

Производительность операций добавления

Добавление в конец:
ArrayList: O(1) амортизированное время (благодаря стратегии геометрического роста)
LinkedList: O(1) постоянное время


Вставка в начало:
ArrayList: O(n) (требует сдвига всех элементов)
LinkedList: O(1) (простое обновление ссылок)


Вставка в произвольную позицию:
ArrayList: O(n) (сдвиг элементов)
LinkedList: O(n) (поиск позиции) + O(1) (вставка)

Потребление памяти
ArrayList:
Основные затраты: массив Object[] + служебные поля
В среднем 25-50% простаивающей емкости
Хорошая пространственная локальность


LinkedList:
Основные затраты: узлы (каждый ~24-32 байта) + служебные поля
Дополнительные 16-24 байта на элемент для ссылок
Плохая пространственная локальность



Специализированные реализации List

CopyOnWriteArrayList

CopyOnWriteArrayList использует стратегию "копирование при записи", которая обеспечивает потокобезопасность без блокировок для операций чтения

Процесс добавления:
Создается полная копия внутреннего массива
Новый элемент добавляется в конец копии
Ссылка на внутренний массив атомарно заменяется на новую копию


Преимущества:

Идеален для сценариев "частое чтение, редкая запись"
Гарантированная consistency итераторов


Недостатки:
Высокая стоимость операций модификации
Дополнительное потребление памяти


Vector

Устаревшая синхронизированная версия ArrayList:
Все методы синхронизированы
Менее эффективна чем Collections.synchronizedList()
Устаревшая стратегия роста (удвоение емкости)



#Java #для_новичков #beginner #List #ArrayList #LinkedList #add
👍1
Факторы, влияющие на производительность

Для ArrayList

Коэффициент роста:
Стандартный коэффициент 1.5 обеспечивает баланс между количеством расширений и использованием памяти. Увеличение коэффициента уменьшает частоту расширений, но увеличивает простаивающую емкость.

Начальная емкость:
Неправильный выбор начальной емкости может значительно повлиять на производительность:
Слишком маленькая: частые расширения и копирования
Слишком большая: избыточное потребление памяти


Размер элементов:
Для крупных объектов стоимость копирования при расширении может быть значительной.

Для LinkedList
Паттерн доступа:
Производительность сильно зависит от паттерна доступа:
Частые вставки в начало/конец: оптимально
Случайный доступ по индексу: неэффективно
Последовательный доступ: эффективно


Размер списка:
Для очень больших списков могут возникать проблемы с производительностью из-за poor locality и большого количества объектов узлов.


Многопоточные considerations

Потокобезопасность

Стандартные реализации ArrayList и LinkedList не являются потокобезопасными.

Concurrent модификации могут привести к:
Потере данных
Повреждению внутренних структур
Бесконечным циклам в итераторах


Thread-safe обертки:
Использование Collections.synchronizedList().

Copy-on-write коллекции:
Использование CopyOnWriteArrayList для сценариев с редкими модификациями.

Concurrent коллекции:
Использование специализированных concurrent реализаций.


Практические рекомендации

Выбор реализации

Выбор ArrayList когда:

Преобладает случайный доступ по индексу
Частые операции получения элементов
Известен приблизительный конечный размер
Память является критическим ресурсом


Выбор LinkedList когда:
Частые вставки/удаления в начале списка
Преобладает последовательный доступ
Размер списка сильно варьируется
Память не является основным ограничением


Оптимизация производительности

Для ArrayList:
Указание начальной емкости при создании
Минимизация вставок в середину списка
Использование ensureCapacity() для batch добавлений


Для LinkedList:
Предпочтение операций addFirst()/addLast() когда возможно
Избегание частого доступа по индексу
Использование ListIterator для последовательных вставок



Избегание распространенных ошибок


Неэффективные паттерны использования:
Частые вставки в начало ArrayList
Использование LinkedList для случайного доступа
Игнорирование начальной емкости для больших ArrayList


Проблемы многопоточности:
Concurrent модификации без proper синхронизации
Использование небезопасных итераторов в многопоточной среде



#Java #для_новичков #beginner #List #ArrayList #LinkedList #add
👍1🔥1
Что выведет код?


import java.util.ArrayList;
import java.util.List;

public class Task261125 {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(1, 3);
list.add(0, 4);
list.add(list.size(), 5);

System.out.println(list);
}
}


#Tasks
Вопрос с собеседований

Что такое marker interface? 🤓


Ответ:

Marker-интерфейс
не содержит методов, а лишь помечает класс, предоставляя JVM или фреймворкам дополнительную информацию.

Примеры — Serializable и Cloneable.

Хотя современный подход — аннотации, такие интерфейсы всё ещё встречаются в старом коде.



#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Forwarded from ChatRoom (Java for Beginner) (Первожрец Java)
Чет я основы забывать начал🤦🏼‍♂️😆
Короче могу взять несколько человек в падаваны и обучить Java с нуля))
🔥2
История IT-технологий сегодня — 27 ноября


ℹ️ Кто родился в этот день

Алан Эмтадж (родился 27 ноября 1964 года) — барбадосско-канадский программист и исследователь, создатель первой поисковой системы «Archie», одного из ранних инструментов навигации по FTP‐архивам в интернете.


🌐 Знаковые события

1980 — стартовал пилотируемый космический аппарат «Союз Т-3»; экипаж — Леонид Кизим, Олег Макаров, Геннадий Стрекалов, при этом Макаров первым из советских космонавтов совершает четвёртый космический полёт.


#Biography #Birth_Date #Events #27Ноября
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
https://t.me/Java_for_beginner_dev/3765

А если реально то меня несколько раз в комментариях на Ютубе спрашивали о менторстве.

Думаю нужно попробовать)


Пишите, возьму всего несколько человек! 💪☺️
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
GraphQL vs REST vs gRPC

REST — ресурсно-ориентированный HTTP API, обычно JSON по HTTP/1.1. Прост, совместим с любым клиентом, хорош для публичных и простых API.
GraphQL — язык запросов + схема; клиент сам описывает форму данных. Один эндпоинт, строгая схема, гибкость запросов, удобен для фронтенда.
gRPC — RPC-фреймворк на основе HTTP/2 + Protocol Buffers; строгие контракты (.proto), бинарная сериализация, встроенный стриминг. Ориентирован на высокую производительность и внутренние сервисы.



Формат данных

REST → JSON (текстовый, человекочитаемый).
GraphQL → JSON-ответ, но запросы декларативны и строго типизированы схемой.
gRPC → Protocol Buffers (бинарный), компактно, фиксированные поля.
Вывод: protobuf обычно экономит трафик и парсится быстрее; JSON удобнее для дебага и совместимости.

Протокол транспорта

REST → HTTP/1.1 (обычно), можно HTTP/2, но без нативного стриминга.
GraphQL → обычно HTTP/1.1 POST/GET для Query/Mutation; Subscription — WebSocket или HTTP/2 SSE.
gRPC → HTTP/2 по умолчанию, мультиплексирование, потоковые фреймы, двунаправленность.
Вывод: для потоковых сценариев и мультиплексирования gRPC технически лучше.


Типы взаимодействия

REST → запрос/ответ (stateless).
GraphQL → query/mutation/subscription; один запрос может агрегировать много сущностей.
gRPC → unary, server streaming, client streaming, bidirectional streaming (всё на уровне протокола).
Вывод: если нужны сложные стримы и двунаправленные каналы — gRPC.


Типизация и контракт

REST → схема часто нестрогая (OpenAPI/Swagger добавляет контракт).
GraphQL → строгая схема (SDL).
gRPC → строгие контракты (.proto).
Вывод: GraphQL и gRPC обеспечивают статический контракт; REST требует дополнительных инструментов для той же дисциплины.


Производительность (в общих чертах)

gRPC обычно выигрывает по пропускной способности и латентности за счёт бинарной сериализации и HTTP/2.
GraphQL может быть эффективным по числу запросов (агрегация) и по уменьшению round-trip’ов, но JSON+резолверы добавляют накладные расходы.
REST проще и зачастую медленнее при больших объёмах и при множественных запросах с агрегацией.
Вывод: для внутренней коммуникации между сервисами с высокой нагрузкой — gRPC; для клиентского слоя — GraphQL/REST в зависимости от потребностей.


Эволюция API и версияция

REST → часто версионируют (/v1/) или добавляют параметры; ломкость при изменениях.
GraphQL → расширяемость без версий (добавление полей безопасно), депрекация поддерживается.
gRPC → совместимость через правила protobuf (резервирование, добавление новых полей безопасно при соблюдении правил).
Вывод: GraphQL и gRPC дают удобные инструменты для эволюции без жесткой версии.


Инструментальная поддержка и экосистема


REST → универсальная поддержка, простые средства тестирования.
GraphQL → богатая экосистема: GraphiQL, Apollo, Relay, Codegen. Отлично для фронтенда.
gRPC → генерация стубов под любые языки, хорошие SDK для серверов и клиентов; браузерная поддержка требует gRPC-Web.
Вывод: выбор зависит от клиентской среды: браузер напрямую лучше работает с REST/GraphQL; для gRPC нужен шлюз (gRPC-Web) или прокси.



#Java #middle #GraphQL
👍1
Практические сценарии

публичный HTTP API для сторонних клиентов (публичная документация)

Выбор: REST или GraphQL
Почему: совместимость, простота, отсутствие необходимости требованиям к бинарному протоколу.
REST, если API простое, CRUD-ориентированное, нужно кэширование по URL и широчайшая совместимость.
GraphQL, если клиенты (много разных) требуют разные наборы данных и важно уменьшить число запросов.


фронтенд (SPA, мобильные клиенты) с разнообразными представлениями

Выбор: GraphQL
Почему: клиент сам формирует shape ответов; экономия round-trips; отличная интеграция с Apollo/Relay; кодогенерация типов для TS/Swift/Kotlin.

внутренняя связь между микросервисами с высокой нагрузкой

Выбор: gRPC
Почему: низкая латентность, компактность, стриминг, строгие контракты, удобная кодогенерация для множества языков.

real-time (чат, телеметрия, видео/аудио)

Выбор: gRPC (bidirectional) или GraphQL Subscriptions (WebSocket)

Почему: gRPC даёт нативный поток; GraphQL Subscriptions удобны для фронтенда, но требуют инфраструктуры и могут быть сложнее в масштабировании.

интеграция с legacy REST-сервисами

Выбор: GraphQL в качестве BFF (Backend-for-Frontend) или REST-шлюз
Почему: GraphQL может агрегировать несколько REST-вызовов и отдать клиенту нужную структуру.


Почему часто комбинируют: GraphQL для клиентов, gRPC для микросервисов

Это распространённый и рациональный паттерн:
Внутренние сервисы общаются по gRPC (эффективно, типобезопасно, стриминг).
BFF / API Gateway (или отдельный GraphQL-сервер) агрегирует данные из gRPC/REST/БД и предоставляет фронту единый, гибкий интерфейс.
Фронтенд работает с GraphQL (или REST), не заботясь о том, как именно данные доставлены внутри инфраструктуры.


Преимущества паттерна:
Отделение оптимизации внутренней сетевой коммуникации (gRPC) от удобства клиентских API (GraphQL).
Централизация логики агрегации и адаптации под клиентов.
Возможность менять внутреннюю реализацию без ломки фронта.


Пример (псевдокод Java resolver, вызывающий gRPC-stub):
// GraphQL resolver
public class UserResolver {
private final UserGrpc.UserBlockingStub userStub;

public UserResolver(UserGrpc.UserBlockingStub userStub) {
this.userStub = userStub;
}

public User getUser(String id) {
UserRequest req = UserRequest.newBuilder().setId(id).build();
UserResponse resp = userStub.getUser(req); // gRPC call to internal service
return mapToGraphQLUser(resp);
}
}



Детальный разбор преимуществ и ограничений

Удобство разработки
REST: быстро стартовать, понятная модель. Но при сложных клиентских потребностях растёт число эндпоинтов.
GraphQL: позволяет фронтенду быстро изменять данные без координации с бэком, но требует работы со схемой и авторизацией на уровне полей.
gRPC: требует .proto и генерации стабов, но даёт сильную типизацию и меньше рутинного кода при изменениях.


Кеширование
REST: простое кеширование по URL (HTTP caches, CDNs).
GraphQL: кеширование сложнее — операция может возвращать разные поля; решения: persisted queries, apollo cache, CDN на уровне persisted queries/operation id.
gRPC: кеширование на транспортном уровне сложнее; обычно кешируют ответы в сервисах.


Отладка и наблюдаемость
REST: легко отлаживать (curl, браузер).
GraphQL: дебаг через GraphiQL/Apollo Studio; трассировка полей сложнее (нужны field-level metrics).
gRPC: бинарные пакеты труднее смотреть вручную; нужно подходящие инструменты (grpcurl, tshark + protobuf descriptors).


Безопасность и авторизация


REST: стандартные механизмы (OAuth, JWT, TLS).
GraphQL: нужно управлять авторизацией на уровне полей (field-level), чтобы не раскрывать данные; также важны depth-limiting, query complexity limiting, persisted queries.
gRPC: поддерживает mTLS, аутентификацию/авторизацию через metadata; access control реализуется в сервисах.


Количество сетевых вызовов / latency
GraphQL часто уменьшает RTT за счёт агрегации (один запрос вместо множества).
gRPC уменьшает сетевые накладные расходы: меньше байт, лучше TCP connection reuse, HTTP/2 мультиплексирование.



#Java #middle #GraphQL
👍1
Практические шаблоны интеграции (patterns)

1) BFF (Backend-for-Frontend) — GraphQL на фронте + gRPC внутри

GraphQL агрегатор (BFF) вызывает gRPC сервисы, комбинирует ответы и отдаёт клиенту.
Позволяет хранить оптимизированные внутр. контракты и независимую клиентскую схему.


2) API Gateway с трансляцией

gRPC Gateway (прокси) экспонирует REST/JSON поверх gRPC-сервисов или наоборот.
Полезно для совместимости с внешними клиентами.


3) Dual API

Предоставлять одновременно REST (для публичного потребления) и GraphQL (для интерактивного фронта).
Поддерживать один источник данных и разные фасады.

4) Persisted Queries + CDN

Для GraphQL: генерировать хэш-запросов (operationId) и кэшировать на CDN; уменьшает payload и риск DoS.


Частые ошибки

Выбор gRPC для публичного браузерного API без gRPC-Web — приведёт к дополнительной сложности (нужен прокси).
GraphQL без контроля сложности — клиенты могут генерировать тяжёлые запросы (глубокая вложенность). Нужно ставить лимиты.
REST для сложной фронт-логики — приведёт к множеству эндпоинтов и оверхеду в клиенте.
Игнорирование кэширования в GraphQL — потеря преимуществ CDN/edge caching; нужен persisted queries или отдельные REST-эндпоинты для тяжелых ресурсов.



Чек-лист для принятия решения (практический)

Клиенты — браузеры? мобильные? сторонние интеграторы?
браузер/мобильный фронт → GraphQL выгоден;
сторонние сторонние потребители → REST предпочтителен (совместимость).

Нужен ли стриминг / двунаправленная связь?
да → gRPC;
нет → GraphQL/REST.


Высокая нагрузка внутри сети (RTT, пропускная способность)?
да → gRPC;

Требуется гибкость выбора полей клиентом и уменьшение запросов?
да → GraphQL;

Требуется простое кеширование через CDN/HTTP?
да → REST (или реализовать persisted queries для GraphQL).

Нужно строгая схема и codegen для многих языков?
gRPC или GraphQL (оба дают schema/codegen).


Рекомендованные архитектурные сочетания (рецепты)

Внутренние микросервисы (gRPC) + GraphQL BFF + браузерный фронт — оптимальный вариант для больших команд: скорость внутри, гибкость для фронтенда.
REST public API + GraphQL internal BFF for web clients — если нужно максимально простое публичное API, но гибкость для своих фронтенд-команд.
gRPC end-to-end — когда все клиенты контролируются и могут использовать gRPC (например, мобильный клиент с gRPC-Web или нативный клиент).


Пример архитектуры

Сценарий: крупное приложение с веб-клиентом и мобильными приложениями + множество микросервисов.
Внутренние микросервисы: общаются по gRPC (protobuf).
Aggregation Layer: GraphQL BFF. Он:
вызывает gRPC сервисы (stub-ы),
использует DataLoader / batching для борьбы с N+1,
кеширует часто запрашиваемые фрагменты,
реализует field-level авторизацию.
Фронтенд: запрашивает GraphQL; для критичных статических ресурсов (изображения) используется CDN.
Преимущество: фронтенд получает гибкий API, внутренние сервисы остаются быстрыми и типобезопасными.



#Java #middle #GraphQL
👍1
Что выведет код?

public class Task271125 {
public static void main(String[] args) {
int i = 0;
do {
i++;
if (i == 2) continue;
System.out.print(i + " ");
} while (i < 3 && i > 0);

System.out.print("end: " + i);
}
}


#Tasks
Варианты ответа:
Anonymous Quiz
30%
1 end: 1
10%
1 3 end: 2
40%
1 3 end: 3
20%
1 2 3 end: 3
Вопрос с собеседований

Что делает метод Objects.requireNonNull()? 🤓


Ответ:

Метод Objects.requireNonNull() проверяет аргумент на null и выбрасывает NullPointerException с сообщением при нарушении.

Это позволяет явно гарантировать корректность входных параметров и упростить диагностику ошибок.

Применяется в конструкторах, сеттерах и публичных API.



#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
История IT-технологий сегодня — 28 ноября


ℹ️ Кто родился в этот день

Кристиан Керстинг (родился 28 ноября 1973 года в Куксхафене, Германия) — немецкий учёный в области ИИ и машинного обучения, профессор, возглавляющий лабораторию по ИИ и машинному обучению (AIML) в Darmstadt; значимые публикации в probabilistic inductive logic programming.


🌐 Знаковые события

1964 — к Марсу запущена американская автоматическая станция «Маринер-4».


#Biography #Birth_Date #Events #28Ноября
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2