From 0a1c9a38b3d499806777c2a02868acc0741408e8 Mon Sep 17 00:00:00 2001 From: Nikolay Gagarinov Date: Thu, 25 Jun 2026 19:58:34 +0500 Subject: [PATCH] =?UTF-8?q?feat(40-methods-definition):=20=D0=B4=D0=BE?= =?UTF-8?q?=D0=B1=D0=B0=D0=B2=D0=B8=D1=82=D1=8C=20=D1=83=D1=80=D0=BE=D0=BA?= =?UTF-8?q?=20=D0=BF=D1=80=D0=BE=20=D0=BF=D0=B0=D0=BA=D0=B5=D1=82=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Перенос DEFER-темы из Python (40-define-functions/350-modules + 400-packages), теория взята из нативного курса java_basics_course/340-packages. Урок 500-packages (RU-only): package, соответствие директориям, вложенные пакеты, import (короткие и fully-qualified имена, import *), статический импорт. Упражнение: amountPerPerson через static import Math.ceil (зеркало Python). Co-Authored-By: Claude Opus 4.8 (1M context) --- .../500-packages/App.java | 10 +++ .../500-packages/Makefile | 2 + .../500-packages/Test.java | 10 +++ .../500-packages/ru/EXERCISE.md | 10 +++ .../500-packages/ru/README.md | 84 +++++++++++++++++++ .../500-packages/ru/data.yml | 15 ++++ 6 files changed, 131 insertions(+) create mode 100644 modules/40-methods-definition/500-packages/App.java create mode 100644 modules/40-methods-definition/500-packages/Makefile create mode 100644 modules/40-methods-definition/500-packages/Test.java create mode 100644 modules/40-methods-definition/500-packages/ru/EXERCISE.md create mode 100644 modules/40-methods-definition/500-packages/ru/README.md create mode 100644 modules/40-methods-definition/500-packages/ru/data.yml diff --git a/modules/40-methods-definition/500-packages/App.java b/modules/40-methods-definition/500-packages/App.java new file mode 100644 index 00000000..d5e949e3 --- /dev/null +++ b/modules/40-methods-definition/500-packages/App.java @@ -0,0 +1,10 @@ +import static java.lang.Math.ceil; + +public class App { + public static int amountPerPerson(double total, int people, int tipPercent) { + // BEGIN + double withTip = total * (1 + tipPercent / 100.0); + return (int) ceil(withTip / people); + // END + } +} diff --git a/modules/40-methods-definition/500-packages/Makefile b/modules/40-methods-definition/500-packages/Makefile new file mode 100644 index 00000000..d0d0a48c --- /dev/null +++ b/modules/40-methods-definition/500-packages/Makefile @@ -0,0 +1,2 @@ +test: + @ test.sh diff --git a/modules/40-methods-definition/500-packages/Test.java b/modules/40-methods-definition/500-packages/Test.java new file mode 100644 index 00000000..4332fb4e --- /dev/null +++ b/modules/40-methods-definition/500-packages/Test.java @@ -0,0 +1,10 @@ +import static org.assertj.core.api.Assertions.assertThat; + +class Test { + public static void main(String[] args) { + assertThat(App.amountPerPerson(300, 4, 0)).isEqualTo(75); + assertThat(App.amountPerPerson(300, 4, 20)).isEqualTo(90); + assertThat(App.amountPerPerson(350, 3, 10)).isEqualTo(129); + assertThat(App.amountPerPerson(100, 3, 0)).isEqualTo(34); + } +} diff --git a/modules/40-methods-definition/500-packages/ru/EXERCISE.md b/modules/40-methods-definition/500-packages/ru/EXERCISE.md new file mode 100644 index 00000000..2722baa6 --- /dev/null +++ b/modules/40-methods-definition/500-packages/ru/EXERCISE.md @@ -0,0 +1,10 @@ +Реализуйте метод `amountPerPerson()`. Он принимает сумму счета в ресторане `total`, количество человек `people` и процент чаевых `tipPercent`, а возвращает сумму, которую платит каждый. Итог округляется **вверх** — никто не должен недоплатить. + +Для округления вверх используйте метод `ceil()`. Он уже подключен в начале файла статическим импортом из класса `Math`, поэтому вызывать его можно без префикса `Math.`. + +```java +App.amountPerPerson(300, 4, 20); // => 90 +App.amountPerPerson(350, 3, 10); // => 129 +``` + +Сначала посчитайте итоговую сумму с чаевыми, затем разделите ее на количество человек и округлите вверх. Результат метода `ceil()` имеет тип `double`, а вернуть нужно `int` — не забудьте про приведение типа. diff --git a/modules/40-methods-definition/500-packages/ru/README.md b/modules/40-methods-definition/500-packages/ru/README.md new file mode 100644 index 00000000..900a38a8 --- /dev/null +++ b/modules/40-methods-definition/500-packages/ru/README.md @@ -0,0 +1,84 @@ +Когда программа растет, в ней становится не только больше строк кода, но и больше классов. Каждый класс решает свою задачу и лежит в отдельном файле, а в реальном приложении таких файлов могут быть сотни и тысячи. Часть классов пишут сами, часть приходит вместе с подключенными библиотеками. + +При таком количестве классов почти неизбежно возникает ситуация, когда два разных класса получают одинаковые имена. Если два класса с одинаковым именем оказываются в одном проекте, программа не скомпилируется. Свой класс переименовать можно, а вот с классом из чужой библиотеки так не получится. Поэтому требование уникальности имен сильно мешало бы переиспользовать чужой код. + +Чтобы решить эту проблему, в Java используют **пакеты**. Пакет — это механизм для объединения классов в логически связанные группы. Пакеты похожи на папки в файловой системе: как папки организуют файлы, так пакеты организуют классы. Разные пакеты могут содержать классы с одинаковыми именами, и конфликта не возникнет. + +## Определение пакетов + +Пакет задают ключевым словом `package` в самом начале файла, сразу после него идет имя пакета: + +```java +// Файл company/User.java +package company; + +public class User { + // код для работы с пользователем +} +``` + +Структура пакетов связана с файловой структурой проекта: имя пакета соответствует директории, в которой лежит файл. Пакеты бывают вложенными — тогда и директории вложены друг в друга. Если класс лежит в пакете `io.hexlet.model`, то и файл находится в директории `io/hexlet/model`. + +Обычно имя пакета начинают с префикса, закрепленного за компанией или разработчиком, — чаще всего это доменное имя в обратном порядке. Например, для домена `hexlet.io` пакеты начинаются с `io.hexlet`. Дальше структура зависит от архитектуры приложения: классы группируют по смыслу, например в пакет `model` складывают основные сущности — пользователей и курсы: + +```java +// Файл io/hexlet/model/User.java +package io.hexlet.model; + +public class User { + public static String getGreeting(String userName) { + return "Hello, " + userName + "!"; + } +} +``` + +## Импорт классов + +Классы из одного пакета обращаются друг к другу просто по имени. Но постоянно приходится использовать и классы из других пакетов. Чтобы обратиться к классу из другого пакета, его нужно импортировать — для этого служит ключевое слово `import`, после которого идет полное имя класса: + +```java +package io.hexlet; + +import io.hexlet.model.User; + +class App { + public static void main(String[] args) { + var greeting = User.getGreeting("John"); + System.out.println(greeting); + } +} +``` + +После импорта к классу обращаются по короткому имени. Без импорта пришлось бы каждый раз писать полное (fully qualified) имя, включая название пакета: + +```java +var greeting = io.hexlet.model.User.getGreeting("John"); +``` + +Полное имя выручает, когда в одном месте нужны два класса с одинаковым именем из разных пакетов: один класс импортируют, а ко второму обращаются по полному имени. + +Можно импортировать сразу все классы пакета с помощью `*`: + +```java +import java.util.*; +``` + +Так удобно, когда из пакета нужно много классов, но злоупотреблять этим не стоит: импорт «всего подряд» захламляет пространство имен и повышает риск конфликта имен между пакетами. + +## Статический импорт + +Java позволяет импортировать не только классы, но и отдельные статические методы — тогда их можно вызывать без указания класса. Это удобно, когда какой-то метод используется часто, и делает код компактнее: + +```java +import static java.lang.Math.ceil; + +public class App { + public static void main(String[] args) { + // Имя класса Math при вызове можно опустить + double result = ceil(2.3); // 3.0 + System.out.println(result); + } +} +``` + +Можно импортировать и сразу все статические методы класса: `import static java.lang.Math.*;`. Статический импорт мы используем в задании этого урока. diff --git a/modules/40-methods-definition/500-packages/ru/data.yml b/modules/40-methods-definition/500-packages/ru/data.yml new file mode 100644 index 00000000..cce711e9 --- /dev/null +++ b/modules/40-methods-definition/500-packages/ru/data.yml @@ -0,0 +1,15 @@ +--- +name: Пакеты +tips: + - > + [Пример приложения на Java с пакетами и + импортами](https://github.com/hexlet-boilerplates/java-package) +definitions: + - name: Пакет + description: >- + механизм группировки классов в логически связанные группы; помогает + избежать конфликтов имен. Задается ключевым словом `package`. + - name: import + description: >- + ключевое слово, которое подключает класс из другого пакета, чтобы + обращаться к нему по короткому имени без указания пакета.