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

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

Наш канал на RUTube - https://rutube.ru/channel/37896292/
Download Telegram
6. Конвенции именования и работа под капотом

Понимание того, как имена идентификаторов обрабатываются в JVM, помогает оценить их влияние на производительность и структуру программы.

6.1. Хранение идентификаторов в памяти

Идентификаторы (имена классов, методов, полей) хранятся в Metaspace как часть метаданных класса. Они представляют собой строки, которые компилируются в байт-код и загружаются в JVM при загрузке класса.
Длина имени идентификатора не влияет на размер объекта в куче (Heap), так как имена хранятся отдельно в Metaspace. Однако длинные имена могут незначительно увеличить объем метаданных.


6.2. Влияние на байт-код
В байт-коде идентификаторы преобразуются в ссылки на строки в пуле констант (constant pool) класса. Это позволяет JVM эффективно работать с именами, минимизируя их влияние на производительность.
JVM не различает стили именования (camelCase, PascalCase и т.д.), так как они являются лишь соглашениями для разработчиков. Однако несоблюдение конвенций может запутать инструменты анализа кода.


6.3. Рефлексия и имена
Рефлексия в Java (например, через Class.getMethod) использует имена методов и полей. Правильные имена (например, getName) позволяют рефлексии точно находить нужные элементы.
Неправильные имена (например, name вместо getName для геттера) могут привести к ошибкам при использовании рефлексии в фреймворках, таких как Spring или Hibernate.

Пример:
import java.lang.reflect.Method;

class Example {
public String getName() {
return "Test";
}
}

class ReflectionTest {
public static void main(String[] args) throws Exception {
Method method = Example.class.getMethod("getName"); // Работает
// Method method = Example.class.getMethod("name"); // Ошибка, если метод не существует
}
}


6.4. Оптимизация и производительность
Длина имени: Хотя длинные имена увеличивают объем метаданных в Metaspace, их влияние на производительность минимально благодаря оптимизациям JVM, таким как интернирование строк.
Читаемость vs. производительность: Длинные, но описательные имена (например, calculateTotalOrderPrice) предпочтительнее коротких и неясных (например, calc), так как читаемость важнее незначительных затрат памяти.
Инструменты минимизации: При использовании инструментов, таких как ProGuard, имена могут быть обфусцированы (сокращены) для уменьшения размера байт-кода, но это не влияет на исходный код.


6.5. Утечки памяти и имена
Неправильные имена не напрямую вызывают утечки памяти, но они могут привести к ошибкам, которые косвенно влияют на память. Например, если метод с именем clear не очищает ресурсы, а разработчик предполагает обратное, это может привести к удержанию объектов в куче.
Четкие имена, такие как releaseResources, помогают избежать таких недоразумений.



7. Лучшие практики

Следуйте официальным конвенциям: Используйте рекомендации Oracle’s Java Code Conventions для обеспечения совместимости с другими проектами.
Будьте описательны, но лаконичны: Имена должны быть понятными, но не избыточно длинными (например, getCustomerName лучше, чем getTheNameOfTheCustomer).
Используйте глаголы для методов: Методы должны начинаться с глагола, описывающего действие (например, calculate, get, set).
Избегайте неоднозначности: Не используйте имена, которые могут быть поняты неправильно (например, process может означать слишком многое).
Документируйте через имена: Делайте код самодокументирующимся, используя понятные имена вместо избыточных комментариев.
Проверяйте с помощью линтеров: Используйте инструменты, такие как Checkstyle, для автоматической проверки соблюдения конвенций.


Пример самодокументирующегося кода:

class OrderProcessor {
// Хорошо: имя метода понятно без комментариев
public double calculateTotalPrice(List<Item> items) {
return items.stream().mapToDouble(Item::getPrice).sum();
}
}


#Java #для_новичков #beginner #java_syntax #Conventions
👍2
Что выведет код?

public class Task080725 {
public static void main(String[] args) {
int String = 10;
System.out.println(String);
}
}


#Tasks
👍1
Варианты ответа:
Anonymous Quiz
65%
Ошибка компиляции
10%
"String"
15%
10
10%
null
😱1
Чем отличается forEach от forEachOrdered в Stream API? 🤓

Ответ:

forEach() выполняет действие для каждого элемента потока в произвольном порядке (особенно в параллельных потоках).

forEachOrdered() гарантирует обработку в порядке следования элементов, но может быть медленнее.

Пример:
List<String> list = Arrays.asList("a", "b", "c");
list.parallelStream().forEach(System.out::println); // Порядок не гарантирован

list.parallelStream().forEachOrdered(System.out::println); // a, b, c

