Java for Beginner
681 subscribers
578 photos
158 videos
12 files
880 links
Канал от новичков для новичков!
Изучайте Java вместе с нами!
Здесь мы обмениваемся опытом и постоянно изучаем что-то новое!

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

Наш канал на RUTube - https://rutube.ru/channel/37896292/
Download Telegram
Варианты ответа:
Anonymous Quiz
0%
0
71%
5
19%
15
10%
Ошибка компиляции
Продолжаем выбирать темы для разбора и голосовать за рассмотрение предложенных! 🤓

Голосуем за тему к рассмотрению в эти выходные!

Выбираем новую тему!
(можете предложить что-то из того, что предлагали на прошлой и позапрошлых неделях и что проиграло в голосовании!)

Не стесняемся! ✌️
Please open Telegram to view this post
VIEW IN TELEGRAM
Что такое паттерн Factory Method? 🤓

Ответ:

Factory Method — паттерн проектирования, где метод создает объекты подклассов, скрывая детали их создания. Определяется в абстрактном классе или интерфейсе, а подклассы реализуют логику.

Пример:
interface Shape {
static Shape create(String type) {
return switch (type) {
case "circle" -> new Circle();
case "square" -> new Square();
default -> throw new IllegalArgumentException();
};
}
}

class Circle implements Shape {}
class Square implements Shape {}

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

#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
Управление зависимостями в Maven

Управление зависимостями — одна из ключевых возможностей Maven, которая позволяет автоматизировать загрузку, разрешение и использование библиотек в проекте. Maven обеспечивает централизованное управление зависимостями через локальный и удаленные репозитории, а также предоставляет механизмы для работы с транзитивными зависимостями, разрешения конфликтов и настройки специфичных сценариев.


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


Maven использует декларативный подход к управлению зависимостями, которые определяются в файле POM.xml в секции <dependencies>.


Каждая зависимость указывается через три ключевых атрибута:
groupId: Уникальный идентификатор организации или проекта.
artifactId: Имя артефакта.
version: Версия артефакта.


Пример:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.3.20</version>
</dependency>


Когда Maven выполняет сборку, он разрешает зависимости следующим образом:
Загрузка POM-модели: Maven парсит POM.xml, создавая объектную модель проекта (POM model) в оперативной памяти. Эта модель включает информацию о зависимостях, репозиториях и настройках.
Поиск зависимостей: Maven сначала проверяет локальный репозиторий (~/.m2/repository). Если зависимость отсутствует, он обращается к удаленным репозиториям, указанным в <repositories> или унаследованным из super POM (по умолчанию Maven Central).
Загрузка артефактов: Maven скачивает JAR-файлы и их POM-файлы, сохраняя их в локальном репозитории. В памяти создаются структуры данных, представляющие зависимости, включая их метаданные (groupId, artifactId, version).
Разрешение транзитивных зависимостей: Maven анализирует POM-файлы загруженных зависимостей, чтобы определить их собственные зависимости (см. ниже).


В памяти Maven хранит граф зависимостей — направленный ациклический граф (DAG), где узлы представляют зависимости, а ребра — их взаимосвязи. Этот граф используется для определения порядка загрузки и разрешения конфликтов. Размер графа зависит от количества зависимостей и их транзитивных связей, что может значительно увеличивать потребление памяти в крупных проектах.


Транзитивные зависимости

Транзитивные зависимости — это зависимости, которые требуются другим зависимостям. Например, если проект зависит от spring-core, а spring-core требует commons-logging, то commons-logging становится транзитивной зависимостью.


Maven автоматически включает транзитивные зависимости в сборку, что упрощает управление, но может привести к конфликтам или ненужным библиотекам.

Процесс разрешения транзитивных зависимостей:
Maven загружает POM-файл каждой зависимости и рекурсивно анализирует их <dependencies>.
Все найденные зависимости добавляются в граф зависимостей, который хранится в памяти.
Maven применяет правила разрешения конфликтов (см. ниже) для выбора подходящих версий.


