Лабораторна робота 1

Архітектура та синтаксис Java

1 Завдання на лабораторну роботу

1.1 Індивідуальне завдання

Створити консольну програму, в якій здійснюється обчислення значень функції на певному інтервалі. У програмі треба визначити значення початку інтервалу, кінця інтервалу, а також величини кроку, з яким змінюється аргумент. Відповідні значення слід прочитати з клавіатури.

Програма повинна містити визначення та введення необхідних даних і один великий цикл, у тілі якого здійснюється

  • обчислення функції одним з варіантів, залежно від значення аргументу
  • виведення на консоль аргументу та результату на кожному кроці циклу
  • збільшення значення аргументу на величину кроку і перехід на наступне обчислення, якщо необхідно.

Програма повинна складатися з одного класу з двома статичними функціями:

  • окрема статична функція для обчислення значення y залежно від значення аргументу x;
  • метод main(), в якому здійснюється читання вихідних даних, а також цикл обчислення функції та виведення значень x та y.

Варіант функціональної залежності, який слід реалізувати у програмі, визначається відповідно до номера студента у списку групи. Визначену константу n описати з модифікатором final. Для форматованого виведення результатів застосувати функцію printf().

1.2 Степені числа 8

Увести значення n (від 0 до 10) і вивести значення степенів числа 8 до n включно. Реалізувати два підходи – з використанням арифметичних і побітових операцій.

1.3 Використання break і continue з міткою

Увести значення x та n, обчислити та вивести результат виразу:

Якщо i дорівнює j + x, перейти на наступний крок зовнішнього циклу без множення на проміжний результат. Для переходу на наступний крок застосувати continue з міткою.

Якщо знаменник на якійсь ітерації дорівнює 0, вийти з обох циклів з виведенням повідомлення про помилку. Для виходу застосувати break з міткою.

1.4 Бібліотека функцій для перетворення типів

Створити клас зі статичними функціями перетворення аргументу типу boolean у ціле значення (0 або 1) і навпаки (нуль – false, ненульове значення – true). Продемонструвати роботу функцій, викликавши їх з іншого класу іншого пакету. Застосувати звичайний і статичний імпорт.

2 Методичні вказівки

2.1 Мова програмування Java і Java-платформа

2.1.1 Загальні концепції

Під Java розуміють:

  • мову програмування;
  • програмну платформу.

Робота над мовою Java почалася з 1990 р. Програміст компанії Sun Microsystems Патрік Ноутон (Patrick Naughton) сформулював проблеми адаптації програмного забезпечення до різних платформ та пристроїв, які існували в компанії. Патріка Ноутона було включено в автономну групу, якою керував Джеймс Гослінг (James Gosling). Першою назвою мови був Oak. Назва Java з'явилася в 1995 р.

Одночасно у світі виникла та стрімко розвивалася глобальна мережа Internet. У 1995 році компанія представила власний браузер HotJava з підтримкою Java-аплетів.

23 січня 1996 р. вийшов офіційний реліз JDK 1.0.

У 1997 році Microsoft намагалася включити підтримку істотно зміненої Java у Visual Studio 97. Після судового розгляду у 2001 р. Microsoft втратила право надалі використовувати торговельну марку Java.