#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
📌 Факт дня:

А вы знали, что первый "цифровой текстовый редактор" был создан в 1967 году?

Программа QED, разработанная для компьютеров SDS 940, позволяла редактировать текст в реальном времени. Она вдохновила современные редакторы, такие как Vim и Notepad.

Proof

#facts
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
📌 Цитата дня: Исаак Брук

"ЭВМ должна быть не только умной, но и доступной."


Исаак Брук, разработчик первой в мире ЭВМ М-1 на полупроводниках, сказал это в 1950 году на заседании АН СССР, обсуждая важность технологий.


Биография

#Citation #Biography
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Модульность и многомодульные проекты в Maven

Многомодульный проект в Maven — это проект, состоящий из нескольких подмодулей (submodules), каждый из которых является самостоятельным Maven-проектом со своим POM.xml. Все модули объединяются под общим родительским (parent) или агрегирующим (aggregator) POM.xml, который определяет общую конфигурацию и координирует сборку.

Основные характеристики:
Каждый модуль имеет собственный жизненный цикл, артефакты (JAR, WAR и т.д.) и зависимости.
Родительский POM задает общие настройки, такие как версии плагинов, зависимости и свойства.
Модули могут зависеть друг от друга, образуя граф зависимостей.
Сборка выполняется централизованно через родительский POM или выборочно для отдельных модулей.


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


Структура: Aggregator (Parent POM) vs Parent Project

Многомодульный проект может использовать два подхода к организации: aggregator POM и parent POM. Хотя термины часто пересекаются, их роли различаются.

Aggregator POM

Агрегирующий POM — это файл, который перечисляет модули проекта в секции <modules> и координирует их сборку. Он не обязательно содержит конфигурацию, а служит для запуска сборки всех модулей.

Пример:
<project>
<groupId>com.example</groupId>
<artifactId>aggregator</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging>
<modules>
<module>module-api</module>
<module>module-core</module>
<module>module-web</module>
</modules>
</project>


Упаковка: <packaging>pom</packaging> указывает, что проект не создает артефакт (JAR/WAR), а только управляет модулями.
Сборка: Команда mvn package в директории aggregator вызывает сборку всех модулей в порядке, определенном реактором (см. ниже).


Parent POM

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

Пример:
<project>
<groupId>com.example</groupId>
<artifactId>parent</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging>
<properties>
<java.version>11</java.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.3.20</version>
</dependency>
</dependencies>
</dependencyManagement>
<modules>
<module>module-api</module>
<module>module-core</module>
</modules>
</project>


Модуль наследует настройки из родительского POM:
<project>
<parent>
<groupId>com.example</groupId>
<artifactId>parent</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>module-api</artifactId>
</project>


Наследование: Модули наследуют <groupId>, <version>, <properties>, <dependencyManagement>, <pluginManagement> и другие настройки.
Отличие: Родительский POM может существовать отдельно от агрегирующего, например, в другом проекте. Модули ссылаются на него через <parent>, но могут не быть перечислены в <modules>.


В памяти Maven загружает родительский POM первым, создавая базовую модель, которая затем дополняется конфигурацией каждого модуля. Если родительский POM находится в удаленном репозитории, Maven загружает его из ~/.m2/repository или скачивает, что добавляет сетевые операции и временное использование памяти.

Aggregator vs Parent

Aggregator: Управляет сборкой модулей через <modules>. Не обязательно является родительским.
Parent: Определяет наследуемую конфигурацию через <parent>. Может не быть агрегирующим.
Комбинация: Часто один POM выполняет обе роли, что упрощает структуру.


#Java #middle #Maven #Profiles #Parent_POM #MultiModule #Module_Inheritance
👍1
Module Inheritance

Наследование в многомодульных проектах позволяет централизовать конфигурацию.

Модули наследуют от родительского POM:

Метаданные: <groupId>, <version> (если не переопределены в модуле).
Свойства: <properties> для общих настроек, таких как версии Java или библиотек.
Управление зависимостями: <dependencyManagement> задает версии зависимостей, которые модули могут использовать без указания версии.
Управление плагинами: <pluginManagement> определяет версии и конфигурации плагинов.
Репозитории: <repositories> и <pluginRepositories> для загрузки артефактов.


Пример наследования зависимостей:
<!-- parent POM -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>

<!-- module POM -->
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
</dependencies>


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


Нюансы наследования

