JavaRush /Курсы /JAVA 25 SELF /module-info.java: синтаксис, создание модулей

module-info.java: синтаксис, создание модулей

JAVA 25 SELF
60 уровень , 1 лекция
Открыта

1. Что такое module-info.java и где он находится?

Модуль в Java всегда начинается с файла module-info.java. Это своего рода «паспорт» модуля, где вы объявляете его имя, экспортируемые пакеты и зависимости от других модулей.

Где искать?
Файл module-info.java должен находиться в корне папки исходников вашего модуля. Например, если у вас структура проекта такая:

project-root/
└── src/
    └── my.module.name/
        ├── module-info.java
        └── com/
            └── example/
                └── api/
                    └── MyClass.java

Здесь my.module.name — это имя модуля (о правилах именования чуть позже).

Без этого файла модуль просто не считается модулем!
Если его нет — это обычный «старый» Java‑проект, пусть даже с кучей папок и классов.

2. Синтаксис module-info.java: основные элементы

Давайте сразу посмотрим на пример самого простого файла — это не страшно, честно!

module my.module.name {
    exports com.example.api;
    requires java.sql;
}

Разберём по кусочкам:

module my.module.name { ... }
Это объявление модуля с именем my.module.name. Имя модуля — это уникальный идентификатор, обычно совпадающий с корневым пакетом (например, com.example.app).
Забавный факт: если вы назовёте модуль java.base, то компилятор будет не в восторге. Не стоит пытаться подменять стандартные модули.

exports com.example.api;
Эта строчка говорит: «Я, модуль, готов поделиться всем, что находится в пакете com.example.api». Всё, что внутри этого пакета и помечено как public, будет видно другим модулям. Всё остальное — строго для своих.

requires java.sql;
А вот тут мы честно признаёмся компилятору: «Мне для работы нужен стандартный модуль java.sql». Без этого компилятор не даст нам использовать классы из этого модуля.

Дополнительные ключевые слова (для общего развития)

  • opens <package>; — открывает пакет для рефлексии (например, для библиотек сериализации типа Jackson).
  • uses <service-interface>; — говорит, что модуль использует некий сервис (интерфейс).
  • provides <service-interface> with <implementation-class>; — сообщает, что модуль предоставляет реализацию сервиса.

В этой лекции мы сосредоточимся на exports и requires — они нужны в подавляющем большинстве учебных и боевых проектов.

3. Примеры module-info.java

Пример 1. Минимальный модуль

module com.example.hello {
    exports com.example.hello.api;
}
  • Этот модуль экспортирует только пакет com.example.hello.api.
  • Всё, что лежит, например, в com.example.hello.internal, будет скрыто от других модулей, даже если там есть public-классы.

Пример 2. Модуль с зависимостью

module com.example.dbclient {
    exports com.example.db.api;
    requires java.sql;
}

Мы можем использовать JDBC, но только потому, что честно объявили зависимость от java.sql.

Пример 3. Несколько экспортируемых пакетов

module com.example.library {
    exports com.example.library.api;
    exports com.example.library.utils;
}

Можно экспортировать сколько угодно пакетов (но не стоит экспортировать всё подряд — в этом смысл модулей!).

4. Ограничения и правила

Имя модуля

  • Обычно совпадает с корневым пакетом (например, com.example.app).
  • Не должно совпадать с именами стандартных модулей (java.base, java.sql и т.п.).
  • Не должно содержать пробелов, спецсимволов, начинаться с цифры и т.д.
  • Рекомендация: используйте обратное доменное имя вашей организации или проекта, чтобы избежать конфликтов.

Один модуль — один module-info.java
В одном модуле может быть только один такой файл. Если их два — компилятор устроит вам «модульный скандал».

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

Пакеты внутри модуля
Можно экспортировать только те пакеты, которые реально существуют в структуре исходников этого модуля. Экспорт несуществующего пакета приведёт к ошибке компиляции.

5. Практика: создаём module-info.java в проекте

Допустим, у нас есть простой проект со следующим содержимым:

project-root/
└── src/
    └── com.example.greetings/
        ├── module-info.java
        └── com/
            └── example/
                └── greetings/
                    ├── api/
                    │   └── Greeter.java
                    └── internal/
                        └── SecretSauce.java

Шаг 1. Создаём module-info.java

module com.example.greetings {
    exports com.example.greetings.api;
}

Шаг 2. Пробуем использовать класс из internal‑пакета в другом модуле

Допустим, у нас есть второй модуль com.example.app, который хочет получить доступ к SecretSauce:

module com.example.app {
    requires com.example.greetings;
}

import com.example.greetings.internal.SecretSauce; // ОШИБКА!

Результат:
Компилятор скажет: «Пакет com.example.greetings.internal не экспортируется модулем com.example.greetings». Даже если класс SecretSaucepublic, он недоступен другим модулям.
Это и есть настоящая инкапсуляция на уровне модулей!

Шаг 3. Пробуем не объявить requires

Если в com.example.app мы не напишем requires com.example.greetings;, а попытаемся использовать класс из com.example.greetings.api, компилятор выдаст ошибку:

package com.example.greetings.api is not visible

6. Типичные ошибки при работе с module-info.java

Ошибка №1: Несовпадение имени модуля и структуры проекта.
Если вы назовёте модуль com.example.app, а структура папок будет src/main/java/app, компилятор не поймёт, что вы от него хотите. Имя модуля обычно совпадает с корневым пакетом, а папки должны это отражать.

Ошибка №2: Экспорт всего подряд.
Экспортировать нужно только то, что реально должно быть видно другим модулям. Не надо делать exports com.example; просто потому, что «так проще». Это нарушает инкапсуляцию.

Ошибка №3: Забыл добавить requires.
Если вы используете классы из другого модуля или стандартной библиотеки (например, java.sql), но забыли объявить зависимость — будет ошибка компиляции.

Ошибка №4: Несуществующий пакет в exports.
Если вы написали exports com.example.foo;, а такого пакета нет — компилятор скажет, что вы «экспортируете воздух».

Ошибка №5: Публичные классы в неэкспортируемом пакете.
Если класс объявлен public, но лежит в пакете, который не экспортируется, этот класс будет виден только внутри модуля. Это не ошибка, но часто становится неожиданностью для новичков.

Ошибка №6: Несколько module-info.java в одном модуле.
В одном модуле должен быть только один файл module-info.java. Если их два — компилятор не сможет собрать проект.

1
Задача
JAVA 25 SELF, 60 уровень, 1 лекция
Недоступна
Подключение к цифровому океану данных 🌐
Подключение к цифровому океану данных 🌐
1
Задача
JAVA 25 SELF, 60 уровень, 1 лекция
Недоступна
Разблокировка многогранной библиотеки 💎
Разблокировка многогранной библиотеки 💎
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