Пакеты
Пакет — пространство имен для группы классов. Он решает две задачи:
- избегает конфликтов имен (
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: они скачивают библиотеки и их зависимости автоматически.
Практика
Создайте проект «Библиотека»:
- Пакет
library.model:record Book(String title, String author, int year). - Пакет
library.service: классCatalogс методамиadd,findByAuthor,sortedByYear. - Пакет
library: классMain, который добавляет книги и печатает результаты. - Скомпилируйте проект из консоли и запустите через
java -cp.