Основними властивостями мови є такі:

  • кросплатформна (синтаксис мови та набір стандартних засобів не залежить від певної операційної системи та типу комп'ютера);
  • стандартизована;
  • об'єктно-орієнтована;
  • підтримує строгу типізацію (обмежена кількість примітивних типів, удосконалені правила перетворення типів);
  • легка в засвоєнні та розробці;
  • забезпечує підвищену надійність завдяки відсутності вказівників та обов'язковій перевірці віртуальною машиною коду класів, що завантажуються, і дій, які виконує програма;
  • пристосована до розробки Інтернет-застосунків.

Для запобігання багатьох типових помилок, притаманних програмам на C++, запропоновано механізм автоматичного збирання сміття (garbage collection). Цей механізм автоматично підраховує кількість посилань на кожний об'єкт Java. Коли на об'єкт більше не вказує жодне посилання, він вважається непотрібним та може бути видалений з пам'яті, звільняючи ресурси для програми.

Синтаксис Java багато в чому схожий з C++. Разом з тим, Java має властивість кросплатформності (транспортабельності), застосовує інтерпретатор байт-коду, використовує іншу об'єктну модель (аналогічну C#), тобто іншу сукупність об'єктно-орієнтованих концепцій і набору засобів опису класів і зв'язків між ними, а також механізмів створення об'єктів, та ін.

На відміну від багатьох інших мов і систем програмування, сирцевий код Java компілюється не безпосередньо в машинні команди, а в так званий байт-код. Набір команд цього коду повинен бути інтерпретований для виконання на конкретному комп'ютері під керуванням конкретної операційної системи. Іншими словами, потрібна спеціальна програмна платформа.

Програмна платформа у загальному випадку включає набір програмних засобів, що забезпечують виконання інших програм. Програмні засоби, що складають програмну платформу, як правило, мають стандартний набір функцій, технічно по-різному реалізованих на різних апаратних платформах і в різних операційних системах. Java-платформу складають віртуальна машина Java і стандартні класи.

Віртуальна машина Java (Java Virtual Machine) – це програма, яка інтерпретує і виконує байт-код, попередньо створений з сирцевого тексту програми компілятором.

Крім мови Java, наведені нижче мови також створені для розробки Java-застосунків:

  • Clojure
  • Kotlin
  • Processing
  • Groovy
  • Scala
  • Gosu
  • Fantom
  • Ateji PX
  • JRuby
  • Jython
  • Rhino
  • Ceylon
  • Flow
  • Join Java
  • Pizza
  • Ballerina
  • Ateji PX
  • Oxygene

Крім того, низка раніше створених універсальних мов також забезпечує створення застосунків для JVM:

  • Ada
  • AWK
  • BASIC
  • BBx
  • Boo
  • C
  • COBOL
  • ColdFusion
  • Common Lisp
  • Simula
  • Component Pascal
  • Erlang
  • Forth
  • Go
  • JavaScript
  • Logo
  • Lua
  • Oberon-2
  • OCaml
  • Raku
  • Object Pascal
  • Pascal
  • PHP
  • Prolog
  • Python
  • REXX
  • Ruby
  • Scheme
  • Tcl
  • Smalltalk

Кількість мов, орієнтованих на JVM дуже швидко розширюється. Продовжують створюватися нові мови з підтримкою JVM.

Концептуально платформа Java реалізована на різних рівнях, залежно від призначення програмних застосунків:

  • Java Card – технологія, яка дозволяє безпечно запускати невеликі Java-програми (аплети) на смарткартах та подібних пристроях малої пам'яті.
  • Java ME (Micro Edition) – визначає кілька різних наборів бібліотек для пристроїв з обмеженими можливостями; її часто використовують для розробки додатків для мобільних пристроїв, КПК, телевізорів та принтерів.
  • Java Platform, Standard Edition, (Java SE) – стандартна версія платформи Java, призначена для створення і виконання застосунків, розрахованих на індивідуальне користування;
  • Java Platform, Enterprise Edition, скорочено Java EE – платформа, яка реалізує серверну архітектуру для задач середніх і великих підприємств.

Технічно платформа Java SE також реалізована на двох рівнях (до Java 8 включно):

  • Java Runtime Environment (JRE) – середовище виконання Java-програм. Фізично це набір програмних засобів, що включають віртуальну машину Java і бібліотеку класів.
  • Java Development Kit (JDK) – комплект розробника застосунків мовою Java, що включає в себе компілятор Java (javac), стандартні бібліотеки класів Java, приклади, документацію, різні утиліти і середовище виконання Java-програм (JRE).

2.1.2 Версії Java

Кожна нова версія Java має нові можливості в порівнянні з попередньою.

  • Java версії 1.2 (4 грудня 1998) настільки перевершувала платформу 1.1, що, починаючи з неї, усі наступні версії назвали платформою Java 2.
  • Починаючи з JDK 1.5 (29 вересня 2004) заведено казати про Java 5. У цій версії істотно розширено синтаксис і засоби стандартних бібліотек.
  • Версія Java 6 (JDK 1.6, 11 грудня 2006) відрізняється від попередньої переважно розширеними бібліотеками класів.
  • Версія Java 7 (28 липня 2011) окрім розширених бібліотек класів, надає нові зручні синтаксичні конструкції.
  • Java 8 (18 березня 2014) завдяки розширенням можливостям інтерфейсів, наявності лямбда-виразів, а також появі Stream API надає можливість реалізації функційного та декларативного програмування. Це істотно вплинуло на стиль і виразність Java-програмування.
  • Починаючи з 2017 року версії Java додаються кожні пів року.

Серед останніх версій окремо можна виділити версії з тривалою підтримкою (англ. long-term support), підтримку яких, на відміну від інших версій, заплановано здійснювати декілька років, а не до публікації наступної версії. Остання версія з тривалою підтримкою – Java 21 (вересень 2023 року). Подальші приклади в тексті орієнтовані на використання Java 21.

На жаль, у версіях, починаючи з дев'ятої, не повністю реалізовано принцип зворотної сумісності. Код, створений у попередніх версіях Java, не може бути виконаний без додаткового перероблювання та перекомпіляції. Через ці проблеми Java 8 залишається розповсюдженою версією серед розроблювачів і теж передбачає подальшу підтримку (до грудня 2030 року).

2.1.3 Інсталяція Java 21

Для того, щоб застосунок Java можна було виконати на конкретному комп'ютері, на ньому необхідно встановити JDK. На сайті oracle.com переходимо на сторінку завантаження Java (Products | Java | Download Java). Можна одразу перейти до сторінки за адресою https://www.oracle.com/java/technologies/downloads/. Серед доступних версій вибираємо таку, для якої здійснюється довготривала підтримка. На сьогодні це Java 21.

Вибираємо варіант інсталяції для своєї операційної системи (Installer). Якщо робота здійснюється під управлінням операційної системи Windows, найкращим варіантом буде x64 Installer. Після завантаження інсталятора на виконання вам пропонують вибрати теку для розташування програми (можна залишити без змін). На останній сторінці майстра інсталяції слід натиснути Close.

Після завершення можна перевірити успішність встановлення, набравши в командному рядку (Start | Run... cmd) таку команду:

java -version

У консольному вікні буде виведена версія JRE.

2.2 Інтегроване середовище розробки IntelliJ IDEA

2.2.1 Інтегровані середовища розробки для Java-програмування

В перші роки існування Java програмісти користувалися засобами компіляції, які завантажуються з командного рядка. Разом з тим, для інших мов програмування існували потужні середовища розробки, такі як Visual C++, Borland Delphi тощо. Візуальні засоби середовищ для автоматизації створення та зневадження програм істотно підвищували продуктивність праці програмістів. Загалом існують десятки комерційних і безплатних IDE для Java. Нижче наведені найбільш популярні середовища, а також ті, які історично найбільше вплинули на розвиток Java-розробки.

  • Історично першим було Visual Café for Java (1996 р.) – середовище, яке розповсюджувалося на комерційних засадах. Проєкт проіснував до 2002 року.
  • Випуск комерційного середовища Microsoft Visual Studio 97 (1997 р.) містив підтримку Visual J++ – "Java від Microsoft". Потім як мова .NET-розробки підтримувалася мова Visual J# (до 2007 р.)
  • JBuilder – комерційне середовище, створене у 1997 р. компанією Borland. Остання версія CodeGear JBuilder 2008 вийшла у 2009 р.
  • Oracle JDeveloper – безплатне середовище розробки (з 2005 р.), перша версія IDE 1998 року була комерційною. Середовище в першу чергу орієнтовано на використання технологій Oracle. Остання стабільна версія вийшла у 2016 р.
  • BlueJ – інтегроване середовище розробки Java із відкритим кодом, яке застосовується з метою засвоєння програмування початківцями, а також в невеличких проєктах.
  • NetBeans – безплатне середовище розробки декількома мовами програмування (в першу чергу Java). Проєкт NetBeans IDE підтримується і спонсорується компанією Oracle. NetBeans успішно конкурує з найбільш розповсюдженими середовищами (Eclipse й IntelliJ IDEA), але поступається у гнучкості й продуктивності.
  • Eclipse IDE – найбільш популярне у світі кросплатформне безплатне середовище розробки. Спочатку Eclipse розроблялося фірмою IBM як наступник середовища розробки IBM VisualAge. Eclipse характеризується гнучкістю й можливістю нарощування функціональності через механізм плагінів.
  • JetBrains IntelliJ IDEA – найбільш потужне середовище професійної розробки Java-застосунків. IDE розповсюджується у двох варіантах. Безкоштовна версія Community Edition дозволяє створювати застосунки Java SE, повна версія Ultimate Edition, яка дозволяє, зокрема, розробляти серверні рішення, є комерційною.

2.2.2 Встановлення IDE IntelliJ IDEA і створення першого проєкту

Інтегроване середовище розробки IntelliJ IDEA – застосунок, повністю написаний на Java. Проте для встановлення IDE Java не обов'язково повинна бути заздалегідь встановлена на комп'ютері. Під час встановлення IntelliJ IDEA автоматично встановлюється спеціальний варіант віртуальної машини Java – JetBrainsRuntime. Але для компіляції застосунків JetBrainsRuntime не може бути застосована. Необхідно встановити стандартну версію JDK.

Існує два варіанти IDE, які підтримують різні підмножини технологій Java. Безплатний варіант Community Edition забезпечує повній набір засобів розробки для платформи Java SE мовами Java, Kotlin, Groovy та Scala, засоби управління проєктом, роботи з репозиторієм, тестування та зневадження програм. Варіант Ultimate Edition підтримує повний набір технологій, додатково включаючи Java EE, Spring Framework, спеціальні засоби роботи з базами даних, підтримку розробки на JavaScript і TypeScript тощо.

Програму встановлення середовища програмування IntelliJ IDEA можна звантажити зі сторінки завантаження Download IntelliJ IDEA - The Leading Java and Kotlin IDE сайту компанії JetBrains. Обираємо варіант Ultimate Edition.

Примітка: з цієї сторінки можна також завантажити варіант Community Edition, але студенти, які мають академічні акаунти, можуть користуватися повною версією (Ultimate Edition).

Після завантаження інсталятора його потрібно запустити на виконання. Натискаючи кнопку Next, проходимо по сторінках майстра встановлення.

  • На сторінці Choose Install Location вибираємо теку для встановлення (можна залишити без змін).
  • На сторінці Installation Options опції також можна залишити без змін.
  • На сторінці Choose Start Menu Folder вибираємо групу в меню Пуск і натискаємо кнопку Install.
  • Після встановлення IntelliJ IDEA на останній сторінці майстра можна відразу вибрати опцію Run IntelliJ IDEA і натиснути Finish.

Після першого запуску середовища нам пропонують погодитися з умовами ліцензії. Якщо IntelliJ IDEA раніше встановлювалася на комп'ютері, нам пропонують вікно, в якому можна вибрати варіант імпорту установок попередньої версії. Якщо IntelliJ IDEA встановлюється вперше, ніякі опції імпортувати не потрібно.

Для активації IntelliJ IDEA можна скористатися академічним акаунтом, натиснувши кнопку Log In to JetBrains Account.... Розкривається вікно браузера, в якому можна або зайти в наявний акаунт JetBrtains, або створити новий. Далі у вікні Licenses можна натиснути кнопки Activate і Continue.

У вікні Welcome to IntelliJ IDEA усталено обрано позицію Projects. З цієї позиції логічно починати під час першого запуску. Вибираємо створення нового проєкту (кнопка New Project).

Примітка. У закладці Customize вікна Welcome to IntelliJ IDEA можна, зокрема, здійснити загальні налаштування стилів середовища. Кольорова тема (Color theme) вибирається на свій розсуд. Можна також змінити розмір шрифту, налаштування клавіш тощо.

На сторінці майстра для нового проєкту вибрані найбільш розповсюджені опції, зокрема, позиція Java. Середовище намагається знайти встановлені JDK. Якщо це не вдалося, можна зі списку в рядку JDK вибрати функцію Add JDK... і вказати шлях до раніше встановленого JDK, або встановити JDK, завантаживши його з Internet (функція Download JDK).

Якщо вибрати опцію Add sample code і не вибирати опцію Generate code with onboarding tips, до проекту буде додано файл Main.java з таким кодом:

public class Main {
    public static void main(String[] args) {
        System.out.println("Hello world!");
    }
}

У тілі функції main() замість виведення рядка "Hello World" можна розмістити необхідній програмний код.

Для запуску програми на виконання можна скористатися функцією головного меню Run | Run 'Main.java', зеленою стрілкою в панелі інструментів або клавішною комбінацією Shift+F10. У разі успішної компіляції здійснюється виконання програми. У нижній частині головного вікна з'являється спеціальна область, що імітує роботу в командному вікні.

Якщо під час створення нового проєкту включити опцію Generate code with onboarding tips, буде згенеровано більш складний сирцевий код. Робота з цим кодом дозволяє спробувати складніші способи роботи – зневадження, використання підказки для виправлення окремих фрагментів коду тощо.

2.2.3 Елементи графічного інтерфейсу користувача IDE IntelliJ IDEA. Використання шаблонів коду та гарячих клавіш

Головне вікно IDE включає як традиційні для всіх сучасних інтегрованих середовищ елементи користувацького інтерфейсу (меню, панель інструментів, головне вікно редактору, рядок стану), так і специфічний для середовища IntelliJ IDEA набір інструментальних вікон (Tool Windows). Інструментальні вікна мають кнопки виклику, розташовані по периметру робочої області, з піктограмою, підписом і числовим позначенням (останнє не обов'язково). Якщо на ці кнопки натиснути, поруч з ними відкриються віконця з деякою допоміжною функціональністю.

У стандартному головному меню впадає в очі відсутність функції збереження. Автозбереження відбувається під час запуску програми або під час виходу з програми.

Підменю головного меню пропонують потужні засоби управління кодом (Navigate, Code, Analyze і Refactor). У таблиці наведені деякі функції для роботи з кодом та відповідні гарячі клавіші:

Функція меню Опис Клавіатурна комбінація
Navigate | Back Перейти до попереднього місця перегляду або редагування Ctrl+Alt+Left
Navigate | Forward Перейти до наступного місця перегляду або редагування Ctrl+Alt+Right
Navigate | Previous Highlighted Error Перейти до попередньої знайденої помилки в коді Shift+F2
Navigate | Next Highlighted Error Перейти до наступної знайденої помилки в коді F2
Code | Override methods Перевизначити метод базового класу Ctrl+O
Code | Implement methods Реалізувати метод абстрактного класу або інтерфейсу Ctrl+I
Code | Generate... Згенерувати фрагмент коду (конструктор, гетери й сетери, перевизначені методи тощо) Alt+Insert

Редактор IntelliJ IDEA підтримує велику кількість клавішних комбінацій для редагування. Крім стандартної роботи з буфером, підтримується, наприклад, видалення рядка (Ctrl-Y), дублювання рядки або блоку (Ctrl-D), перехід до точок переривання (Ctrl+номер_точки_переривання), коментування блоку (Ctrl+/) тощо.

Комбінація Ctrl-пропуск дозволяє отримати список можливих елементів об'єкта, параметрів методу тощо. Клавішна комбінація Ctrl-Shift-пропуск фільтрує список, залишивши тільки варіанти очікуваного типу.

Використовуючи комбінацію Ctrl+Alt+L, можна відформатувати код.

Корисна клавішна комбінація Alt-Enter дозволяє отримати набір варіантів виправлення помилки, яка виникла (наприклад, додати директиву import, згенерувати порожній метод тощо).

Перелік всіх клавішних комбінацій можна отримати у вікні Settings, далі Keymap (File | Settings...) .

У рядку, розташованому безпосередньо після рядка меню, показаний шлях до файлу, який ми редагуємо (всередині проєкту), а також, найбільш вживані функції (вибір програми для запуску, кнопки запуску та налагодження, отримання структури проєкту та пошуку).

Середовище IntelliJ IDEA істотно полегшує введення сирцевого коду завдяки використанню шаблонів коду (Live Templates). Викликати відповідну функцію можна через головне меню (Code | Insert Live Template...) або за допомогою клавішної комбінації Ctrl-J. З'являється список шаблонів коду. Список залежить від контексту (розташування курсора у вікні редактору). Найбільш корисні шаблони наведені в таблиці:

Послідовність символів Програмний код
psvm
public static void main(String[] args)
St
String
psf
public static final
fori
for (int i = 0; i < ; i++)
itar
for (int i = 0; i < args.length; i++) {
    String arg = args[i];

}
ifn
if ( == null) {
     
}
iter
for (Object o : ) {
    
}
sout
System.out.println();

Шаблони можна також просто набирати в коді відповідною послідовністю літер. Після появи віконця підказки підтверджуємо введення й отримуємо відповідний текст у вікні редактору.

2.2.4 Використання зневаджувача

Запуск програми для зневадження може здійснюватися за допомогою функції головного меню Run | Debug 'Main', кнопкою із зображенням зеленого жука в панелі інструментів або клавішною комбінацією Shift+F9. У найпростішому випадку для зневадження програми досить вказати точку переривання (кликнути мишею на вертикальній сірій смузі ліворуч від необхідного рядку) і запустити програму на зневадження. Виконання програми зупиниться на вибраному рядку, після чого проміжні значення змінних можна подивитися в області виведення Variables або просто розмістивши курсор миші над змінною в програмному коді. В підменю Run | Debugging Actions під час налагодження доступні різні варіанти виконання програми по кроках:

  • Step into (F7) – з заходженням у функції, що викликаються
  • Step over (F8) – без заходження в функції, що викликаються.

2.2.5 Структура проєкту

Для кожного проєкту створюється окремий каталог (з ім'ям проєкту, далі Проєкт). Файли кореневої теки проєкту містять інформацію про модулі. Проєкт може включати кілька окремих модулів. Інформація про конкретний модуль міститься у файлі з розширенням .iml.

Тека src містить пакети з сирцевим кодом проєкту. Тека out містить результат компіляції сирцевого коду. Всередині теки out знаходиться підкаталог production, в ньому – Проєкт, далі структура тек повторять аналогічну структуру тек підкаталогу src.

Опції проєкту, пов'язані з компіляцією, кодуванням і т.д., представлені файлами прихованої теки .idea.

2.3 Базові засоби мови Java

2.3.1 Загальна структура програми мовою Java. Особливості виконання програми

У Java немає глобальних змінних, функцій чи процедур. Це зроблено з метою запобігання конфліктів імен. Програма складається з одного чи більше описів класів з полями (елементами даних) і методами (функціями-елементами). Класи в Java можуть мати модифікатор public Такі класи мають назву відкритих (публічних). Один із відкритих класів повинен визначати статичний метод main(), з якого починається виконання програми. Програмний код визначення класів слід зберігати у текстових файлах з розширенням .java. Ім'я класу (без розширення) повинне збігатися з іменем публічного класу, який міститься у цьому файлі. Слід пам'ятати, що великі й маленькі літери відрізняються.

Кожен клас компілюється в окремий файл, що містить двійковий код і має розширення .class. На відміну від С++, це не команди процесора, а байт-коди.

Скомпільована програма може бути виконана на комп'ютері, лише якщо на ньому встановлена так звана віртуальна машина Java (JVM, Java Virtual Machine) – спеціальна програма, яка здійснює інтерпретацію байт-кодів. Такий підхід дозволяє створювати програми, які можна переносити з одного операційного середовища (операційної системи, апаратної платформи) на інше без додаткової перекомпіляції. На відміну від C++, Java не передбачає статичного компонування коду у файл, який може бути виконано (.exe). Компонування (отримання байт-коду з різних файлів з розширенням .class або зі спеціальних архівів та інтерпретація коду) здійснюється динамічно.

Починаючи з Java 9, запропоновано модульну структуру коду. Спеціальний файл module-info.java, який можна створити в проєкті, містить таку інформацію:

  • визначення модулів, від яких залежить цей модуль,
  • інформацію про пакети, які експортує цей модуль,
  • список сервісів, які надає модуль.

Модульна структура підвищує ефективність завантаження і виконання великих Java-застосунків.

2.3.2 Ідентифікатори, ключові та зарезервовані слова. Коментарі

Як і в C++, у мові Java відрізняються великі та маленькі літери.

Сирцевий код Java складається з лексем. Лексема (token) – це послідовність символів, що мають певне сукупне значення. Проміж окремими лексемами розташовують розділювачі – пропуск, табуляція, новий рядок тощо.

Лексеми поділяються на такі групи:

  • ключові (зарезервовані) слова
  • ідентифікатори
  • літерали (константи)
  • знаки операцій.

Як і в C++, ключове слово – це лексема, яка має єдиний наперед визначений сенс в програмному коді. Усі ключові слова є зарезервованими. Зарезервовані слова не можна використовувати як ідентифікатори. У Java також існують зарезервовані слова, які не є ключовими. Їх взагалі не можна використовувати. Це const та goto.

Примітка: починаючи з Java 10, у мові з'явилися контекстно-залежні ключові слова, такі як var або record (у Java 14); ці слова не є зарезервованими, але мають визначений сенс у певному контексті.

Ідентифікатори використовуються для іменування змінних, функцій та інших програмних об'єктів. Першим символом повинна бути літера чи символ підкреслення ("_", underscore character). Далі можуть використовуватися також цифри. Використання символу підкреслення на початку імені не є бажаним.

Доцільно використовувати змістовні імена, які відображають природу об'єкта або функції. Не можна використовувати пропуски всередині ідентифікатора. Тому, якщо необхідно створити ідентифікатор з кількох слів, ці слова пишуть злито, починаючи друге, третє та інші слова з великої літери – так звана "верблюжа нотація" (camel notation). Наприклад, можна створити таке ім'я змінної:

thisIsMyVariable

Для змістовних імен доцільно використовувати англійську мнемоніку. Імена класів та інтерфейсів слід починати з великої літери, інші імена – тільки з маленької. Імена статичних констант складаються з великих літер та символу підкреслення, наприклад PI, CONST_VALUE тощо.

Коментарі – це текст всередині сирцевого коду, який не обробляє компілятор. Мова Java підтримує три види коментарів:

  • у стилі C++ (// до кінця рядка)
  • у стилі C (/* */)
  • коментарі Javadoc (/** */).

Спеціальний засіб javadoc.exe, що входить у JDK (Java Development Kit), використовує коментарі третього виду для автоматичної генерації документації. Для цього такі коментарі повинні бути відформатовані за стандартом Javadoc. Можна додавати коментарі для рівня класів і інтерфейсів, а також для рівня методів і полів. Коментарі Javadoc повинні бути розташовані перед відповідними фрагментами коду. Кожен коментар складається з опису і тегів. У коментарі javadoc можна включати теги форматування HTML. Не рекомендується включати теги, що забезпечують виведення жирним шрифтом, курсивом тощо. Є спеціальний набір тегів Javadoc, таких як @author, @param, @return тощо. Ці теги забезпечують стандартне представлення документації, що стосується класів і методів. Наприклад, такі коментарі перед методом

/**
* Повертає ім'я файлу з відповідним індексом.<br>
* Імена файлів зберігаються в масиві рядків.
* @param i індекс
* @return ім'я файлу.
* */
public String getFileName(int i) {
    return names[i];
}

забезпечують генерацію такого фрагмента HTML-файлу документації:

Method Detail

getFileName

public String getFileName(int i)
Повертає ім'я файлу з відповідним індексом.
Імена файлів зберігаються в масиві рядків.
Parameters:
i – індекс
Returns:
file ім'я файлу.

Примітка: для того, щоб отримати шаблон коментаря Javadoc в середовищі IntelliJ IDEA, слід ввести початок коментаря (/**) перед кодом, який необхідно описати; необхідний шаблон буде згенеровано автоматично.

2.3.3 Визначення локальних змінних. Примітивні типи

Локальні змінні визначаються (створюються) всередині методів. Опис локальних змінних у Java здійснюється аналогічно C++. Наприклад:

int i = 11;
double d = 0, x;
float f; 
int j, k;

Локальні змінні можуть бути визначені в будь-якому місці усередині тіла функції, а також у вкладеному блоці. У Java не можна у внутрішньому блоці визначати імена, вже описані в зовнішньому блоці:

{
    int i = 0;
    {
        int j = 1; // Змінна j визначається у внутрішньому блоці
        int i = 2; // Помилка! Змінна i визначена в зовнішньому блоці
    }
}

У Java не можна оголошувати змінні без їхнього створення.

Ключове слово final стосовно до імен змінних означає, що вони не можуть бути змінені.

final int h = 0;

Слово const зарезервоване, але не використовується.

Примітивні, чи базові типи поділяються на цілі типи, типи з крапкою, що плаває, символьні й булеві. Примітивні типи приведені в наведеній нижче таблиці.

Ключове слово Опис Розміри
Цілі типи
byte маленьке ціле (від -128 до 127) 8 біт
short коротке ціле (від -32768 до 32767) 16 біт
int ціле (від -2147483648 до 2147483647) 32 біта
long довге ціле (від -9223372036854775808 до 9223372036854775807) 64 біта
Типи з плаваючою крапкою
float дійсне число звичайної точності 32 біта
double дійсне число подвійної точності 64 біта
Інші типи
char символ у кодах Unicode 16 біт
boolean булеве значення (true або false)  

У багатьох інших мовах (наприклад, у С та у С++) формат і розміри примітивних типів даних залежать від платформи (DOS, Win 32 тощо). У Java розміри й формат стандартизовані й не залежать від платформи.

Константи цілого типу записуються як послідовності десяткових цифр. Усталений тип константи – int. Він може бути уточнений додаванням наприкінці константи літер L чи l (тип long). Цілі константи можуть записуватися у вісімковій системі числення, у цьому випадку першою цифрою повинна бути цифра 0, число може містити тільки цифри 0...7. Цілі константи можна записувати й у шістнадцятковій системі числення, у цьому випадку запис константи починається із символів 0x чи 0X. Для позначення цифр понад 9 використовуються латинські літери a, b, c, d, e та f (великі або маленькі). Наприклад:

int octal = 023; // 19
int hex = 0xEF;  // 239    

У Java 7 з'явилася можливість визначати також двійкові константи (з використанням префіксів 0B або 0b):

int m = 0b110011; // 51

Крім того, групи розрядів у константах можна розділяти знаком підкреслення, наприклад: int n = 1_048_576;

Константи типу char беруть в одинарні лапки (апострофи), значення константи задається або знаком з поточного набору символів, або цілою константою, якій передує зворотна коса риска (символ із заданим кодом). Є ряд спеціальних символів, що можуть використовуватись як значення константи типу char (такі подвійні символи називаються керувальними послідовностями):

'\n' – новий рядок,
'\t' – горизонтальна табуляція,
'\r' – переведення на початок рядку, 
'\'' – одиночні лапки (апостроф),
'\"' – подвійні лапки,
'\\' – зворотна коса риска (backslash).

Для зберігання даних символьного типу в пам'яті використовується таблиця Unicode.

Константи дійсних типів можуть записуватись у формі з крапкою або в експонентному форматі та усталено мають тип double. При необхідності тип константи можна уточнити, записавши наприкінці суфікс f чи F для типу float, суфікс d чи D для типу double. Наприклад:

1.5f    // 1.5   типу float
2.4E-2d // 0.024 типу double

Значення з рухомою крапкою не можна присвоювати цілим змінним. Перетворення до більш вузького типу (дійсного типу до цілого, числа з подвійною точністю до числа з одинарною точністю) пов'язано з ризиком утрати даних і повинне здійснюватися явно:

int   i  = 10;
float f  = i;        // Таке перетворення допускається
long  l  = f;        // Помилка!
long  l1 = (long) f; // Явне приведення типів

Числа без десяткової крапки інтерпретуються як цілі (типу int). Числа з плаваючою крапкою мають тип double. Для приведення їх до більш вузьких типів використовується явне приведення типів:

float f  = 10.5;         // Помилка!
float f1 = (float) 10.5; // Явне приведення типів
float f2 = 10.5f;        // Уточнення типу константи. Помилки немає

У Java немає беззнакових (unsigned) цілих типів.

Булевим змінним можна присвоювати тільки константи true та false. Змінні типу boolean не можна неявно чи явно приводити до інших типів і навпаки.

Константа-рядок складається із символів, які беруть у подвійні лапки. Наприклад:

"Це рядок"

Результат додавання рядка до змінної іншого типу забезпечує перетворення значення у представлення у вигляді рядка. Зокрема, такий підхід застосовують для виведення значень декількох змінних. Наприклад:

int k = 1;
double d = 2.5;
System.out.println(k + " " + d); // 1 2.5

Починаючи з версії мови 10, Java надає можливість створення неявно типізованих локальних змінних. Для опису таких змінних застосовують контекстно-залежне ключове слово var. Такі змінні обов'язково повинні бути проініціалізовані. Тип змінної компілятор визначає відповідно до типу виразу, що ініціалізує. Наприклад:

var i = 1;
var s = "Hello";
      

Попри те, що тип не вказано явно, компілятор створює змінну певного типу. Після того, як змінна створена, не можна змінювати її тип:

var k = 1;
k = "Hello"; // Помилка!

2.3.4 Вирази та операції

Всередині методів класів, з яких складається програма, можуть міститись твердження (оператори), які, своєю чергою, складаються з виразів. Вираз складається з однієї чи кількох операцій. Об'єкти операцій мають назву операндів. Операції бувають унарними (один операнд), бінарними (два операнди) і тернарними (три операнди).

У Java підтримуються практично всі стандартні арифметичні й логічні операції, а також операції порівняння мови С++. Ці операції мають такий же пріоритет і асоціативність, як і в C++. Пріоритет додавання і віднімання нижче, ніж множення і ділення, пріоритет присвоєння нижче, ніж арифметичних операцій тощо. Для зміни послідовності операцій слід використовувати дужки.

До арифметичних операцій належать +, – (бінарні й унарні), *, / а також операція отримання залишку від ділення % (тільки до цілих). Якщо / застосовується до цілих, результатом ділення буде теж ціле, а залишок відкидається. Якщо хоча б один операнд – типу з рухомою крапкою (дійсний), ми отримаємо дійсний результат.

System.out.println(1 / 2);   // 0
System.out.println(1.0 / 2); // 0.5

До операцій відношення належать перевірка на рівність == і на нерівність !=, а також перевірки > (більше) >= (більше або дорівнює) < (менше) <= (менше або дорівнює). До логічних операцій належать логічне І (&&), АБО (||) та НІ (!). Операції відношення та логічні повертають значення типу boolean. Операції І та АБО можна застосовувати побітові & і |. У такому випадку завжди здійснюється повне обчислення значень обох операндів, тоді як обчислення значення другого операнду операцій && і || може не здійснюватись, якщо результат вже встановлено.

До операцій присвоювання відносяться операції простого і складеного присвоювання. Результатом операції простого присвоювання є значення того виразу, що присвоюється лівому операнду. Складене присвоювання можна представити в загальному вигляді в такий спосіб:

a op= b 

У цьому випадку op – арифметична чи побітова операція: + - * / % | & ^ << >>. Кожна складена операція еквівалентна присвоюванню:

a = (a) op (b);

Наприклад,

x += 5;

що еквівалентно

x = x + 5;

Операція інкременту ++ забезпечує збільшення цілої змінної на одиницю. Вона має дві форми префіксну і постфіксну. Префіксна форма забезпечує збільшення змінної до того, як значення операції буде використано, а постфіксна – після. Операція декременту -- забезпечує зменшення змінної на одиницю і правила її використання аналогічні.

На відміну від C++, операція "кома" може бути застосована тільки в заголовках циклів, наприклад:

int i, j;
for (i = 0, j = 0; i < 10; i++, j += 2) {
    System.out.println(i + " " + j);
}

Використання побітових операцій & (побітове І), | (побітове АБО), ^ (виключаюче АБО), ~ (побітове не) та << (побітовий зсув ліворуч) аналогічне С++. У Java існує додаткова операція беззнакового зсуву (>>>), оскільки операція >> додає одиницю, а не нуль для від'ємних цілих чисел (зберігає знак).

Умовна операція (тернарна) має такий вигляд:

умова ? вираз1 : вираз2 

Спочатку обчислюється значення умови. Якщо воно істинне, то обчислюється вираз1 і його значення повертається умовною операцією. Якщо значення умови хибне, то обчислюється вираз2 і повертається його значення. У наступному прикладі обчислюється мінімальне з двох чисел:

min = a < b ? a : b;

Порядок застосування унарних операцій та операцій присвоєння "справа наліво", а всіх інших операцій – "зліва направо".

У Java не допускається безпосередня робота з указівниками, отже, немає операцій розіменування та узяття адреси (*, -> та &). Операція -> замість вибору елемента за вказівником застосовується для створення лямбда-виразів.

У Java немає операції sizeof() оскільки її головне призначення в С++ – з'ясовувати розміри тих чи інших даних під час перенесення сирцевого коду на іншу платформу. У Java розміри всіх типів стандартизовані.

2.3.5 Твердження (інструкції). Керування виконанням програми

Твердження (або інструкція, іноді оператор, англ. statement) – найменша автономна частина мови програмування. Програма являє собою послідовність тверджень. Більшість тверджень мови Java аналогічна твердженням C++.

Порожнє твердження складається з однієї крапки з комою.

Твердження-вираз є повний вираз, який закінчується крапкою з комою. Наприклад:

k = i + j + 1;  // присвоєння
Arrays.sort(a); // виклик функції
return;         // вихід з функції

На відміну від C++, вирази, які не мають сенсу, такі як

i + j + 1;

призводять до помилки компіляції.

Складене твердження – це послідовність тверджень, укладена у фігурні дужки. Складене твердження часто іменують блоком. Після фігурної дужки, яка закриває блок, крапка з комою не ставиться. Синтаксично блок може розглядатися як окреме твердження, однак воно також має значення у визначенні видимості та часу життя ідентифікаторів. Ідентифікатор, оголошений усередині блоку, має область видимості від точки визначення до фігурної дужки, що закривається. Блоки можуть необмежено вкладатися один в одного.

Твердження вибору – умовне твердження (if) та перемикач (switch).

Умовне твердження застосовується у двох видах:

if (вираз-умова)
    твердження1
else
    твердження2

або

if (умова)
    твердження1

Під час виконання цього твердження обчислюється вираз-умова і, якщо це істина, то виконується твердження1 а інакше – твердження2.

На відміну від C++, вираз-умова може бути лише типу boolean. Тому наведений нижче код

int k;
// ... отримання k
if (k) { // перевірка, чи k не дорівнює нулю

}

призведе до синтаксичної помилки. Слід писати

if (k != 0) {

}

Перемикач дозволяє вибрати одну з кількох можливих гілок обчислень і будується за схемою:

switch (цілий_вираз)
    блок

Блок має такий вигляд:

{
    case константа_1: твердження
    case константа-2: твердження
    ...
    default: твердження
}

Виконання перемикача полягає в обчисленні керувального виразу і переході до групи тверджень, позначених case-міткою, значення якої дорівнює керувальному виразу. Якщо такої мітки немає, виконуються твердження після мітки default (яка може бути відсутня). Під час виконання перемикача відбувається перехід на твердження з обраною міткою і далі твердження виконуються у нормальному порядку. Для того, щоб не виконувати тверджень, які залишилися у тілі перемикача, необхідно використовувати оператор break.

Окрім цілих та символів, у конструкції switch () можна використовувати рядки. В цьому випадку константи варіантів (після case) повинні теж бути рядками, наприклад:

case "some text":

Починаючи з Java 12, окрім твердження switch можна застосовувати операцію switch. Загальний синтаксис операції switch такий:

Тип1 змінна = switch (вираз) {
    case ЗНАЧЕННЯ1 -> вираз1Типу1;
    case ЗНАЧЕННЯ2 -> вираз2Типу1;
    ...
    default -> виразNТипу1; // ця гілка може бути відсутньою
};

Операцію switch можна також використовувати як частину складнішого виразу.

Використання операції switch дозволяє скоротити сирцевий код та зробити його більш наочним. Припустимо, залежно від вмісту рядка ("one" або "two") слід записати у змінну n відповідне ціле значення, або 0, якщо вміст рядка якийсь інший. Традиційний код (твердження switch) буде таким:

String number;
// ...
int n;
switch (number) {
    case "one":
        n = 1;
        break;
    case "two":
        n = 2;
        break;
    default:
        n = 0;
}

За допомогою операції switch необхідне значення можна отримати так:

String number;
// ...
int n = switch (number) {
    case "one" -> 1;
    case "two" -> 2;
    default -> 0;
};

Починаючи з Java 13, замість операції -> можна використовувати ключове слово yield.

Твердження циклу реалізовані в трьох варіантах: цикл із передумовою, цикл із постумовою і цикл із параметром (існує четверта форма, яка стосується масивів та колекцій). Синтаксис тверджень циклу аналогічний C++, але слід пам'ятати, що в усіх циклах перевірка умови продовження вимагає результату типу boolean.

Цикл із передумовою будується за схемою

while (вираз-умова) 
    твердження

На кожному повторенні циклу обчислюється вираз-умова типу boolean і якщо значення цього виразу дорівнює true, виконується твердження – тіло циклу.

Цикл із постумовою будується за схемою

do
    твердження
while (вираз-умова); 

Вираз-умова типу boolean обчислюється і перевіряється після кожного повторення твердження – тіла циклу, цикл повторюється, поки умова виконується. Тіло циклу в циклі з постумовою виконується принаймні один раз.

Цикл із параметром будується за схемою:

for (E1; E2; E3)
    твердження

де E1, E2 і E3 – вирази необхідних типів. Цикл з параметром реалізується за таким алгоритмом:

  • обчислюється вираз E1 (зазвичай цей вираз виконує підготовку до початку циклу);
  • обчислюється Булев вираз E2 і якщо він дорівнює false, виконується перехід до наступного твердження програми (вихід з циклу);
  • якщо E2 дорівнює true, виконується твердження – тіло циклу;
  • обчислюється вираз E3 – виконується підготовка до повторення циклу, після чого знову виконується вираз E2.

У наступному прикладі сума

y = 12 + 22 + 32 + ... + n2

знаходиться за допомогою трьох різних циклічних тверджень.

За допомогою циклу while:

int y = 0;
int i = 1;
while (i <= n) {
    y += i * i;
    i++;
}

За допомогою циклу do ... while:

int y = 0;
int i = 1;
do {
    y += i * i;
    i++;
}
while (i <= n);

За допомогою циклу for:

int y = 0;
for (int i = 1; i <= n; i++) {
    y += i * i;
}

Циклічні твердження можна вкладати одне в інше.

У сполученні з твердженнями циклу використовуються твердження переходу – оператор break, який дозволяє перервати виконання найбільш внутрішнього з циклів, оператор continue, який перериває поточну ітерацію найбільш внутрішнього з циклів while, do або for. Найчастіше break використовують у такій конструкції:

if (умова_дострокового_завершення_циклу)
    break;

У Java після ключових слів break та continue можна розташувати мітку, що передує одному з вкладених циклів. У цьому випадку твердження стосуються не найбільш внутрішнього, а позначеного циклу. Наприклад:

  int a;
  . . .
  double b = 0;
label:
  for (int i = 0; i < 10; i++) {
      for (int j = 0; j < 10; j++) {
          if (i + j + a == 0) {
              break label;
          }
          b += 1.0 / (i + j + a);
      }
  }

Твердження goto не використовується в мові Java, але goto є зарезервованим словом. Це слово ніяк не може бути використано.

У Java немає оператора typedef. Мова Java також не підтримує типів struct та union.

2.4 Пакети та функції

У Java немає заголовних файлів. Для того, щоб запобігти можливим конфліктам імен, уся глобальна область видимості розділяється на пакети.

Пакет – це набір взаємозалежних класів та інших елементів коду, які здійснюють взаємодію один з одним через загальний доступ до функцій і даних і через загальний простір імен. Усі сирцеві файли одного пакету повинні міститися в одній теці. Пакети можуть вкладатися один в інший. Кожен клас Java знаходиться в будь-якому пакеті. Імена пакетів повинні збігатися з іменами тек, у яких знаходяться файли сирцевого тексту (чи скомпільовані файли).

У першому рядку сирцевого файлу (не враховуючи порожніх рядків і коментарів) найчастіше знаходиться заголовок пакета, до якого відносяться класи, визначені у файлі.

package ім'я_пакету;

Якщо ім'я пакета пропущене, вважається, що код належить до безіменного пакета (усталеного пакета), межі якого визначаються поточною текою. До класів та інших синтаксичних конструкцій такого пакета не можна звернутися ззовні. Такий варіант не є бажаним.

Бажано використовувати більш змістовні імена пакетів. Можна створювати вкладені пакети, відповідно створюючи вкладені теки. Крім того, бажано забезпечити унікальність імен пакетів. Для забезпечення унікальності можна використовувати обернене доменне ім'я. Наприклад, якщо доменне ім'я автора author.com, то слід використовувати пакет com, далі підпакет author і далі підпакети, відповідно до різних задач. Далі в прикладах використовуватиметься пакет ua.inf.iwanoff, що є оберненим доменним ім'ям автора. У цьому пакеті створюватимуться підпакети.

У Java немає глобальних функцій. Аналогом глобальної функції є статичний метод класу. Опис статичної функції у найпростішому випадку має таку структуру:

static тип_результату ім'я_функції(список_формальних_параметрів) тіло

На відміну від C++, у Java не треба і не можна створювати прототипи функцій (оголошення функцій без визначення).

Параметри функції, що вказуються в списку у визначенні функції, називаються формальними. Параметри, що вказуються під час виклику функції, називаються фактичними параметрами, або аргументами. Під час виклику функції виділяється пам'ять під її формальні параметри, потім кожному формальному параметру присвоюється значення фактичного параметра.

Тіло функції являє собою складений оператор (блок). Наприклад, визначення статичної функції, що обчислює суму двох цілих чисел, може бути таким:

static int sum(int a, int b) {
    int c = a + b;
    return c;
} 

Можна взагалі обійтися без змінної с:

static int sum(int a, int b) {
    return a + b;
} 

Виклик функції може бути здійснений у виразі в описі або в тілі іншої функції. Під час виклику функції вказується її ім'я і список фактичних параметрів без зазначення їхніх типів:

int x = 4;
int y = 5;
int z = sum(a, b);
int t = sum(1, 3); 

Функція може бути без параметрів:

int zero() {
    return 0;
}

Викликаючи таку функцію, також необхідно використовувати дужки:

System.out.println(zero());

Інструкція return у тілі функції забезпечує завершення роботи функції. Значення виразу після return стає значенням функції, яке ця функція повертає.

Функція може не повертати ніякого результату. Для позначення цього використовується тип void.

void hello() {
    System.out.println("Hello!");
}

У цьому випадку в тілі функції return може бути відсутнім. Якщо твердження return присутня, то після нього не повинно бути ні якого виразу. Таку функцію можна викликати тільки окремим твердженням.

hello();

Параметри передаються до функцій за значенням, тобто значення фактичних параметрів копіюються в пам'ять, відведену для формальних параметрів. При цьому значення, з якими працює функція – це її власні локальні копії фактичних параметрів і їхня зміна на ці параметри не впливає. Таким чином, під час передачі за значенням вміст фактичних параметрів не змінюється:

static void f(int k) {
    k++;       // k = 2;
}

public static void main(String[] args) {
    int k = 1;
    f(k);
    System.out.println(k); // k = 1;
}

На відміну від багатьох інших мов програмування Java не надає механізму передачі параметрів типів-значень за посиланням.

У Java можна перевантажувати імена функцій. Перевантаженням імені називається його використання для позначення різних операцій над різними типами.

Якщо списки формальних параметрів збігаються, але типи значень, що повертаються, різні, компілятор повідомляє про помилку. Якщо списки формальних параметрів двох функцій розрізняються числом чи параметрів їхніми типами, то ці дві функції вважаються перевантаженням однієї функції й повинні мати різні визначення.

Перевантажені функції використовуються в тих випадках, якщо кілька функцій виконує схожі дії над об'єктами різних типів і зручно дати однакові імена всім цим функціям:

static int max(int a, int b) { }                 // Вибір максимального з двох цілих чисел
static int max(double x, double y, double z) { } // Вибір максимального з трьох дійсних чисел

Для того, щоб визначити, яку саме функцію варто викликати, порівнюються кількість і типи фактичних параметрів, зазначені у виклику, з кількістю і типами формальних параметрів всіх описів функцій з таким ім'ям. У результаті викликається та функція, у якої формальні параметри щонайкраще зіставилися з параметрами виклику, чи видається помилка, якщо такої функції не знайшлося.

Усталені параметри функції, які можуть бути описані у С++, у Java не підтримуються.

Статичні функції в межах класу викликаються з застосуванням лише імені функції та списку фактичних параметрів. Для того, щоб викликати статичну функцію іншого класу, необхідно вказувати його ім'я і далі через точку ім'я функції. В такий спосіб можна звертатись до імен у межах пакета, а також до класів і функцій пакету java.lang. Цей пакет містить класи з дуже корисними функціями. Наприклад, клас Math надає велику кількість математичних функцій. У таблиці наведені найбільш вживані математичні функції класу Math:

Функція Зміст Приклад виклику
double pow(double a, double b) Обчислення ab Math.pow(x, y)
double sqrt(double a) Обчислення квадратного кореня Math.sqrt(x)
double sin(double a) Обчислення синуса Math.sin(x)
double cos(double a) Обчислення косинуса Math.cos(x)
double tan(double a) Обчислення тангенса Math.tan(x)
double asin(double a) Обчислення арксинуса Math.asin(x)
double acos(double a) Обчислення арккосинуса Math.acos(x)
double atan(double a) Обчислення арктангенса Math.atan(x)
double exp(double a) Обчислення ex Math.exp(x)
double log(double a) Обчислення натурального логарифма Math.log(x)
double abs(double a)
int abs(int a)
Знаходження модуля числа Math.abs(x)
long round(double a) Округлення до найближчого цілого Math.round(x)

Крім математичних функцій, клас Math надає такі корисні константи, як Math.PI, Math.E.

Якщо класи знаходяться в інших пакетах (не у java.lang), для виклику цих функцій слід або застосовувати префікс – ім'я_пакету.ім'я_класу. Якщо необхідні класи вкладених пакетів, префікс буде ще складнішим. Для того, щоб запобігти використанню повних імен, застосовується конструкція import. Конструкції import розташовують на початку файлу з сирцевим кодом, або безпосередньо після конструкції package.

Для забезпечення доступу до класу чи інтерфейсу з іншого пакету є три варіанти:

  1. Імпорт класу чи інтерфейсу (import ім'я_пакету.імпортоване_ім'я).
  2. Імпорт усього пакету (import ім'я_пакету.*).
  3. Статичний імпорт – імпорт статичних елементів зазначеного класу (import static ім'я_пакету.*).

Наведений нижче приклад демонструє перші два варіанти:

import java.io.FileReader;  // Імпорт класу (інтерфейсу)
import java.util.*;         // Імпорт усього пакету

public class TestClass {
    public static void main(String[] args) {
        java.io.FileWriter fw;  // Повне ім'я
        FileReader fr;          // Прямий  доступ до імпортованого імені
        ArrayList al;           // ArrayList входить у пакет java.util
        . . .
    }
}

Не слід включати в програму твердження import java.lang.*. Цей пакет імпортується автоматично.

Додаткова форма імпорту, яка з'явилася у версії Java 5, дозволяє імпортувати тільки статичні елементи зазначеного класу. Наприклад, у програмах, які реалізують математичні обчислення доцільно додавати статичний імпорт елементів класу Math:

import static java.lang.Math.*;    

Тепер статичні елементи можна використовувати без додаткового кваліфікатора, наприклад:

double d = sin(1);    

2.5 Консольне введення та виведення

Для забезпечення консольного введення Java надає декілька варіантів:

  • безпосереднє використання потоку введення System.in, зокрема його функції read();
  • використання класу java.io.Console;
  • використання класу java.util.Scanner.

Перший варіант – низькорівневий і вимагає великої кількості "ручної роботи", тому зараз майже не застосовується. Другий варіант (клас java.io.Console, починаючи з JDK 1.6) теж має певні недоліки, зокрема, інтегровані середовища Eclipse й IntelliJ IDEA не підтримують роботу з об'єктами цих класів у своїх консольних вікнах.

Найбільш зручним засобом уведення даних є клас java.util.Scanner. Клас Scanner надає функції для читання даних з різних джерел, наприклад, з файлів. У нашому випадку ми вказуємо на необхідність читання з клавіатури (стандартний потік введення System.in). Об'єкт-сканер можна застосувати для читання даних різних типів. Наприклад, функція next() повертає наступне прочитане значення типу String (рядок), nextInt() дозволяє отримати ціле, nextDouble() повертає прочитане число типу double. Є також функції nextBoolean(), nextByte(), nextShort(), nextLong(), nextFloat() тощо. Усі функції обумовлюють зупинку виконання програми, яке поновлюється після введення з клавіатури відповідного значення.

Для можливості роботи з класом Scanner на початку сирцевого коду слід додати:

import java.util.Scanner;

Це дозволить використовувати ім'я Scanner без додаткового префіксу.

Спочатку треба створити об'єкт цього класу за допомогою операції new (докладно ця операція буде розглянута пізніше). Зв'язуємо об'єкт-сканер зі стандартним System.in. Далі можна читати дані різних типів. Наприклад:

package ua.inf.iwanoff.java.first;

import java.util.Scanner;

public class ScannerTest {

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String s = scanner.next();       // читання рядка
        double d = scanner.nextDouble(); // читання дійсного числа
        int i = scanner.nextInt();       // читання цілого числа
        // ... використання введених даних
    }

}

Великою зручністю класу є можливість довільного розташування даних у вхідному потоці: окремі дані можна розділяти пропусками, табуляцією, або переведенням рядка. Єдиний виняток – використання функції nextLine(), яка читає дані до кінця рядка.

Виведення у консольне вікно здійснюється за допомогою функцій об'єкта out класу System. Функція print() дозволяє вивести результат без переходу на новий рядок, println() здійснює перехід на новий рядок після виведення.

Можна також скористатися функцією printf() для форматованого виведення. Використання цього методу аналогічне використанню відповідної функції мови С. Перший параметр – так званий рядок форматування. Далі можна вказати довільну кількість параметрів, значення яких слід вивести на консоль. Наприклад:

    double d = 3.5;
    int i = 12;
    System.out.printf("%f %d%n", d, i);

Використовують такі специфікатори формату:

Специфікатор формату Форматування яке здійснюється
%a Шістнадцяткове значення з плаваючою точкою
%b Логічне (булеве) значення аргументу
%c Символьне представлення аргументу
%d Десяткове ціле значення аргументу
%e Експоненціальне подання аргументу
%f Десяткове значення з плаваючою точкою
%g Вибирає коротше представлення з двох: або %f
%o Вісімкове ціле значення аргументу
%n Вставка символу нового рядка
%x Шістнадцяткове ціле значення аргументу
%% Вставка символу %

Після символу % можна вказувати ширину поля.

Є також можливість виведення повідомлень у потік System.err (стандартний потік повідомлень про помилки). Виведення в цей потік має більш високий пріоритет, ніж виведення в System.out, тому іноді повідомлення про помилки випереджають "нормальне" виведення.

2.6 Запуск Java-застосунків з командного рядка

Скомпільовані програми можуть бути запущені в командному рядку. Для запуску командного рядка в Windows використовується команда cmd. У командному рядку запускається віртуальна машина Java (команда java), далі через пропуск указується параметр -classpath (чи -cp), після якого через пробіл вказується повний шлях до каталогу проєкту. Далі вказується ім'я пакета і через крапку ім'я класу, що містить функцію main().

Припустимо, проект First створений у робочому просторі, зв'язаним з текою E:\workspace, а функція main() реалізована в класі TestClass пакету first. Для запуску програми в командному рядку варто набрати

java -cp E:\workspace\First first.TestClass

Під час виведення на консоль у Windows символів кирилиці можуть виникнути проблеми. Їх можна вирішити, вказавши віртуальній машині кодову сторінку DOS за допомогою параметра -Dfile.encoding=IBM-866:

java -Dfile.encoding=IBM-866 -cp E:\workspace\First\bin first.TestClass

3 Приклади програм

3.1 Середнє арифметичне

Необхідно ввести з клавіатури два числа (дійсне та ціле) і обчислити їх середнє арифметичне.

Створюємо новий проект. У новому проєкті створюємо пакет ua.inf.iwanoff.java.first, до якого додаємо клас Average. Додаємо до класу функцію main(). Одержуємо такий код:

package ua.inf.iwanoff.java.first;

public class Average {

    public static void main(String[] args) {
        
    }

}

Тепер всередині функції maіn() створюємо об'єкт класу Scanner, описуємо дві змінні, наприклад, a і b, читаємо їхні значення з клавіатури й обчислюємо значення c, що є їхнім середнім арифметичним.

Scanner s = new Scanner(System.in);
double a = s.nextDouble();
int b = s.nextInt();
double c = (a + b) / 2;

Для забезпечення можливості використання класу Scanner слід перед описом класу Average додати твердження імпорту (import java.util.Scanner;). Визначення (опис) змінної, як і в C++, можна поєднувати з присвоєнням початкового значення (ініціалізацією). У цьому випадку створюється змінна s типу Scanner, b типу int, а також змінні a і c типу double.

Після ініціалізації змінної c необхідний результат вже обчислений. Його необхідно вивести на екран (у консольне вікно) з використанням функції println() об'єкта out класу System.

System.out.println("Середнє арифметичне: " + c);

У цьому рядку плюс означає не додавання, а зшивання рядків. До строкової константи "Середнє арифметичне: " пришивається рядкове представлення значення змінної c.

Тепер можна навести повний текст програми.

package ua.inf.iwanoff.java.first;

import java.util.Scanner;

public class Average {

    public static void main(String[] args) {
        Scanner s = new Scanner(System.in);
        double a = s.nextDouble();
        int b = s.nextInt();
        double c = (a + b) / 2;
        System.out.println("Середнє арифметичне: " + c);
    }

}

Після запуску програми слід перейти у підвікно Console, увести в різних рядках значення a та b, після чого в консольному вікні з'явиться результат.

3.2 Степені числа 2

Необхідно ввести n (1 до 30 включно) та вивести на екран степені числа 2 – від першого до введеного n-го. Можна реалізувати два варіанти – з використанням арифметичних дій і побітових операцій.

3.2.1 Використання арифметичних операцій

До попереднього пакета додаємо клас Powers. Для виконання однотипних дій доцільно створити цикл, у тілі якого обчислюється черговий степінь 2 та виводиться на екран. Реалізація алгоритму мовою Java матиме такий вигляд:

Scanner s = new Scanner(System.in);
int n = s.nextInt();
int k = 2;  // основа степеня
int power = 1;
for (int i = 1; i <= n; i++) {
    power *= k;
    System.out.printf("2 ^ %2d = %d\n", i, power);
}    

У цьому прикладі для опису змінних використовується тип int (цілий), тому що й основа степеня, і показник, і степінь – цілі числа. Початкове значення результату

int power = 1;

є типовим для обчислення добутків послідовностей Як видно з прикладу, параметр циклу можна визначати безпосередньо в заголовку циклу. Для множення, як і в інших мовах програмування, використовується знак зірочки. Замість традиційного для багатьох мов твердження

power = power * k;    

можна записати

power *= k;    

Програма матиме такий вигляд:

package ua.in.iwanoff.labs.fourth;

import java.util.Scanner;

public class Powers {

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.println("Уведіть n у діапазоні від 1 до 30");
        int n = scanner.nextInt();
        int power = 1;
        final int k = 2;
        if (n < 0 || n > 30) {
            System.err.println("Неправильне значення n");
        }
        else {
            for (int i = 0; i <= n; i++) {
                System.out.printf("2 ^ %2d = %d\n", i, power);
                power *= k;
            }
        }
    }

}

3.2.2 Використання побітових операцій

Більш ефективним буде підхід, який використовує побітову операцію зсуву.

package ua.in.iwanoff.labs.fourth;

import java.util.Scanner;

public class PowersOfTwo {

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.println("Уведіть n у діапазоні від 1 до 30");
        int n = scanner.nextInt();
        if (n < 0 || n > 30) {
            System.err.println("Неправильне значення n");
        }
        else {
            for (int i = 0; i <= n; i++) {
                System.out.printf("2 ^ %2d = %d\n", i, 1 << i);
            }
        }
    }

}

3.3 Найбільший спільний дільник

Припустимо, необхідно обчислити найбільший спільний дільник. Скористаємось алгоритмом Евкліда, який полягає у послідовному відніманні меншого числа з більшого та заміні більшого числа отриманою різницею. Алгоритм завершується, коли два числа збігатимуться. Програма матиме такий вигляд:

package ua.inf.iwanoff.java.first;

import java.util.Scanner;

public class GreatestCommonDivisor {

    static int gcd(int m, int n) {
        while (m != n) {
            if (m > n)
                m -= n;
            else
                n -= m;
        }
        return m;
    }

    public static void main(String[] args) {
        Scanner s = new Scanner(System.in);
        int m = s.nextInt();
        int n = s.nextInt();
        System.out.println(gcd(m, n));
    }

} 

Результат роботи можна використати для обчислення найменшого спільного кратного чисел. Для цього їхній добуток слід поділити на найбільший спільний дільник.

3.4 Рекурсія

Припустимо, необхідно створити рекурсивну функцію обчислення цілого степеня дійсного числа та здійснити тестування для різних значень. Функцію розташуємо в окремому класі:

package ua.inf.iwanoff.java.first;

public class IntPower {
    public static double power(double x, int n) {
        if (n < 0) {
            return 1 / power(x, -n);
        }
        if (n == 0) {
            return 1;
        }
        return x * power(x, n - 1);
    }
}

В іншому класі можна скористатися статичним імпортом. Клас Program матиме такий вигляд:

package ua.inf.iwanoff.java.first;

import java.util.Scanner;
import static ua.inf.iwanoff.java.first.IntPower.*; 

public class Program {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.print("Уведiть x: ");
        double x = scanner.nextDouble();
        System.out.print("Уведiть n: ");
        int n = scanner.nextInt();
        double p = power(x, n);
        System.out.println("Степiнь: " + p);
    }
}

3.5 Обчислення виразу

Необхідно прочитати з клавіатури x та обчислити y за такою формулою:

де n дорівнює 6. Обчислення виразу слід розмістити в окремій функції. Програма може мати такий вигляд:

package ua.inf.iwanoff.java.first;

import java.util.Scanner;

public class Formula {

    public static double f(double x) {
        final int n = 6;
        double y;
        if (x < 0) {
            y = 0;
            for (int i = 1; i <= n; i++) {
                y += (i - x) * (i - x);
            }
        }
        else {
            y = 1;
            for (int i = 1; i <= n; i++) {
                y *= (x + i);
            }
        }
        return y;
    }

    public static void main(String[] args) {
        Scanner s = new Scanner(System.in);
        double x = s.nextDouble();
        double y = f(x); // Виклик функції
        System.out.println("x = " + x + "\ty = " + y);
    }

}

3.6 Таблиця значень квадратних коренів чисел

Необхідно прочитати з клавіатури значення початку інтервалу, кінця інтервалу, величини кроку, з яким змінюється аргумент та у циклі вивести значення квадратних коренів чисел. Програма може мати такий вигляд:

package ua.inf.iwanoff.java.first;

import java.util.Scanner;

public class SquareRoots {

    public static void main(String[] args) {
        Scanner s = new Scanner(System.in);     
        double from = s.nextDouble();
        double to = s.nextDouble();
        double step = s.nextDouble();
        if (from < 0 || to < 0 || from >= to || step <= 0) {
            System.out.println("Неправильні дані");
        }
        else {
            // Основний цикл програми:
            for (double x = from; x <= to; x += step) {
                System.out.println("x = " + x + "\t y = " + Math.sqrt(x));
            }
        }
    }

}

Як результат виконання цієї програми на консолі з'являться пари значень x та y.

4 Вправи для контролю

Усі вправи передбачають створення консольного застосунку. Обчислення основного результату здійснити в окремій статичній функції, яка викликається з функції main(). Введення та виведення здійснювати у функції main().

  1. Увести два дійсних числа. Знайти та вивести середнє арифметичне других степенів чисел.
  2. Увести два дійсних числа. Знайти та вивести середнє геометричне – квадратний корінь з їхнього добутку. Якщо корінь не можна обчислити, вивести повідомлення про помилку.
  3. Увести ціле додатне число. Перевірити, чи є воно простим. Вивести відповідно "yes" або "no". Число називається простим, якщо у нього рівно два дільники – 1 і визначене число.
  4. Увести ціле додатне число. Перевірити, чи є воно точним квадратом іншого цілого числа. Вивести знайдене число, або "no" в іншому випадку.
  5. Увести два цілих додатних числа. Знайти та вивести найменше спільне кратне цих чисел.
  6. Створити рекурсивну функцію обчислення суми квадратів перших n чисел.
  7. Створити рекурсивну функцію обчислення добутку синусів перших n натуральних чисел.

5 Контрольні запитання

  1. Що таке Java-платформа?
  2. Чим відрізняється JDK і JRE?
  3. Що таке віртуальна машина Java?
  4. Що таке байт-код?
  5. Які файли містять сирцевий код на Java і які містять результат компіляції?
  6. Коли і як здійснюється компонування Java-програми?
  7. У чому полягають переваги та недоліки синтаксису мови Java (у порівнянні з С++)?
  8. Яка різниця між ключовими й зарезервованими словами?
  9. Чим відрізняються коментарі Javadoc від інших видів коментарів?
  10. Як створюється вбудована документація?
  11. Чим відрізняються примітивні типи даних Java від аналогічних типів C++?
  12. Для чого використовують послідовності що керують?
  13. Як здійснюється приведення типів?
  14. У чому полягають особливості типу boolean?
  15. Як привести значення вираз типу boolean до цілого типу?
  16. Чи можна застосовувати операцію & замість && для операндів типу boolean?
  17. Чи завжди потрібна мітка при використанні break?
  18. Чи можна розмістити декілька пакетів у одному сирцевому файлі?
  19. Чи можна звертатися до імен з іншого пакета, не використовуючи операції import?
  20. У чому є переваги та недоліки статичного імпорту?