Транзитивные зависимости увеличивают объем данных в памяти, так как Maven должен загрузить и обработать все связанные POM-файлы. Для оптимизации Maven кэширует зависимости в локальном репозитории, но при первом разрешении или при использовании флага --update-snapshots может происходить интенсивная сетевая активность.


Dependency Mediation и Nearest-Wins Strategy

Когда разные зависимости требуют одну и ту же библиотеку, но с разными версиями, возникает конфликт.

Maven использует стратегию dependency mediation с правилом nearest-wins (ближайший побеждает):
Nearest-wins strategy: Maven выбирает версию зависимости, которая находится ближе к корню графа зависимостей (т.е. имеет меньшую глубину в цепочке транзитивных зависимостей).
Пример: Если проект напрямую зависит от commons-logging:1.2, а другая зависимость требует commons-logging:1.1, то Maven выберет 1.2, так как она указана в корневом POM-файле (глубина 1). Если обе версии находятся на одинаковой глубине, Maven выберет ту, что встретилась первой в порядке парсинга.


#Java #middle #Maven #Dependencies
В памяти Maven строит граф зависимостей, где каждая версионная коллизия разрешается путем выбора ближайшей версии. Это требует хранения временных структур данных для сравнения версий, что может быть ресурсоемким для проектов с большим количеством зависимостей.

Для явного контроля версий можно использовать секцию <dependencyManagement> в POM-файле:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
</dependencies>
</dependencyManagement>


Зависимости, указанные в <dependencyManagement>, имеют приоритет над транзитивными, что позволяет избежать конфликтов. Эти данные загружаются в память как часть POM-модели и применяются во время разрешения графа.


Dependency Convergence

Dependency convergence — это концепция, которая требует, чтобы в графе зависимостей использовалась только одна версия каждой библиотеки. Нарушение конвергенции (например, использование двух версий одной библиотеки) может привести к ошибкам, таким как ClassNotFoundException или несовместимость API.


Для обеспечения конвергенции используется плагин maven-enforcer-plugin с правилом dependencyConvergence:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<version>3.4.1</version>
<executions>
<execution>
<id>enforce</id>
<goals>
<goal>enforce</goal>
</goals>
<configuration>
<rules>
<dependencyConvergence/>
</rules>
</configuration>
</execution>
</executions>
</plugin>


Если плагин обнаруживает конфликт версий, сборка завершается с ошибкой. В памяти maven-enforcer-plugin загружает полный граф зависимостей для анализа, что может значительно увеличить потребление ресурсов в крупных проектах.


Optional Dependencies

Опциональные зависимости (<optional>true</optional>) — это зависимости, которые не включаются в транзитивный граф проектов, использующих данный артефакт. Они полезны, когда библиотека предоставляет дополнительные функции, которые не требуются всем потребителям.


Пример:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.36</version>
<optional>true</optional>
</dependency>


Если проект A включает slf4j-api как опциональную зависимость, то проект B, зависящий от A, не унаследует slf4j-api, пока не объявит его явно. Это уменьшает размер графа зависимостей, снижая потребление памяти и вероятность конфликтов.

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


BOM (Bill of Materials)

BOM-файл — это специальный POM-файл, который определяет версии зависимостей для согласованного управления ими в проекте или группе проектов. BOM используется через <dependencyManagement> с областью видимости (scope) import.

Пример использования BOM от Spring Boot:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.7.18</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>


BOM-файл загружается в память как часть POM-модели и предоставляет централизованный список версий, которые применяются ко всем зависимостям в проекте. Это упрощает управление версиями и обеспечивает согласованность, особенно в многомодульных проектах. В памяти BOM увеличивает объем данных, так как Maven должен загрузить и обработать дополнительный POM-файл.

#Java #middle #Maven #Dependencies
Использование import scope

Область видимости import используется исключительно в <dependencyManagement> для импорта BOM-файлов. Она позволяет включить конфигурацию зависимостей из внешнего POM-файла, не добавляя сам артефакт в сборку.

Пример:

<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.example</groupId>
<artifactId>custom-bom</artifactId>
<version>1.0.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>


