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 0000000..d5e949e --- /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 0000000..d0d0a48 --- /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 0000000..4332fb4 --- /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 0000000..2722baa --- /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 0000000..900a38a --- /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 0000000..cce711e --- /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: >- + ключевое слово, которое подключает класс из другого пакета, чтобы + обращаться к нему по короткому имени без указания пакета.