Переопределение: Модуль может переопределить унаследованные настройки, например, указав собственный <version> или <properties>.
Глубокое наследование: Если родительский POM сам наследуется от другого POM, Maven рекурсивно загружает все родительские модели, что увеличивает потребление памяти.
Конфликты: Неправильное переопределение (например, дублирование плагинов) может вызвать ошибки. Используйте mvn help:effective-pom для анализа итоговой конфигурации.



Разделение по слоям: API, Core, Impl, Web


Многомодульные проекты часто структурируются по слоям для разделения ответственности.


Типичная структура:
API: Содержит интерфейсы, DTO и публичные контракты. Упаковка — JAR. Пример: module-api.
Core: Реализует бизнес-логику, зависящую от API. Упаковка — JAR. Пример: module-core.
Impl: Конкретные реализации, например, интеграция с базами данных. Упаковка — JAR. Пример: module-impl.
Web: Веб-приложение, зависящее от Core или Impl. Упаковка — WAR. Пример: module-web.


Пример структуры:
project-root/
├── pom.xml (parent/aggregator)
├── module-api/
│ └── pom.xml
├── module-core/
│ └── pom.xml
├── module-impl/
│ └── pom.xml
├── module-web/
│ └── pom.xml


Зависимости между модулями:
<!-- module-core POM -->
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>module-api</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>

<!-- module-web POM -->
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>module-core</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>


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


Преимущества разделения

Модульность: Упрощает тестирование и повторное использование.
Четкие границы: Снижает связанность между компонентами.
Параллельная разработка: Команды могут работать над разными модулями независимо.


Нюансы

Циклические зависимости: Maven не допускает циклических зависимостей между модулями (например, module-api зависит от module-core, а module-core — от module-api). Это проверяется реактором, и при обнаружении цикла сборка завершается с ошибкой.
Размер графа: Большое количество модулей увеличивает сложность графа зависимостей, что требует больше памяти для хранения и обработки.



#Java #middle #Maven #Profiles #Parent_POM #MultiModule #Module_Inheritance
👍1
Best Practices

Versioning и dependencyManagement

Единая версия: Используйте одинаковую версию для всех модулей, унаследованную от родительского POM (${project.version}). Это упрощает управление и предотвращает несовместимость.
dependencyManagement: Централизуйте версии зависимостей в родительском POM:<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.3.20</version>
</dependency>
</dependencies>
</dependencyManagement>


Это снижает дублирование и обеспечивает согласованность версий.
pluginManagement: Аналогично управляйте версиями плагинов:<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.10.1</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
</plugins>
</pluginManagement>


В памяти dependencyManagement и pluginManagement хранятся как часть родительской POM-модели, минимизируя дублирование данных в модулях.


CI/CD подходы с модулями

Полная сборка: Настройте CI/CD (например, Jenkins, GitHub Actions) для выполнения полной сборки через mvn clean install в корне проекта. Это гарантирует, что все модули совместимы.
Инкрементальная сборка: Для ускорения используйте флаг --also-make (-am) или --projects (-pl) для сборки только измененных модулей (см. ниже).


Публикация артефактов: Используйте mvn deploy для загрузки артефактов в репозиторий (например, Nexus).
Настройте <distributionManagement> в родительском POM:<distributionManagement>
<repository>
<id>nexus</id>
<url>https://nexus.example.com/repository/maven-releases/</url>
</repository>
</distributionManagement>


Параллельная сборка: Используйте флаг -T (например, -T 4) для параллельного выполнения модулей. Это ускоряет сборку, но увеличивает пиковое потребление памяти из-за одновременной обработки нескольких POM-моделей.


Сборка части дерева

Maven позволяет собирать отдельные модули или их поддерево с помощью опций реактора:
Выбор модуля: Собрать только указанный модуль:mvn package -pl module-web
Включение зависимостей: Собрать модуль и все его зависимости:mvn package -pl module-web -am
Исключение модулей: Пропустить модуль:mvn package -pl !module-api


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


Работа с реактором

Реактор (Reactor) — это внутренний механизм Maven, который управляет порядком сборки модулей в многомодульном проекте.


Реактор:
Строит граф модулей: Анализирует <modules> в агрегирующем POM и зависимости между модулями (через <dependencies>).
Определяет порядок: Выполняет топологическую сортировку графа, чтобы модули, от которых зависят другие, собирались первыми.
Координирует сборку: Запускает жизненный цикл для каждого модуля в рассчитанном порядке.


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

Нюансы реактора

Циклические зависимости: Реактор обнаруживает циклы и завершает сборку с ошибкой. Используйте mvn dependency:tree для анализа.
Пропуск модулей: Флаг -pl или -am изменяет граф, который обрабатывает реактор, уменьшая объем памяти.
Ошибки: Если модуль завершает сборку с ошибкой, реактор останавливает процесс, но промежуточные артефакты сохраняются в target.