В памяти Maven загружает импортированный POM-файл как часть модели проекта, добавляя его зависимости в структуру <dependencyManagement>. Это увеличивает потребление памяти, но упрощает управление версиями, так как все модули проекта используют единый набор версий.



Dependency Tree (mvn dependency:tree) и анализ конфликтов

Плагин maven-dependency-plugin с целью tree позволяет визуализировать граф зависимостей:
mvn dependency:tree


Пример вывода:
[INFO] com.example:my-project:jar:1.0-SNAPSHOT
[INFO] +- org.springframework:spring-core:jar:5.3.20:compile
[INFO] | \- commons-logging:commons-logging:jar:1.2:compile
[INFO] \- org.junit.jupiter:junit-jupiter:jar:5.9.2:test


Команда dependency:tree загружает в память полный граф зависимостей, включая транзитивные зависимости, и выводит его в консоль. Это полезно для анализа конфликтов и выявления нежелательных зависимостей. Для более детального анализа можно использовать флаг -Dverbose для отображения исключенных или конфликтующих версий.


Для разрешения конфликтов можно:
Исключить зависимости:
```
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.3.20</version>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>

Исключения уменьшают размер графа зависимостей, снижая потребление памяти.
Явно указать версию в <dependencyManagement> для принудительного выбора версии.

```

Использовать dependency:analyze для выявления неиспользуемых или необъявленных зависимостей:
mvn dependency:analyze


В памяти dependency:tree создает временные структуры для хранения графа, что может быть ресурсоемким для проектов с сотнями зависимостей. Оптимизация, такая как использование <exclusions> или BOM, помогает сократить объем данных.


Нюансы и внутренние механизмы

Управление памятью:
Граф зависимостей хранится в памяти как DAG, где каждый узел представляет артефакт, а ребра — зависимости. Размер графа пропорционален количеству зависимостей.
Maven использует Aether (библиотеку для работы с репозиториями), которая загружает метаданные зависимостей в память. Это может привести к пиковому потреблению памяти при первом разрешении.
Для оптимизации используйте флаг -o (offline) для работы с локальным кэшем или настройте JVM с помощью -Xmx.


Кэширование:
Локальный репозиторий (~/.m2/repository) кэширует JAR-файлы, POM-файлы и метаданные, что снижает сетевую нагрузку.
Maven хранит метаданные о версиях в файлах _remote.repositories, что ускоряет повторное разрешение.


Конфликты и Classpath:
Неправильное разрешение зависимостей может привести к включению двух версий одной библиотеки в classpath, вызывая ошибки вроде NoClassDefFoundError.
Используйте dependency:tree и maven-enforcer-plugin для предотвращения таких проблем.


Параллельное разрешение:
В многомодульных проектах Maven разрешает зависимости для каждого модуля отдельно, но кэширует результаты в памяти. Параллельное выполнение (-T) увеличивает пиковое потребление памяти из-за одновременной обработки нескольких графов.

Сетевые проблемы:
Если удаленный репозиторий недоступен, Maven может завершиться с ошибкой. Настройка зеркал в settings.xml или использование --offline помогает избежать этого.


#Java #middle #Maven #Dependencies
Что выведет код?

public class Task030725 {
private static int counter = 0;

public static void main(String[] args) throws InterruptedException {
Runnable task = () -> {
for (int i = 0; i < 1_000_000; i++) {
counter++;
}
};

Thread t1 = new Thread(task);
Thread t2 = new Thread(task);

t1.start();
t2.start();

t1.join();
t2.join();

System.out.println(counter);
}
}


#Tasks
Что такое паттерн Builder и зачем он нужен? 🤓

Ответ:

Builder — паттерн для пошагового создания сложных объектов с множеством параметров.
Упрощает создание объектов и улучшает читаемость.

Пример:
class User {
private String name;
private int age;
private User(Builder builder) {
this.name = builder.name;
this.age = builder.age;
}
static class Builder {
private String name;
private int age;
Builder setName(String name) {
this.name = name; return this; }
Builder setAge(int age) { this.age = age; return this; }
User build() { return new User(this); }
}
}
User user = new User.Builder().setName("Alice").setAge(25).build();

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

#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM