Статьи

Полный курс по языку Java — от установки JDK до многопоточности и HTTP-запросов

Пакеты и организация проекта

Страница 24 из 30 · 2026-10-25 · 4 мин чтения

Пакеты

Пакет — пространство имен для группы классов. Он решает две задачи:

  • избегает конфликтов имен (java.util.Date и java.sql.Date);
  • группирует код по назначению.

Имя пакета в нижнем регистре, обычно в виде обратного доменного имени: com.example.shop.

Пакет обязан соответствовать структуре каталогов:

src/└── com/    └── example/        └── shop/            ├── Main.java            ├── model/            │   ├── Product.java            │   └── Order.java            ├── service/            │   └── OrderService.java            └── util/                └── Formatter.java

Объявление пакета

Первая строка файла (кроме комментариев):

package com.example.shop.model;public record Product(int id, String name, double price) {}
package com.example.shop.model;import java.util.List;public record Order(int id, List<Product> products) {    public double total() {        return products.stream().mapToDouble(Product::price).sum();    }}

Импорт

package com.example.shop.service;import com.example.shop.model.Order;import com.example.shop.model.Product;import java.util.ArrayList;import java.util.List;public class OrderService {    private final List<Order> orders = new ArrayList<>();    public Order create(List<Product> products) {        Order order = new Order(orders.size() + 1, products);        orders.add(order);        return order;    }    public int count() {        return orders.size();    }}

Варианты импорта:

import java.util.List;import java.util.*;import static java.lang.Math.max;import static java.lang.Math.*;

Импорт со звездочкой подключает все классы пакета, но не вложенные пакеты. Предпочитайте явные импорты. Вместо импорта можно писать полное имя: java.util.List<String> list;.

Главный класс

package com.example.shop;import com.example.shop.model.Product;import com.example.shop.service.OrderService;import java.util.List;public class Main {    public static void main(String[] args) {        OrderService service = new OrderService();        var order = service.create(List.of(            new Product(1, "Книга", 12.5),            new Product(2, "Ручка", 1.2)        ));        System.out.println("Сумма заказа: " + order.total());        System.out.println("Заказов: " + service.count());    }}

Компиляция и запуск из корня проекта:

javac -d out $(find src -name "*.java")java -cp out com.example.shop.Main

На Windows в PowerShell:

javac -d out (Get-ChildItem -Recurse src -Filter *.java).FullNamejava -cp out com.example.shop.Main

Модификаторы доступа и пакеты

Член класса без модификатора виден только внутри своего пакета. Это удобно для внутренних классов, которые не должны быть частью публичного API:

package com.example.shop.util;class InternalHelper {    static String trim(String s) {        return s.strip();    }}
package com.example.shop.util;public class Formatter {    public static String price(double value) {        return String.format("%.2f руб.", value);    }    public static String clean(String s) {        return InternalHelper.trim(s);    }}

Класс InternalHelper недоступен вне пакета util.

Как организовать проект

Два распространенных подхода.

По слоям:

com.example.shop├── controller├── service├── repository└── model

По функциональности:

com.example.shop├── orders│   ├── Order.java│   ├── OrderService.java│   └── OrderRepository.java└── products    ├── Product.java    └── ProductService.java

Для небольших проектов подходят слои. В крупных системах чаще группируют по предметной области: связанный код лежит рядом.

Общие принципы:

  • один файл — один публичный класс;
  • имена пакетов короткие, существительные;
  • классы одного пакета тесно связаны по смыслу;
  • зависимости направлены в одну сторону: например, service знает про model, но model не знает про service;
  • не создавайте пакет utils как свалку разнородного кода.

Стандартная структура Maven и Gradle

Сборщики ожидают определенную раскладку:

project/├── pom.xml├── src/│   ├── main/│   │   ├── java/│   │   │   └── com/example/shop/Main.java│   │   └── resources/│   │       └── application.properties│   └── test/│       ├── java/│       │   └── com/example/shop/MainTest.java│       └── resources/└── target/

Исходники — в src/main/java, тесты — в src/test/java, ресурсы — в src/main/resources. Подробнее о сборке — в главе про Maven и Gradle.

Чтение ресурсов

Файлы из resources попадают в classpath и читаются так:

import java.io.IOException;import java.io.InputStream;import java.nio.charset.StandardCharsets;public class ResourceReader {    public static void main(String[] args) throws IOException {        try (InputStream in = ResourceReader.class.getResourceAsStream("/application.properties")) {            if (in == null) {                System.out.println("Ресурс не найден");                return;            }            System.out.println(new String(in.readAllBytes(), StandardCharsets.UTF_8));        }    }}

Путь, начинающийся с /, считается от корня classpath.

Модули Java

Начиная с Java 9 есть система модулей. Файл module-info.java в корне исходников описывает, что модуль требует и что открывает:

module com.example.shop {    requires java.net.http;    exports com.example.shop.model;}

Для учебных и большинства прикладных проектов модули не обязательны. Если IDE предлагает создать module-info.java, на начальном этапе можно отказаться.

Организация зависимостей

Внешние библиотеки поставляются как .jar. Подключать их вручную через -cp неудобно, поэтому используют Maven или Gradle: они скачивают библиотеки и их зависимости автоматически.

Практика

Создайте проект «Библиотека»:

  1. Пакет library.model: record Book(String title, String author, int year).
  2. Пакет library.service: класс Catalog с методами add, findByAuthor, sortedByYear.
  3. Пакет library: класс Main, который добавляет книги и печатает результаты.
  4. Скомпилируйте проект из консоли и запустите через java -cp.