#Java #middle #Maven #Profiles #Parent_POM #MultiModule #Module_Inheritance
👍1
Жизненный цикл в многомодульных проектах

Жизненный цикл в многомодульных проектах аналогичен одномодульному, но применяется к каждому модулю индивидуально. Основные фазы (Clean, Default, Site) выполняются в порядке, определенном реактором.

Последовательность: Реактор вызывает фазы жизненного цикла (например, validate, compile, package) для каждого модуля по очереди. Например, mvn package сначала выполнит package для module-api, затем для module-core и так далее.
Параллельность: С флагом -T Maven выполняет фазы для независимых модулей параллельно, что ускоряет сборку, но увеличивает потребление памяти из-за одновременной загрузки нескольких POM-моделей и плагинов.
Общие ресурсы: Родительский POM задает общие плагины и зависимости, которые загружаются в память один раз и используются всеми модулями, оптимизируя ресурсы.
Пропуск фаз: Флаги, такие как -DskipTests, применяются ко всем модулям, что снижает нагрузку на память.


В памяти Maven хранит модель жизненного цикла для каждого модуля, включая привязки плагинов к фазам. Для крупных проектов это может привести к значительному потреблению памяти, особенно на фазах, таких как compile или test, где загружаются исходные файлы, зависимости и результаты тестов.

Нюансы

Инкрементальная сборка: Maven использует временные метки файлов в target, чтобы пропускать неизмененные модули. Это снижает нагрузку на память и процессор.
Ошибки в модуле: Если одна фаза завершается с ошибкой в модуле, Maven останавливает сборку, но уже созданные артефакты сохраняются.
Кэширование артефактов: Модули, установленные в ~/.m2/repository (через mvn install), не пересобираются при повторных запусках, что оптимизирует производительность.



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

Управление памятью:
Maven загружает модель POM для каждого модуля, создавая объединенную модель проекта. Это увеличивает потребление памяти пропорционально количеству модулей.
Реактор строит граф модулей в памяти, что требует дополнительных ресурсов для хранения и сортировки.
Параллельная сборка (-T) увеличивает пиковое потребление памяти из-за одновременной обработки нескольких модулей.
Для оптимизации используйте -pl для выборочной сборки и настройте JVM с помощью -Xmx.


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


Конфликты зависимостей:
Модули могут использовать разные версии одной библиотеки, что приводит к конфликтам. Используйте <dependencyManagement> для согласованности.
Плагин maven-enforcer-plugin с правилом dependencyConvergence помогает выявить конфликты.


Производительность:
Инкрементальная сборка и кэширование ускоряют процесс, но первый запуск или полная сборка (mvn clean) могут быть медленными.
Параллельная сборка сокращает время, но требует мощного оборудования из-за высокой нагрузки на память и процессор.


Отладка:
Используйте mvn -X для вывода подробной информации о порядке сборки и загрузке модулей.
Команда mvn dependency:tree -pl module-name помогает анализировать зависимости конкретного модуля.
Плагин help:effective-pom показывает итоговую конфигурацию модуля с учетом наследования.


CI/CD интеграция:
Настройте CI/CD для выполнения mvn clean install на каждое изменение, чтобы гарантировать целостность всех модулей.
Используйте матричные сборки для тестирования модулей в разных окружениях (например, разные версии Java).
Храните SNAPSHOT-версии в репозитории (например, Nexus) для промежуточных сборок, а релизные версии — в отдельном репозитории.


#Java #middle #Maven #Profiles #Parent_POM #MultiModule #Module_Inheritance
👍1
Что выведет код?

import java.util.function.Function;

public class Task090725 {
public static void main(String[] args) {
Function<Integer, Integer> f = x -> x * 2;
Function<Integer, Integer> g = x -> x + 3;

System.out.println(f.compose(g).apply(5));
System.out.println(f.andThen(g).apply(5));
}
}


#Tasks
👍2
Варианты ответа:
Anonymous Quiz
20%
13 16
30%
10 13
20%
16 10
30%
16 13
👍2
Что такое TreeMap и как он работает? 🤓

Ответ:

TreeMap — реализация Map, основанная на красно-черном дереве, которая хранит ключи в отсортированном порядке. Время операций — O(log n).

Пример:
TreeMap<String, Integer> map = new TreeMap<>();
map.put("B", 2);
map.put("A", 1);
System.out.println(map.keySet()); // [A, B]

Подходит для задач, где важен порядок ключей, но медленнее HashMap.

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