Вікіпідручник
ukwikibooks
https://uk.wikibooks.org/wiki/%D0%93%D0%BE%D0%BB%D0%BE%D0%B2%D0%BD%D0%B0_%D1%81%D1%82%D0%BE%D1%80%D1%96%D0%BD%D0%BA%D0%B0
MediaWiki 1.39.0-wmf.23
first-letter
Медіа
Спеціальна
Обговорення
Користувач
Обговорення користувача
Вікіпідручник
Обговорення Вікіпідручника
Файл
Обговорення файлу
MediaWiki
Обговорення MediaWiki
Шаблон
Обговорення шаблону
Довідка
Обговорення довідки
Категорія
Обговорення категорії
Полиця
Обговорення полиці
Рецепт
Обговорення рецепта
TimedText
TimedText talk
Модуль
Обговорення модуля
Gadget
Gadget talk
Gadget definition
Gadget definition talk
Реалізація алгоритму рекурсивного спуску з прикладами на C++
0
2621
36871
32522
2022-08-03T18:58:09Z
Володимир Груша
985
wikitext
text/x-wiki
Вашій увазі пропонується невеличке керівництво та описання реалізації [[w:Алгоритм|алгоритму]] [[w:Рекурсивний спуск|рекурсивного спуску]] на [[w:Мова програмування|мові програмування]] [[w:C++|C++]].
== Вступ ==
Незважаючи на те, що стандарт мови [[C++]] досить обширний, деякі теми, такі як синтаксичний аналіз виразів в ньому не розглядаються. Програми синтаксичного аналізу використовуються для обчислення значень алгебраїчних виразів, наприклад (100-23)*213. Сьогодні синтаксичні аналізатори оточені певною загадковістю. З різних причин, процедури що використовуються в процесі синтаксичного аналізу відомі небагатьом. Навіть дуже розумні програмісти іноді пасують перед необхідністю синтаксичного аналізу.
Насправді синтаксичний аналіз виразів - досить проста процедура. Ця простота є наслідком строгих правил алгебри. В цій роботі ми оглянемо програму аналізу методом рекурсивного спуску (recursive-descent parser) та всі її процедури. Однак перш ніж приступити до розробки, варто трохи розповісти про вирази і правила їх граматичного поділу.
==Вирази==
Оскільки програма синтаксичного поділу обчислює арифметичні вирази, необхідно ясно уявити перед собою, з яких частин складається вираз. Розглянемо вирази з наступних компонентів:
* Числа
* Операції
* Дужки
* Змінні
В нашому синтаксичному аналізаторі символ “^” буде означати піднесення до степеня. Символ ”=” означає оператор присвоювання. Вище згадані компоненти об’єднуються у вираз, відповідно правилам алгебри. Наприклад:
123-23
(123-435)*334/34
х^3-1
x=1
Встановимо наступні пріоритети операторів.
{|class="wikitable"
|-
|Високий || + - (унарні)
|-
| || ^
|-
| || * / %
|-
| || + -
|-
|Низький || =
|}
Оператори, котрі мають однаковий пріоритет, обчислюються зліва направо.
В прикладах, показаних по процесу пояснення, всі змінні поначаються однією буквою. Регістр літер не береться до уваги. В першій версії аналізатора всі числові змінні приводяться до дійсного типу.
== Синтаксичний аналіз виразів: постановка задачі ==
Існує багато способів синтаксичного аналізу і обчислення виразів. В рамках алгоритму рекурсивного спуску вирази розглядаються як рекурсивні структури данних. Якщо б вираз міг складатися із операцій +, -, *, / і дужок, то всі вирази можна було б визначити такими правилами:
<вираз> ::= <доданок> [+ <доданок>] [- <доданок>]
<доданок> ::= <атом> [* <атом>] [/ <атом>]
<атом> ::= <змінна> | <число> | (<вираз>)
Квадратні дужки містять необов'язковий елемент, а символ ::= інтерпритується як "породжує". Правила, вказані вище, часто називають породжуючими правилами, або продукціями. Тому, визначення доданка можна було б озвучити так: "Доданок породжує атом чи атом помножений чи поділений на атом". Зверніть увагу на те, що породжуючі правила неявно враховують пріоритет операцій.
Вираз:
10+5*Х
складається з двох доданків: 10 і 5*X. Другий доданок складається з двох атомів: 5 і Х. Ці атоми складаються з одного числа і однієї змінної.
З іншого боку, вираз
14*(7-Х)
складається з двох атомів: 14 і (7-Х). Атоми складаються з одного числа і одного виразу, поміщеного в дужки. Вираз в дужках складається з двох доданків.
Цей процес виявляє базис рекурсивного спуску, що представляє собою набір взаємнорекурсивних функцій, що реалізують створені правила. На кожному кроці аналізатор виконує операції, послідовність яких визначена правилами алгебри. Щоб продемонструвати, як породжені правила застосовуються для синтаксичного аналізу виразів, подивимося наступний приклад.
9/3-(100+56)
Для синтаксичного аналізу треба виконати такі дії:
# Знайти перший терм 9/3.
# Знайти кожний атом і поділити цілі числа. Результат буде рівний 3.
# Знайти другий атом, (100+56). Запустити рекурсивний аналіз другого підвиразу.
# Знайти всі атоми і додати їх. Результат 156.
# Повернутися з рекурсивного виклику і відняти 156 від 3 отримавши -153.
Потрібно знати дві речі:
# Породжені правила неявно враховують приорітет операторів.
# Цей метод аналізу і обчислення виразу дуже схожий на спосіб, з допомогою якого люди самі обчислюють математичні вирази.
Далі ми розглянемо три програми синтаксичного аналізу виразів. Перша програма аналізує і рахує вираз з дійсним типом, що складається лише з констант. Потім ми розглянемо синтаксичний аналізатор, що дозволяє приймати змінні. А третя версія аналізатора буде реалізована у вигляді шаблонного класу, який можна застосувати для синтаксичного аналізу виразів довільного типу.
== Клас parser ==
В основі програми синтаксичного аналізу виразів лежить клас parser. Перша версія цього класу приведена нижче. Наступні версії будуть створюватись на основі модифікацій першої.
<syntaxhighlight lang="c">
class parser
{
char *exp_ptr;
char token[80];
char tok_type;
double vars[NUMBER];
void eval_exp2(double &result);
void eval_exp3(double &result);
void eval_exp4(double &result);
void eval_exp5(double &result);
void eval_exp6(double &result);
void atom(double &result);
void get_token();
void putback();
void serror(int error);
double find_var(char *s);
int isdelim(char c);
public:
parser();
double eval_exp(char *exp);
}
</syntaxhighlight>
Клас <code>parser</code> містить три закриті поля. Вираз є звичайним рядком, на початок якого вказує вказівник <code>exp_ptr</code>. В процесі роботи аналізатор зчитує рядок, переміщуючи вказівник, аж поки не знайдеться його кінець. Так аналізатор обчислює значення виразу що зберігається в простих ASCII-рядках. Інші два поля, <code>token</code> і <code>tok_type</code>, використовуються в лексичному аналізі, про що буде говоритись пізніше.
Початковою точкою аналізу є функція <code>eval_exp()</code>, якій треба передати вказівник на вхідний вираз. Функції <code>eval_exp2() - eval_exp6()</code> разом з функцією <code>atom()</code> реалізують породжені правила вказані вище. В наступних версіях аналізатора до них буде додано функцію <code>eval_exp1()</code>.
Функція <code>serror()</code> призначена для обробки синтаксичних помилок, створених у виразі. Функції <code>get_token()</code> і <code>isdelim()</code> використовуються для розбиття виразу на складові частини.
== Лексичний аналіз ==
Для того, щоб обчислити вираз, нам потрібно буде розбити його на компоненти. Ця операція називається лексичним аналізом.
Кожен компонент виразу називається лексемою (токеном). Наприклад, вираз
A * B - (W + 10)
містить лексеми А, *, B, -, (, W +, 10, і ). Кожна лексема представляє собою нерозділювану частину виразу.
Для синтаксичного аналізу необхідна функція (лексичний аналізатор), яка послідовно повертала б окремі лексеми, з яких складається вираз. Крім того, функція повинна ігнорувати пропуски, а також виявляти кінець виразу. Функція, що дозволяє виділяти лексеми, називається - get_token. Вона є членом класу parser.
Нам також потрібно буде знати тип лексем. В нашій програмі використані тільки три типи лексем: <code>VARIABLE</code> (змінна), <code>NUMBER</code> (число) і <code>DELIMITER</code> (розділювач). До типу <code>DELIMITER</code> відносяться також оператори і дужки.
Функція <code>get_token()</code> розглянута нижче. Вона отримує наступну лексему з виразу, на який вказує вказівник <code>exp_ptr</code> і поміщає її в змінну <code>token</code>. Тип отриманої лексеми записується в змінну <code>tok_type</code>.
<syntaxhighlight lang="c">
// Отримує наступну лексему.
void parser::get_token() {
char *temp;
tok_type = 0;
temp = token;
*temp = '\0';
if (!*exp_ptr) return; // в кінці виразу
while(isspace(*exp_ptr)) ++exp_ptr; // пропустити пропуски
if(strchr("+-*/%^=()", *exp_ptr)) {
tok_type = DELIMITER;
*temp++ = *exp_ptr++;
} else if(isalpha(*exp_ptr)) {
while(!isdelim(*exp_ptr)) *temp++ = *exp_ptr++;
tok_type = VARIABLE;
} else if (isdigit(*exp_ptr)) {
while(!isdelim(*exp_ptr)) *temp++ = *exp_ptr++;
tok_type = NUMBER;
}
*temp = '\0';
}
//Якщо параметр с є роздільником
// повертає значення true
int parser::isdelim(char c) {
if(strchr(" +-/*%^=()", c) || c==9 || c=='\r' || c==0) return 1;
return 0;
}
</syntaxhighlight>
Придивимось до цих функцій. Після перших ініціалізацій функція <code>get_token()</code> перевіряє, чи не знайдено кінець вхідного рядка. Для цього вона перевіряє символ, на який вказує вказівник <code>exp_ptr</code>. Якщо його значення рівне нулю, то досягнуто кінця виразу. Якщо у виразі залишились ще не вилучені лексеми, функція <code>get_token()</code> ігнорує всі пропуски що йдуть на початку. Оскільки пропуски ігноруються, вказівник <code>exp_ptr</code> може вказувати або на число, змінну, оператор або кінець виразу. Якщо наступним символом є оператор, він записується в змінну <code>token</code>, а в змінну <code>tok_type</code> записується константа <code>DELIMITER</code>. Якщо наступний символ - буква, то припускається, що лексема є змінною, а змінна <code>tok_type = VARIABLE</code>. Якщо наступний символ - цифра, то зчитується все число і записується в змінну <code>token</code>, а в змінну <code>tok_type</code> записується константа <code>NUMBER</code>. Нарешті, якщо наступний символ не має жодного відношення до тих типів, вважається, що функція <code>get_token()</code> досягнула кінця виразу.
Як заявлено раніше, щоб геть зовсім не запутувати код, в ньому пропущена перевірка на помилки, але з декількома домовленостями. Наприклад, передбачається, що вираз не може містити нерозпізнаних символів. Також, в цій версії програми змінні можуть мати довільну довжину, але істотний тільки перший символ.
Щоб краще зрозуміти процес розбиття виразу на лексеми, розглянемо приклад.
А + 100 - (B * C) /2
Ось такі лексеми і типи повертає функція <code>get_token()</code> в цьому прикладі:
{|class="wikitable"
! Лексема !! Тип
|-
| А || VARIABLE
|-
| + || DELIMITER
|-
| 100 || NUMBER
|-
| - || DELIMITER
|-
| ( || DELIMITER
|-
| В || VARIABLE
|-
| * || DELIMITER
|-
| С || VARIABLE
|-
| ) || DELIMITER
|-
| / || DELIMITER
|-
| 2 || NUMBER
|-
| \0 || 0
|}
==Проста програма синтаксичного аналізу виразів==
Розглянемо першу версію синтаксичного аналізатора. Він вичислює значення виразів, складених лише з констант, операторів, дужок.
<syntaxhighlight lang="c">
#include <iostream>
#include <cstdlib>
#include <cctype>
#include <cstring>
using namespace std;
enum types { DELIMITER = 1, VARIABLE, NUMBER};
class parser {
char *exp_ptr; // вказує на вираз
char token[80]; // зберігає поточну лексему
char tok_type; // зберігає тип лексеми
void eval_exp2(double &result);
void eval_exp3(double &result);
void eval_exp4(double &result);
void eval_exp5(double &result);
void eval_exp6(double &result);
void atom(double &result);
void get_token();
void serror(int error);
int isdelim(char c);
public:
parser();
double eval_exp(char *exp);
};
// конструктор
parser::parser()
{
exp_ptr = NULL;
}
//відправна точка parser
double parser::eval_exp(char *exp)
{
double result;
exp_ptr = exp;
get_token();
if(!*token) {
serror(2);
return 0.0;
}
eval_exp2(result);
if(*token)
serror(0);
return result;
}
// додати або віднімати два тарма
void parser::eval_exp2(double &result)
{
register char op;
double temp;
eval_exp3(result);
while((op = *token) == '+' || op == '-') {
get_token();
eval_exp3(temp);
switch(op) {
case '-':
result = result - temp;
break;
case '+':
result = result + temp;
break;
}
}
}
// перемножаємо або ділимо два фактори
void parser::eval_exp3(double &result)
{
register char op;
double temp;
eval_exp4(result);
while((op = *token) == '*' || op == '/' || op == '%') {
get_token();
eval_exp4(temp);
switch(op) {
case '*':
result = result * temp;
break;
case '/':
result = result / temp;
break;
case '%':
result = (int) result % (int) temp;
break;
}
}
}
// степінь
void parser::eval_exp4(double &result)
{
double temp, ex;
register int t;
eval_exp5(result);
if(*token== '^') {
get_token();
eval_exp4(temp);
ex = result;
if(temp==0.0) {
result = 1.0;
return;
}
for(t=(int)temp-1; t>0; --t) result = result * (double)ex;
}
}
// обчислення унарних операцій + або -
void parser::eval_exp5(double &result)
{
register char op;
op = 0;
if((tok_type == DELIMITER) && *token=='+' || *token == '-') {
op = *token;
get_token();
}
eval_exp6(result);
if(op=='-') result = -result;
}
// розпізнавання дужок
void parser::eval_exp6(double &result)
{
if((*token == '(')) {
get_token();
eval_exp2(result);
if(*token != ')')
serror(1);
get_token();
}
else
atom(result);
}
// получаємо число
void parser::atom(double &result)
{
switch(tok_type) {
case NUMBER:
result = atof(token);
get_token();
return;
default:
serror(0);
}
}
// виводить повідомлення про помилку
void parser::serror(int error)
{
static char *e[]= {
"Syntax Error",
"Unbalanced Parentheses",
"No expression Present"
};
cout << e[error] << endl;
}
// дістає наступну лексему
void parser::get_token()
{
register char *temp;
tok_type = 0;
temp = token;
*temp = '\0';
if(!*exp_ptr) return; // в кінці виразу
while(isspace(*exp_ptr)) ++exp_ptr; // пропуск роздільника
if(strchr("+-*/%^=()", *exp_ptr)){
tok_type = DELIMITER;
// advance to next char
*temp++ = *exp_ptr++;
}
else if(isalpha(*exp_ptr)) {
while(!isdelim(*exp_ptr)) *temp++ = *exp_ptr++;
tok_type = VARIABLE;
}
еlse if(isdigit(*exp_ptr)) {
while(!isdelim(*exp_ptr)) *temp++ = *exp_ptr++;
tok_type = NUMBER;
}
*temp = '\0';
}
// якщо параметр с - роздільник повертає значення true
int parser::isdelim(char c)
{
if(strchr(" +-/*%^=()", c) || c==9 || c=='\r' || c==0)
return 1;
return 0;
}
</syntaxhighlight>
Ця програма синтаксичного аналізу може обробити наступні оператори: +, - *, /, %. Крім того, вона може піднести число до цілого степеня і виконати унарну операцію. Програма синтаксичного аналізу правильно обчислює баланс з дужками. Фактичне обчислення виразу реалізується взаємно рекурсивними функціями eval_exp2() - eval_exp6(), а також функцією atom(), яка повертається видобуте число. Призначення кожної функції описано у коментарях. Продемонструємо використання аналізатора.
<syntaxhighlight lang="c">
int main()
{
char expstr[80];
cout << " Для закінчення введіть крапку.\n";
parser ob; // створення аналізатора
for(;;)
{
cout << " Введіть вираз: ";
cin.getline(expstr, 79);
if(*expstr=='.') break;
cout << " Відповідь: " << ob.eval_exp(expstr) << "\n\n";
};
return 0;
}
</syntaxhighlight>
Такі результати можна одержати за допомогою цієї програми.
Для закінчення введіть крапку.
Введіть вираз: 10-2*3
Відповідь: 4
Введіть вираз:: (10-2)*3
Відповідь: 24
Введіть вираз: 10/3
Відповідь: 3.33333
Введіть вираз: .
==Принцип роботи синтаксичного аналізатора==
Щоб зрозуміти точно, як працює синтаксичний аналізатор, протрасуємо його до виразом. Припускайться, що exp_ptr вказує на початок виразу.)
10 - 3 * 2
При виклику функції eval_exp(), як точка входу в аналізатор, видобуває з виразу першу лексему. Якщо лексема є нуль, то функція друкує повідомлення “Вираз пустий” і повертає управління виникаючому модулю. Проте, в даному випадку, лексема містить число 10. Оскільки, перша лексема не рівна нулю, то викликається функція eval_exp2(). В результаті функція eval_exp2() викличе eval_exp3(), і eval_exp3() викличе eval_exp4(), який у свою чергу викличе eval_exp5(). Потім функція eval_exp5() перевіряє, чи є лексема унарним + чи -, і, якщо ні, викликає функцію eval_exp6(). У цей момент програми функція eval_exp6() або рекурсивно звертається до eval_exp2() (у разі якщо вираз містить дужки), або atom(), яка повертає число. Оскільки лексема не являється відкриваючою дужкою, виконується функція atom() і змінна result приймає число 10. Потім з виразу береться інша лексема відшукана, і функції повертають управління на ланцюжок. Оскільки наступна містить знак - , управління передається функції eval_exp2().
Потім трапляється дуже важливий момент. Оскільки лексема містить знак -, він зберегає в змінну op. Потім аналізатор бере наступну лексему, яка є 3, і знову починає рекурсивний спуск по ланцюжку. Спочатку, як і колись, викликається функція atom(), якаповертає значення 3. Це число присвоюється змінній result, після чого зчитується лексема *. Після чого управління повертається по ланцюгу до функції eval_exp3(), яка зчитує останню лексему, рівна числу 2. У цей момент виконується перша арифметична операція - множення 2 * 3. Результат повертається у функцію eval_exp2(), в якійвикоеується віднімання. Результатом віднімання являється число 4. Хоча, на перший погляд, процес аналізу спочатку здається складним, його перевірка на других прикладах показує, що всі функції працюють правильно.
На основі цього синтаксичного аналізатору можна скласти простий калькулятор. Однак перед тим, як застосовувати його в складніших програмах, наприклад, в базах даних, де потрібно навчитись працювати зі змінними. Саме цьому присвячено наступний пункт.
==Синтаксичний аналізатор, що працює зі змінними==
Всі мови програмування, багато калькуляторів і електронні таблиці використовують змінні для запам'ятовування значень. У всіх них застосовується синтаксичний аналіз виразів, тому потрібно навчитись обробляти змінні. Щоб досягти цього, нам потрібно удосконалити наш синтаксичний аналіз виразів. Як заявлено раніше, для визначення змінних ми використовуватимемо букви від а до z. Змінні будуть запам'ятовуватися в масиві класу parser . Як наслідок, в клас parser потрібно включити новий член.
Double vars[NUMBERS];//зберігає значення змінних
Крім того, прийдеться змінити конструктор класу parser.
<syntaxhighlight lang="c">
parser::parser() {
int i;
exp_ptr = NULL;
for(i=0; i<NUMVARS; i++)
vars[i] = 0.0;
}
</syntaxhighlight>
Як бачимо, ініціалізуються нулями.
Крім того, нам згодиться функція, яка визначає значення змінної. Оскільки змінні називаються буквами від a до z, їх легко використовувати в якості індексів масиву vars, відраховуючи з імен змінних ASCII-код букви a. Цю операцію виконує функція-член find-var().
<syntaxhighlight lang="c">
// повертає значення змінної
double parser::find_var(char *s) {
if(!isalpha(*s)) {
serror(1);
return 0.0;
}
return vars[toupper(*token)-'A'];
}
</syntaxhighlight>
Функція допускає довгі імена змінних, але враховує лишень перший їх символ. Всі можуть модифікувати її по своєму розсуду.
Крім того, нам необхідно змінити функцію atom(), щоб вона могла обробляти на тільки числа, а і змінні. Тобто.
<syntaxhighlight lang="c">
//вилучає число або значення змінної
void parser::atom(double &result) {
switch(tok_type) {
case VARIABLE:
result = find_var(token);
get_token();
return;
case NUMBER:
result = atof(token);
get_token();
return;
default:
serror(0);
}
}
</syntaxhighlight>
З технічної точки зору цих змінних достатньо, щоб виконати синтаксичний аналіз виразів, які містять змінні. Однак в нас ще нема функції, яка присвоює змінним їх значення. Досить часто ця операція виконується за межами синтаксичного аналізатора, але ми напишемо свій оператор присвоювання і зробимо його частиною класу parser. Це можна зробити по-різному. По-перше, можна добавити в клас parser функцію eval_ex1(). Тепер наш ланцюжок рекурсивного спуску буде починатися з неї. Це означає, що на початку синтаксичного аналізу виразів повинна викликатися функція eval_ex1(), а не функція eval_ex2().
Переглянемо визначення функції eval_ex1().
<syntaxhighlight lang="c">
//присвоювання
void parser::eval_exp1(double &result) {
int slot;
char ttok_type;
char temp_token[80];
if(tok_type==VARIABLE) {
// зберігає стару лексему
strcpy(temp_token, token);
ttok_type = tok_type;
// знаходимо індекс змцнної
slot = toupper(*token) - 'A';
get_token();
if(*token != '=') {
putback(); // повертає поточну лексему
// відновлює стару лексему -
// присвоєння не відбувається
strcpy(token, temp_token);
tok_type = ttok_type;
} else {
get_token(); // вилучаємо наступну частину виразу exp
eval_exp2(result);
vars[slot] = result;
return;
}
}
eval_exp2(result);
}
</syntaxhighlight>
Очевидно, що ця функція наперед переглядає вираз, щоб визначити, чи дійсно треба виконувати присвоювання. Це необхідно робити тому, що ім'я змінної завжди передує оператору присвоювання, але само по собі не гарантує, що за ним обов’язково буде слідувати оператор присвоювання. Інакше кажучи, аналізатор розпізнає вираз А = 100 як операцію присвоювання і може відрізнити його від виразу А/10/.Для цього функція eval_exp1() зчитує з вхідного потоку наступну лексему. Якщо вона нетримає знак рівності, лексема повертається у вхідний потік з допомогою функції putback(), яка являється частиною класу parser.
<syntaxhighlight lang="c">
//повертає лексему у вхідний потік
void parser::putback() {
char *t;
t = token;
for(; *t; t++)
exp_ptr--;
}
</syntaxhighlight>
Після зроблених змін, клас parser приймає наступний вигляд.
<syntaxhighlight lang="c">
/* Програма, яка виконує рекурсивний спуск виразів зі змінними */
#include <iostream>
#include <cstdlib>
#include <cctype>
#include <cstring>
using namespace std;
enum types { DELIMITER = 1, VARIABLE, NUMBER};
const int NUMVARS = 26;
class parser {
char *exp_ptr; // вказує на вираз
char token[80]; // зберігає поточну лексему
char tok_type; // зберігає тип лексеми
double vars[NUMVARS]; // зберігає значення змінних
void eval_exp1(double &result);
void eval_exp2(double &result);
void eval_exp3(double &result);
void eval_exp4(double &result);
void eval_exp5(double &result);
void eval_exp6(double &result);
void atom(double &result);
void get_token();
void putback();
void serror(int error);
double find_var(char *s);
int isdelim(char c);
public:
parser();
double eval_exp(char *exp);
};
// parser конструктор
parser::parser() {
int i;
exp_ptr = NULL;
for(i=0; i<NUMVARS; i++)
vars[i] = 0.0;
}
// Початкова точка аналізатора
double parser::eval_exp(char *exp) {
double result;
exp_ptr = exp;
get_token();
if (!*token) {
serror(2); // вираз пустий
return 0.0;
}
eval_exp1(result);
if (*token) serror(0); // остання лексема повинна бути 0-символом
return result;
}
// присвоювання
void parser::eval_exp1(double &result) {
int slot;
char ttok_type;
char temp_token[80];
if(tok_type==VARIABLE) {
// зберігає стару лексему
strcpy(temp_token, token);
ttok_type = tok_type;
// знаходимо індекс змінної
slot = toupper(*token) - 'A';
get_token();
if (*token != '=') {
putback(); // повертає поточну лексему
// відновлює стару – присвоювання не відбувається
strcpy(token, temp_token);
tok_type = ttok_type;
} else {
get_token(); //вилучаємо наступну частину виразу exp
eval_exp2(result);
vars[slot] = result;
return;
}
}
eval_exp2(result);
}
// додаємо або віднімаємо два терма
void parser::eval_exp2(double &result) {
register char op;
double temp;
eval_exp3(result);
while((op = *token) == '+' || op == '-') {
get_token();
eval_exp3(temp);
switch (op) {
case '-':
result = result - temp;
break;
case '+':
result = result + temp;
break;
}
}
}
// множимо або ділимо два фактори
void parser::eval_exp3(double &result) {
register char op;
double temp;
eval_exp4(result);
while ((op = *token) == '*' || op == '/' || op == '%') {
get_token();
eval_exp4(temp);
switch (op) {
case '*':
result = result * temp;
break;
case '/':
result = result / temp;
break;
case '%':
result = (int) result % (int) temp;
break;
}
}
}
// піднесення до степеня
void parser::eval_exp4(double &result) {
double temp, ex;
register int t;
eval_exp5(result);
if (*token== '^') {
get_token();
eval_exp4(temp);
ex = result;
if (temp==0.0) {
result = 1.0;
return;
}
for(t=(int)temp-1; t>0; --t) result = result * (double)ex;
}
}
//Виконання унарних операцій + чи -.
void parser::eval_exp5(double &result) {
register char op;
op = 0;
if ((tok_type == DELIMITER) && *token=='+' || *token == '-') {
op = *token;
get_token();
}
eval_exp6(result);
if (op=='-')
result = -result;
}
// аналіз виразу, який містить дужки
void parser::eval_exp6(double &result) {
if ((*token == '(')) {
get_token();
eval_exp2(result);
if (*token != ')')
serror(1);
get_token();
} else
atom(result);
}
// вилучає число або значення змінної
void parser::atom(double &result) {
switch(tok_type) {
case VARIABLE:
result = find_var(token);
get_token();
return;
case NUMBER:
result = atof(token);
get_token();
return;
default:
serror(0);
}
}
// повертає лексему у вхідний потік
void parser::putback() {
char *t;
t = token;
for(; *t; t++) exp_ptr--;
}
// Виводить на екран повідомлення про помилку
void parser::serror(int error) {
static char *e[]= {
"Syntax Error",
"Unbalanced Parentheses",
"No expression Present"
};
cout << e[error] << endl;
}
// отримує наступну лексему.
void parser::get_token() {
register char *temp;
tok_type = 0;
temp = token;
*temp = '\0';
if (!*exp_ptr)
return; // в кінці виразу
while(isspace(*exp_ptr))
++exp_ptr; // пропуск роздільника
if (strchr("+-*/%^=()", *exp_ptr)) {
tok_type = DELIMITER;
// перехід до наступного символу
*temp++ = *exp_ptr++;
} else if (isalpha(*exp_ptr)) {
while(!isdelim(*exp_ptr))
*temp++ = *exp_ptr++;
tok_type = VARIABLE;
} else if(isdigit(*exp_ptr)) {
while (!isdelim(*exp_ptr))
*temp++ = *exp_ptr++;
tok_type = NUMBER;
}
*temp = '\0';
}
// Якщо с – роздільник, то повертає true
int parser::isdelim (char c) {
if (strchr(" +-/*%^=()", c) || c==9 || c=='\r' || c==0)
return 1;
return 0;
}
// повертає значення змінної
double parser::find_var(char *s) {
if(!isalpha(*s)) {
serror(1);
return 0.0;
}
return vars[toupper(*token)-'A'];
}
</syntaxhighlight>
Для перевірки нової версії можна знову застосувати функцію main(), яка така ж як попередня.
<syntaxhighlight lang="c">
// тестування
int main() {
char expstr[80];
cout << " Для закінчення введіть крапку.\n";
parser ob; // створення аналізатора
for (;;) {
cout << " Введіть вираз: ";
cin.getline(expstr, 79);
if (*expstr=='.') break;
cout << " Відповідь: " << ob.eval_exp(expstr) << "\n\n";
};
return 0;
}
</syntaxhighlight>
Тепер можна обчислити складніші вирази, наприклад:
X = 10/4
X – 12
X = (X * (X – 21)^2-12)/2
[[Категорія:C++]]
{{Стадія|75%}}
[[Категорія:Програмне забезпечення]]
adifzekh0sk4xhg273uycjrevz757f7
Common Lisp
0
2623
36868
30889
2022-08-03T18:52:47Z
Володимир Груша
985
wikitext
text/x-wiki
[[File:Common lisp-book cover.svg|thumb|350px|Обкладинка книжки]]
Текст наведеного підручника базується на підручнику [http://www.unicyb.kiev.ua/Library/Lisp/LISP.HTM Мова функціонального програмування Лiсп]. За дозволом автора, цей текст перенесено до розділу Вікіпідручник.
Цей підручник також доступний у [[Вікіпідручник:Книги/Мова програмування Лісп|вигляді Вікі-книги]] в різних форматах.
== Вступ ==
Оригінальний підручник був написаний для інтерпретатора muLisp. На жаль, на сьогоднішній день цей інтерпретатор не має такої активної підтримки як колись. Тому, цей підручник адаптовано для сучасного стандарту мови програмування Лісп — [[w:Коммон Лісп|Коммон Лісп]]. Однак, деякі з наведених прикладів працюватимуть і на інших Лісп-платформах (таких як [[w:Scheme (мова програмування)|Scheme]], [[w:Emacs Lisp|Emacs Lisp]], тощо).
Частини коду, що не сумісні зі стандартом Коммон Ліспа помічено {{CL-}}, перелічені нижче частини підручника помічені [[Файл:00%.svg]] знаходяться на початкових етапах адаптації до стандарту Коммон Лісп. Перелік реалізацій Коммон Ліспа дивіться на сторінці Вікіпедії [[w:Коммон Лісп|Коммон Лісп]].
== Правила форматування ==
Підручник дотримуватиметься таких правил форматування (запозичених із книжки Common Lisp the Language).
Результат виконання тексту програми позначено символом <tt>⇒</tt>
<syntaxhighlight lang="lisp">
(+ 4 5) ⇒ 9
</syntaxhighlight>
Результат розкриття макросу позначено символом <tt>→</tt>
<syntaxhighlight lang="lisp">
(push x v) → (setf v (cons x v))
</syntaxhighlight>
Однаковий (ідентичний) за результатами обчислення код позначено символом ≡
<syntaxhighlight lang="lisp">
(gcd x (gcd y z)) ≡ (gcd (gcd x y) z)
</syntaxhighlight>
== Зміст ==
# [[Мова програмування Лісп/Об'єкти Ліспу|Поняття функціонального програмування. Об'єкти Ліспу. Примітивні функції Ліспу. Функції призначення]][[image:75%.png]]
# [[Мова програмування Лісп/Визначення Функцій в Ліспі|Визначення функцій в Ліспі. Трасировка функцій]][[image:25%.png]]
# [[Мова програмування Лісп/Примітивні об'єкти даних|Примітивні об'єкти даних. Функції властивостей. Функції розпізнання.]][[image:00%.svg]]
# [[Мова програмування Лісп/Числові функції|Числові функції та арифметичні задачі]][[image:00%.svg]]
# [[Мова програмування Лісп/Контpольнi констpукцiї|Контpольнi констpукцiї]][[image:00%.svg]]
# [[Мова програмування Лісп/Iндуктивнi функції|Iндуктивнi функції]][[image:00%.svg]]
# [[Мова програмування Лісп/Функцiї виводу|Функцiї виводу]][[image:75%.png]]
# [[Мова програмування Лісп/Кеpування пам'яттю|Кеpування пам'яттю]][[image:00%.svg]]
# [[Мова програмування Лісп/Пакети пpеpивань|Пакети пpеpивань. Повiдомлення пpо помилки]][[image:00%.svg]]
# [[Мова програмування Лісп/Обробка масивів|Обробка масивів]][[image:00%.svg]]
# [[Мова програмування Лісп/Функції рядків|Функції рядків]][[image:00%.svg]]
# [[Мова програмування Лісп/Породження комбінаторих об'єктів|Породження комбінаторих об'єктів]][[image:00%.svg]]
# [[Мова програмування Лісп/Обчислювані функції|Обчислювані функції]][[image:00%.svg]]
# [[Мова програмування Лісп/Дерева|Дерева. Функції модифікатора]] [[image:75%.png]]
# [[Мова програмування Лісп/Робота з файлами|Робота з файлами]][[image:00%.svg]]
# [[Мова програмування Лісп/Функції планування|Функції планування]][[image:00%.svg]]
# [[:Категорія:Мова програмування Лісп/Відповіді|Відповіді на завдання]][[image:00%.svg]]
[[en:Common Lisp]]
== Додаткові теми ==
* [[Common Lisp/Розробка програм в Emacs та SLIME|Розробка Лісп-програм в Emacs + SLIME]]
* [[Common Lisp/Програмування для Web|Програмування для Web]]
== Додаткова література ==
* {{cite book|
назва=Common Lisp HyperSpec|
автор=Kent Pitman|
рік=1996|
видавництво=The Harlequin Group Limited|
посилання=http://www.lispworks.com/documentation/HyperSpec/Front/index.htm}}
* {{cite book|
автор=Guy L. Steele Jr|
назва=Common Lisp the Language|
видання=2-ге}}
* [[:en:Programming:Common Lisp]] — англомовний вікі-підручник.
* [http://www.cs.gmu.edu/~sean/lisp/LispTutorial.html Lisp Quickstart]
[[Категорія:Мова програмування Лісп]]
[[Категорія:Мови програмування]]
{{Стадія|100%}}
agyxm2holiwaoe9s49ngz8bksemb21w
Основи інформатики
0
2937
36874
36564
2022-08-03T19:01:21Z
Володимир Груша
985
wikitext
text/x-wiki
'''1. Вступ. Інформація та інформаційні процеси '''
[[Основи інформатики/Інформатика. Інформація і повідомлення. Властивості інформації. Інформаційні процеси]]
[[Основи інформатики/Форми і способи подання повідомлень. Кодування повідомлень]]
[[Поняття про сучасні засоби зберігання й опрацювання повідомлень. Одиниці вимірювання ємності запам’ятовуючих пристроїв]]
'''2. Інформаційна система та її складові'''
[[Структура інформаційної системи: апаратна та інформаційна складові, їх взаємодія]]
[[Техніка безпеки при роботі на комп’ютері. Правила підготовки комп’ютера до роботи]]
[[Пристрої введення-виведення даних]]
[[Процесор]]
[[Пам’ять комп’ютера. Внутрішня пам’ять комп’ютера]]
[[Зовнішні запам’ятовуючі пристрої комп’ютера]]
[[Основні характеристики комп’ютера]]
[[Основи інформатики/Історія обчислювальної техніки]]
[[Огляд сучасної обчислювальної техніки. Основні галузі застосування комп’ютерів]]
[[Види програмного забезпечення інформаційної системи]]
[[Операційна система, її функції]]
[[Поняття файла]]
[[Інсталювання програмних засобів]]
[[Комп’ютерні віруси]]
[[Поняття про стиснення даних. Архівація файлів]]
'''4. Прикладне програмне забезпечення'''
'''4.1. Графічний редактор'''
[[Системи опрацювання графічної інформації. Типи графічних файлів]]
[[Графічний редактор і його призначення]]
'''4.2. Текстовий редактор'''
[[Системи опрацювання текстів, їх функції]]
[[Введення тексту з клавіатури. Редагування тексту]]
[[Робота з фрагментами тексту: виділення, перенесення, копіювання, форматування, пошук, заміна]]
[[Робота з таблицями]]
[[Робота з графічними об’єктами в середовищі текстового редактора]]
[[Форматування документа]]
'''4.3. Комп’ютерні презентації'''
[[Поняття комп’ютерної презентації]]
'''4.4. Табличний процесор'''
[[Електронна таблиця та її основні об’єкти. Табличний процесор]]
[[Введення і редагування даних]]
[[Використання обчислень, функцій та операцій]]
[[Побудова діаграм і графіків]]
[[Упорядкування і пошук даних. Фільтрування даних]]
'''4.5. Бази даних. Системи управління базами даних'''
[[Поняття про бази даних та їх види]]
[[Проектування бази даних і створення структури бази даних]]
[[Введення та редагування даних]]
[[Пошук, упорядкування та фільтрування даних]]
[[Використання запитів. Форми. Звіти]]
'''5. Глобальна мережа Інтернет'''
[[Комп’ютерні мережі]]
[[Глобальна мережа Інтернет. Інформаційний зв’язок у мережі Інтернет]]
[[Принципи роботи з HTML. Створення та перегляд]]
[[Пошук інформації в мережі Інтернет. Пошукові системи]]
[[Електронна пошта]]
[[Інформаційна безпека при роботі в мережі Інтернет]]
'''6. Комп’ютерне моделювання. Основи алгоритмізації та програмування'''
[[Інформаційні моделі. Основні етапи комп’ютерного моделювання]]
[[Алгоритми. Виконавець алгоритму. Базові структури алгоритмів]]
[[Порядок складання алгоритмів. Поняття програми]]
[[ Величини. Типи величин. Опрацювання величин]]
[[Вказівка про надання значення. Формальні і фактичні параметри]]
[[Виконання й аналіз правильності алгоритмів і програм]]
[[Вказівки розгалуження]]
[[Вказівки повторення]]
[[Табличні величини. Алгоритми опрацювання табличних величин]]
[[Алгоритми пошуку елементів у таблиці]]
[[Алгоритми впорядкування лінійних таблиць]]
[[Основи інформатики/Scratch]]
[[Категорія:Основи інформатики]]
[[Категорія:Інформатика]]
{{Стадія|25%}}
73dvyco7pw384y2lomfj4c4dj0t3odi
Підручник мови Python
0
3094
36869
33593
2022-08-03T18:54:31Z
Володимир Груша
985
wikitext
text/x-wiki
{{Примітка версії для друку}}
__notoc__
== Зміст ==
# [[Підручник мови Python/Вступ|Вступ]] [[Файл:100 percent.svg]]
# [[Підручник мови Python/Неформальний вступ до мови Python|Неформальний вступ до мови Python]] [[Файл:100 percent.svg]]
# [[Підручник мови Python/Контрольні структури|Контрольні структури]] [[Файл:100 percent.svg]]
# [[Підручник мови Python/Структури даних|Структури даних]] [[Файл:100 percent.svg]]
# [[Підручник мови Python/Модулі|Модулі]] [[Файл:75%.png]]
# [[Підручник мови Python/Ввід і вивід|Ввід і вивід]] [[Файл:75%.png]]
# [[Підручник мови Python/Помилки та винятки|Помилки та винятки]] [[Файл:75%.png]]
# [[Підручник мови Python/Класи|Класи]] [[Файл:75%.png]]
# [[Підручник мови Python/Короткий огляд стандартної бібліотеки|Короткий огляд стандартної бібліотеки]] [[Файл:75%.png]]
# [[Підручник мови Python/Короткий огляд стандартної бібліотеки II|Короткий огляд стандартної бібліотеки II]] [[Файл:75%.png]]
# [[Підручник мови Python/Що далі?|Що далі?]] [[Файл:75%.png]]
== Автори: ==
# ''Ґвідо ван Россум''(''Guido van Rossum'')
# ''Фред Л. Дрейк Молодший'' (''Fred L. Drake, Jr.'')
#:Оригінал знаходиться за цією [http://docs.python.org/tut/tut.html адресою] — '''''нечинне посилання. Зараз''''' — https://web.archive.org/web/20050427074653/http://docs.python.org/tut/tut.html
# Переклад: ''Сергій Кузьменко''.
#: Матеріал взято із [http://docs.linux.org.ua/%D0%9F%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D1%83%D0%B2%D0%B0%D0%BD%D0%BD%D1%8F/Python/%D0%9F%D1%96%D0%B4%D1%80%D1%83%D1%87%D0%BD%D0%B8%D0%BA_%D0%BC%D0%BE%D0%B2%D0%B8_Python/ docs.linux.org.ua] — збірника документації з Unix/Linux українською мовою.
# Редагування та оформлення: спільнота вікіпідручника
Copyright © 2001-2004 Python Software Foundation. All rights reserved.
Copyright © 2000 BeOpen.com. All rights reserved.
Copyright © 1995-2000 Corporation for National Research Initiatives. All rights reserved.
Copyright © 1991-1995 Stichting Mathematisch Centrum. All rights reserved.
[[Категорія:Python]]
[[Категорія:Мови програмування]]
{{Стадія|100%}}
0ggfzr88alvqrj5j0xv7w7gb7asgvt1
Пограймо зі змією
0
3237
36866
34332
2022-08-03T18:39:54Z
Володимир Груша
985
wikitext
text/x-wiki
[[Файл:PetitPrincePython.jpg|right]]
Це книжка про те, як програмувати мовою Python, створювати нові світи, та отримувати від цього задоволення.
Взагалі тут має стояти об'єктивна анотація, але я хочу, щоб її колись написав хтось інший.
=== Зміст ===
#[[Давайте пограємо зі змією/Вступ|Вступ]] [[Файл:50%.png]]
#*Давайте познайомимось
#**Чому для написання гри варто обрати саме Python?
#**Чому не варто писати ігри на мові Python?
#*Що потрібно щоб почати забаву?
#[[Давайте пограємо зі змією/Текстові ігри|Слова, слова, слова, або не кожну гру малюють...]]
#[[Давайте пограємо зі змією/Авіаудар|Авіаудар]] [[Файл:00%.svg]]
#[[Давайте пограємо зі змією/Ігри на полі в клітинку|Цивілізація прямокутника]]
#[[Давайте пограємо зі змією/PyQt|PyQt]]
# [[Давайте пограємо зі змією/OpenGL|OpenGL]]
# [[Давайте пограємо зі змією/Об'єм|Об'єм]]
# [[Давайте пограємо зі змією/Світло|Світло]]!
# [[Давайте пограємо зі змією/Камера|Камера]]!
# Мотор!
#[[Давайте пограємо зі змією/Скриптуємо Блендер|Скриптуємо Блендер]]
#[[Давайте пограємо зі змією/Blender Game Engine|Blender Game Engine]]
#[[Давайте пограємо зі змією/Збираємо команду|Збираємо команду!]]
#[[Давайте пограємо зі змією/Корисні посилання|Корисні посилання]]
{{Епіграф|Дорослі порадили мені не малювати змій ні ззовні, ні з середини, а побільше цікавитись географією, історією, арифметикою та правописом.|[[w:Антуан де Сент-Екзюпері|Антуан де Сент-Екзюпері]]}}
[[Категорія:Python]]
[[Категорія:Давайте пограємо зі змією]]
[[Категорія:Мови програмування]]
{{Стадія|50%}}
1kxey44lmeki2xc8m4w5gg895ea8ejo
C++
0
3242
36870
36512
2022-08-03T18:56:20Z
Володимир Груша
985
wikitext
text/x-wiki
{{Примітка версії для друку}}
__NOTOC__
'''[[w:C++|C++]]''' ('''Сі-плюс-плюс''') — універсальна [[w:мова програмування|мова програмування]] високого рівня з підтримкою декількох [[w:парадигма програмування|парадигм програмування]]: [[w:Об’єктно-орієнтоване програмування|об'єктно-орієнтованої]], [[w:узагальнене програмування|узагальненої]] та [[w:Процедурне програмування|процедурної]]. Розроблена Б'ярном Страуструпом (Bjarne Stroustrup) в AT&T Bell Laboratories (Мюррей-Хілл, Нью-Джерсі) у 1979 році та названа «Сі з класами». Страуструп перейменував мову у C++ у 1983 р. Базується на мові Сі. Визначена стандартом ISO/IEC 14882:2003.
У 1990-х роках С++ стала однією з найуживаніших мов програмування загального призначення.
== Зміст ==
==='''Розділ 1''': Мова програмування С++===
# [[:C++/Вступ у C++|Вступ у C++]]
# [[:C++/Вступ у C++/Компілятор|Компілятор]]
==='''Розділ 2''': Основи С++===
# [[:C++/Основи/Директиви препроцесора|Директиви препроцесора]]
# [[:C++/Основи/Змінні|Змінні]]
# [[:C++/Основи/Складні типи даних|Складні типи даних (масиви)]]
# [[:C++/Основи/Простори імен|Простори імен]]
# [[:C++/Основи/Константи|Константи]]
# [[:C++/Основи/Вказівники|Вказівники]]
# [[:C++/Основи/Об'єднання (union)|Об'єднання (union)]]
==='''Розділ 3''': Об'єктно-орієнтовне програмування===
# [[:C++/Об'єктно-орієнтовне програмування/Структури|Структури]]
# [[:C++/Об'єктно-орієнтовне програмування/Класи|Класи]]
# [[:C++/Об'єктно-орієнтовне програмування/Перевантаження операторів|Перевантаження операторів]]
==='''Розділ 4''': Додатковий функціонал===
# [[:C++/Додатковий функціонал/Шаблони|Шаблони]]
## [[:C++/Додатковий функціонал/Шаблони#Розумні_вказівники_(Smart_pointers)|Розумні вказівники]]
# [[:C++/Додатковий функціонал/Концепція|Концепція]]
# [[:C++/Додатковий функціонал/Модулі|Модулі]]
==='''Розділ 5''': Шаблони проектування і структури даних===
# [[:C++/Шаблони проектування і структури даних/Контейнери|Контейнери]]
== Ключові слова ==
[[C++/Ключові слова|Ключові слова мови програмування С++]]
== Література ==
#Герберт Шилдт - Полный справочник C++
#[http://www.insycom.ru/html/metodmat/inf/Lipman.pdf Липпман, C++ для начинающих]
#[http://vk.com/doc-46376942_155083420?dl=24b21c4e6fb0b99470 «С++ for real programmers», Джефф Елджер]
#[http://www.cplusplus.com/files/tutorial.pdf cplusplus.com] - C++ Language Tutorial, June 2007
== Примітки ==
{{reflist}}
{{Стадія|50%}}
[[Категорія:Мови програмування]]
[[Категорія:C++]]
ml4ri4h6dnkft9uz64s2g3abesfirme
HTML
0
3243
36873
31712
2022-08-03T19:00:04Z
Володимир Груша
985
/* Посилання */
wikitext
text/x-wiki
== Вступ ==
Одного разу я побачив книжку по Web-дизайну, а, оскільки я мав звичку читати все що бачу, то я її прочитав. І з того часу вважав, що знаю HTML. Але недавно, мені сказали адресу одного хорошого сайту [http://www.w3schools.com/ www.w3schools.com]. Символи “w3″ в назві сайту означають “три w”, або “www”. Що важливого я там дізнався? По-перше, що мої знання дещо застарілі. По друге, що те що мої теги розпізнає браузер, ще не значить, що так буде тривати і далі. Тому я вирішив написати сучаснішу українську книжку про веб-дизайн.
[[Файл:Html-small.png]]
Постараюся описати все якомога доступніше і згідно з новими тенденціями. Бо консерватизм – це ніщо інше, як лінь вчити щось нове. Але коли ви не вчите нове, ви відстаєте. А відставання в сучасному світі недопустиме. Тому тут будемо розглядати HTML 4.01.
<blockquote>Насправді найсучаснішою версією HTML вже стає [[w:HTML5|HTML5]], тому краще зразу читати про нього.</blockquote>
Як годиться варто почати з означень. [[w:HTML|HTML]] (Hyper Text Markup Language) – значить мова розмітки гіпертекстових сторінок. Навіть не вважається мовою програмування, але кожен програміст, що себе поважає, має її знати. Бо без неї вчити [[JavaScript]], чи [[PHP]] нема сенсу.
Чим відрізняється стандарт HTML 4.01 від попередніх HTML? Спочатку коротенька історія. Існує така організація W3C (World Wide Web Consortium). Суть її роботи добре виражена в їхньому гаслі “Leading the Web to Its Full Potential…” (“Приведемо всесвітнє павутиння до його повних можливостей”). Судячи з того що вони вже зробили, люди розумні і свою роботу знають. І коли вони кажуть, що в майбутньому браузери не будуть підтримувати старі версії HTML, то воно напевне так і буде. А нові браузери з’являються не так вже і рідко. Коли W3C створювали стандарт HTML, в ньому не передбачалося тегів для форматування гіпертексту. Теги показували тільки структуру документа, наприклад:
<syntaxhighlight lang="html4strict">
<h1>Це заголовок</h1>
<p>Це абзац</p>
</syntaxhighlight>
Але потім розробники браузерів почали додавати в HTML свої теги, які їм подобались. Наприклад:
<syntaxhighlight lang="html4strict">
<marquee>Біжучий рядок, який за чутками вміє відображати лише IE<sup>*</sup></marquee>
</syntaxhighlight>
<blockquote>''IE* – давайте звідси і далі так будемо називати [[w:Internet Explorer|Internet Explorer]]. А про фразу вище – брехня. FF ([[w:Firefox|Firefox]]) щойно нормально вивів той нещасний рядок. Але все одно, краще такими тегами не користуватись.''</blockquote>
Так само небажаною була поява в стандарті HTML 3.2 тегу <nowiki><font></nowiki>. Уявіть собі, що потрібно написати сторінку, де всі заголовки червоні. І доводиться крім тегів заголовку писати ще тег шрифту з атрибутом кольору.
Прихід четвертої версії розділяє форматування тексту і його структуру. Тепер в HTML сторінці зберігаємо тільки структуру документа (різнорівневі заголовки, абзаци, цитати, списки), а все що відноситься до форматування описуєтся в [[CSS]]. Це зручно, бо дозволяє швидко міняти оформлення всього сайту зміною лише файлу з стилем, і крім того зменшує довжину коду, який потрібно написати. Крім того, HTML 4.01 дозволяє швидко переходити до [[w:XHTML|XHTML]] – HTML сумісний з [[w:XML|XML]]. XML – простіше обробляти різними програмами ніж HTML.
== Структура сторінки ==
=== До роботи! ===
Найкращий спосіб навчитись щось робити – зробити це. Не вийде – вчитись далі. А вийде – значить ви вже навчились. :)
Для того щоб вивчити HTML, окрім читання цього підручника нам потрібно мати:
# [[w:Комп'ютер|Комп'ютер]]
# [[w:Браузер|Браузер]]
# [[w:Текстовий редактор|Текстовий редактор]]
Оскільки ви читаєте цей текст, дві перші речі в вас точно є. Текстовий редактор також є на кожному комп’ютері. Важливо зауважити: нам потрібна програма для редагування текстових файлів, а не документів. Зазвичай стандартного текстового редактора вашої ОС (наприклад gedit у GNOME, KEdit у KDE, блокнота Windows) достатньо, але є текстові редактори, які краще пристосовані до написання HTML-сторінок. Непоганий редактор для Windows [[w:Notepad++|Notepad++]], в якому добре писати не тільки HTML, а і CSS, PHP, C++, і ще кілька десятків інших мов. В ньому є така хороша річ, як підсвітка синтаксису, яка дозволяє виявляти помилки прямо під час їх створення :). Якщо ж у вас Linux, тоді ви точно знаєте, що таке хороший текстовий редактор.
Про браузер також варто сказати дещо. Всі радять тримати в себе на комп’ютері набір браузерів (IE, Firefox, Opera, Chrome) і переглядати свої сторінки у всіх зразу. Щоправда, функції тегів в різних браузерах відрізняються не сильно (в ідеалі взагалі не відрізняються). Тому вчитись можна переглядаючи свої сторінки в одному, а вже коли пишете щось велике — подивіться чи не має надто критичних відмінностей у всіх інших.
Щоб створити веб-сторінку, потрібно створити в файловій системі текстовий файл з розширенням html, або htm. Яке з них вибрати – філософське питання. htm – скорочення від html, що є доволі смішним фактом, оскільки html це теж скорочення. Але були часи, коли в деяких ОС розширення файлу могло містити максимум 3 символи, і сторінки гіпертексту мали розширення htm. Тепер можна використовувати обидва розширення.
=== Вміст веб-сторінки ===
Веб-сторінки складаються з [[w:Гіпертекст|гіпертексту]]. Гіпертекст відрізняється від звичайного тексту тим, що містить гіперпосилання. Вони зазвичай позначені підкресленням і синім кольором, і дозволяють зробити гіперстрибок в інший <s>всесвіт</s> гіпертекст, чи будь-яке інше місце, вказане за допомогою [[w:URL|URL]]. Гіпертекст складається з тегів.
URL (Universal Resource Locator) – адреса ресурсу, яку ми бачимо в адресному рядку браузера.
Тег – все що знаходиться між кутніми дужками. Наприклад <nowiki><html></nowiki>.Теги не відображаються браузером, вони лише задають структуру тексту. Теги бувають трьох видів: відкриваючі, закриваючі і одинарні. Відкриваючі і закриваючі теги завжди ходять парами. Закриваючий відрізняєтся від відкриваючого тим, що після знаку менше <code><</code> стоїть знак слеш (чи ділення) <code>/</code>. Пара закриваючого і відкриваючого тега виглядає так: <nowiki><html></html></nowiki>. Одинарні теги – річ суперечлива, і я їх розгляну пізніше
<blockquote>''Важливо знати, що починаючи з версії 4.01 всі теги мають бути написані маленькими буквами.''</blockquote>
Елемент гіпертексту – це все що знаходиться між відкриваючим і закриваючим тегом. Елементи бувають вкладені.
Наведу приклад коду веб-сторінки:
<syntaxhighlight lang="html4strict">
<html>
<head>
<!-- Заголовочна інформація, наприклад: -->
<title>Назва сторінки (відображається в рядку заголовку браузера)</title>
</head>
<body>
Вміст сторінки.
</body>
</html>
</syntaxhighlight>
Всі теги які зустрічаються вище є обов’язковими. Вони присутні в кожній сторінці в інтернеті. Звісно, якщо ви якийсь із них забудете, браузер якось розбереться, але всі серйозні люди такі речі не забувають. Тег html каже браузеру що в ньому міститься код HTML. Тег head, каже що в ньому міститься заголовочна інформація сторінки. Ця інформація на самій сторінці не відображається. Тег title, як вже було сказано, містить заголовок, який відобразиться в рядку заголовку. body містить тіло, або вміст сторінки.
Окрім тегів і тексту, гіпертекстові сторінки можуть містити коментарі. Коментарі виглядають так: <code><nowiki><!-- Коментар --></nowiki></code>. Вони дозволяють писати на сторінці текст, який не відображається браузером. Це потрібно для вставки повідомлень типу <code><nowiki><!-- Тут не забути дописати абзац про коментарі --></nowiki></code>.
Ще існує поняття спеціальних символів. Наприклад, ви напишете таку сторінку:
<syntaxhighlight lang="html4strict">
<html>
<head>
<title>З чого починається сторінка</title>
</head>
<body>
Кожна сторінка HTML починається з тегу <html>.
</body>
</html>
</syntaxhighlight>
Така сторінка відобразиться браузером неправильно, через те, що браузер не виводить теги. А html – тег. Така сама проблема і з символами порівняння. Тому, щоб відображати деякі нестандартні символи, існує поняття спеціальних символів. Спеціальні символи в HTML описуються так: &код;. Наприклад:
{|class="wikitable"
|-
!Назва !! Код !! Вигляд
|-
|Менше || <syntaxhighlight lang="html4strict"><</syntaxhighlight>|| <
|-
|Більше || <syntaxhighlight lang="html4strict">></syntaxhighlight> || >
|-
|Амперсанд ||<syntaxhighlight lang="html4strict">&</syntaxhighlight> || &
|}
Тут я вказав тільки най-найпотрібніші. Якщо вам потрібно більше, вам треба пошукати. Можна пошукати [http://www.coolchevy.org.ua/2008/04/14/specialni-simvoli-html/ десь тут]. Тобто те що ми хотіли описати в попередньому прикладі мало виглядати так:
<syntaxhighlight lang="html4strict">
<html>
<head>
<title>З чого починається сторінка</title>
</head>
<body>
Кожна сторінка HTML починається з тегу <html>.
</body>
</html>
</syntaxhighlight>
=== Теги форматування ===
Тепер перейдем до форматування тексту. Форматування задає не так зовнішній вигляд, як структуру сторінки. Найважливішими тегами форматування є абзаци (англ. paragraph) і заголовки (англ. header). Заголовки бувають шести рівнів. Заголовки першого рівня найголовніші і найбільші, а заголовки шостого рівня навіть менші ніж текст абзаців. Нижче приклад використання заголовків:
<syntaxhighlight lang="html4strict">
<html>
<head>
<title>Володар перстенів</title>
</head>
<body>
<h2>Пролог</h2>
<h3>Про гобітів</h3>
У цій книзі йтиметься здебільшого про хобітів, і з її сторінок читач довідається чимало про їхню ...і т. д.
<h1>БРАТСТВО ПЕРСНЯ</h1>
<h2>КНИГА ПЕРША</h2>
<h3>I Довгоочікувана гостина</h3>
<h3> ...і т. д.</h3>
<h3>XII Втеча до броду</h3>
<h2>КНИГА ДРУГА</h2>
<h3> ...і т. д.</h3>
</body>
</html>
</syntaxhighlight>
<blockquote>''Я тут пишу і пишу приклади. Не забувайте пробувати щось самі! Або хоча б принаймі подивіться, як будуть виглядати приклади сторінок, які вам даються у вашому браузері.''</blockquote>
Тепер ще один маленький приклад, який стосується форматування:
<syntaxhighlight lang="html4strict">
<html>
<head>
<title>Вдаряй мечем</title>
</head>
<body>
Вдаряй мечем,
Вдаряй, вдаряй,
Великий Комтуре Закона,
Щоб з нього честь
Була для нас,
А для Вкраїни оборона!
</body>
</html>
</syntaxhighlight>
На жаль, браузери відкидають всі символи переносу рядка, табуляції і навіть зайві пропуски. Тому цей віршик відобразиться в один або кілька рядків (залежно від ширини вікна). Але є вихід.
Можна кожен рядок вірша помістити в окремий абзац. Щоправда зазвичай між абзацами великі білі поля. Тому можна використати одинарний тег <nowiki><br /></nowiki>. Цей тег означає перехід на новий рядок, тобто обрив ('''br'''eak) старого.
<blockquote>''Тут варто вставити зауваження. Всі теги ходять парами відкриваючий – закриваючий. Між ними містяться елементи гіпертексту. Але тег обриву рядка не містить нічого. Тому він пари і не має. Але найновіші стандарти вимагають, щоб всі теги закривалися. Щоправда врахувавши наявність тегів подібних до br, придумали скорочену форму запису. Він ніби відкривається, а потім зразу закривається. Це здається досить дивним. Звісно можна писати і в старому форматі: <nowiki><br></nowiki>;. Але краще мати код, який відповідає найновішим стандартам.''</blockquote>
І ще один спосіб – взяти увесь вірш в теги <pre></pre>. Увесь текст поміщений між цими тегами відображається точно так само, як його видно в редакторі. Правда цей тег також змінює шрифт тексту на якийсь моноширинний. Але зате ми можемо робити з текстом цікаві речі:
<syntaxhighlight lang="html4strict">
<html>
<head>
<title>Long Tail</title>
</head>
<body>
It is a long tail, certainly,' said Alice, looking down with wonder at the Mouse's tail'
`but why do you call it sad?' And she kept on puzzling about it while the Mouse was speaking,
so that her idea of the tale was something like this:--
<pre>
`Fury said to a
mouse, That he
met in the
house,
"Let us
both go to
law: I will
prosecute
YOU. --Come,
I'll take no
denial; We
must have a
trial: For
really this
morning I've
nothing
to do."
Said the
mouse to the
cur, "Such
a trial,
dear Sir,
With
no jury
or judge,
would be
wasting
our
breath."
"I'll be
judge, I'll
be jury,"
Said
cunning
old Fury:
"I'll
try the
whole
cause,
and
condemn
you
to
death."</pre>
</body>
</html>
</syntaxhighlight>
Ще трохи про теги зміни шрифту. Шрифт може мати три додаткові атрибути '''жирність (bold)''', ''курсивність (italic)'' і <u>підкреслення (underlined)</u>. Вони змінюються за допомогою тегів: <nowiki><b></nowiki>, <nowiki><i></nowiki> та <nowiki><u></nowiki> відповідно.
Правда замість тегу <nowiki><b></nowiki> рекомендують використовувати тег <nowiki><strong></nowiki>. Окрім того існує ще така властивість як викресленість. Колись вона задавалася тегом <nowiki><s></nowiki>, що означало strikeout. Але знову ж таки в сучасному світі слова не викреслюють, їх видаляють, тому в порядку модернізації використовують тег <nowiki><del></nowiki>.
<blockquote>''Школа w3 навпроти тегів <nowiki><u>,<s></nowiki> і <nowiki><strike></nowiki> пише “deprecated”, що перекладається у нас як «застарілі», дослівно ж слово deprecate означає: “сильно заперечувати, виступати проти, протестувати”. Хто протестує не сказано, але скоріше за все Консорціум трьох дубль-ве. Замість тегів викреслення рекомендують використовувати тег видалення. А замість тегу підкреслювання – стилі.''</blockquote>
Крім тегу видалення ввели тег вставки. Тег вставки вказує текст який вставили після видалення. Виглядає така річ приблизно так:
<syntaxhighlight lang="html4strict">
2 + 2 = <del>5</del> <ins>4</ins>
</syntaxhighlight>
При чому текст в тезі <nowiki><ins></nowiki> буде підкреслений. (А хлопці з w3schools казали використовувати стилі. Хм.)
Далі опишу всі теги в таблиці, бо мені вже набридло тут про них розказувати, а вам певне набридло читати.
{|class="wikitable"
|-
!Тег !! Приклад !!Вигляд !!Опис
|-
|b || {{nobr|<nowiki><b>текст</b></nowiki>}} || <b>текст</b> ||Задає жирний текст
|-
|big ||{{nobr|<nowiki><big>текст</big></nowiki>}} || <big>текст</big>||Задає великий текст
|-
|em || || ||Задає наголошений текст. (empharized)
|-
|i || || ||Задає курсивний текст
|-
|small || || ||Задає маленький текст
|-
|strong || || ||Задає сильний текст. Виглядає майже так само, як і жирний
|-
|sub || || ||Задає текст в нижньому індексі
|-
|sup || || ||Задає текст в верхньому індексі
|-
|ins || || ||Задає текст, який вставляється після видалення. Зазвичай підкреслений.
|-
|del || || ||Задає текст, який видалений (виглядає викресленим)
|-
|code || || ||Задає текст, який представляє комп’ютерний код.
|-
|kbd || || ||Задає текст, який введений з клавіатури.
|-
|tt || || ||Задає текст, який виглядає так, ніби введений з телетайпа. (Моноширинний шрифт)
|-
|samp || || ||Задає текст, який є прикладом. (sample). Майже як приклади в цьому тексті.
|-
|var || || ||Задає текст, який представляє змінну. Напевне для всяких наукових статтей
|-
|pre || || ||Задає текст, який зберігає всі символи форматування, такі як табуляції, пробіли, і переноси рядків.
|-
|abbr || || ||Задає текст абревіатури. В атрибуті title можна записати розшифрування.
|-
|acronym || || ||Задає текст акроніму. Акронім і абревіатура – це одне і те саме.
|-
|address|| || ||Задає текст адреси. Відображається курсивом
|-
|bdo || || ||Дуже веселий тег. Для тих хто пише івритом. В в атрибуті dir можна задати напрямки тексту. “rtl” – зправа наліво, “ltr” – зліва направо.
|-
|blockquote|| || ||Задає текст великої цитати.
|-
|q || || ||Задає текст маленької цитати.
|-
|cite || || ||Задає текст якоїсь класичної цитати. Щось на зразок “Хто ясно мислить, той ясно формулює”
|-
|dfn || || ||Задає термін для якого буде дане визначення. (definition)
|}
Ну з структурою гіпертексту думаю ми розібрались, можна тепер переходити до речей глобальніших.
=== А тепер послухаємо музику ===
Тег <BGSOUND> вказує на музичний файл, який буде програватися на веб-сторінці при її відкритті. Звук, час звучання музики та інші характеристики вказуються за допомогою параметрів тега, а також можуть керуватися через скрипти. Цей тег повинен розміщуватися тільки в середині тега <nowiki><HEAD></nowiki>.
Щоб вказати файл, який буде програватися, потрібно написати так:
<syntaxhighlight lang="html4strict">
<bgsound src="Example.mid" loop="3" volume="-1000" balance="3000">
</syntaxhighlight>
Параметри:
* <nowiki>src</nowiki> вказує шлях до музичного файлу.
* <nowiki>loop</nowiki> встановлює, скільки разів буде програватися музика. За замовчуванням програєтся 1 раз.
* <nowiki>volume</nowiki> задає звук звучання музики на сторінці. За замовчуванням — 0. Гучність — ціле число від -10000 до 0. Нуль — максимальний рівень. Чим більше значення цього параметра, тим тихіше звучить музика.
* <nowiki>balance</nowiki> регулює гучність звучання в лівій і правій колонках.
== Лінки ==
=== Атрибути ===
Деякі теги мають властивості, які називаються атрибутами. Наприклад майже кожен тег має атрибут title. В ньому прописується текст підказки яку видно, коли користувач наводить курсор на елемент тегу. Хай нам потрібно написати відоме скорочення: HTML. І щоб коли користувачі наводять на нього курсор, вони могли його розшифрувати. Це робиться просто:
<syntaxhighlight lang="html4strict">
<html>
<head><title>Абревіатура</title></head>
<body>
<abbr title="Hypertext Markup Language">HTML</abbr>
</body>
</html>
</syntaxhighlight>
Тут ми бачимо, як правильно записувати атрибути. Назва атрибуту, потім знак рівності і значення в подвійних лапках. В стандарті HTML 4.01 немає атрибутів без значень.
<blockquote><i>Краще писати всі атрибути і їх значення маленькими буквами.<br />
Нащо?<br />
Заради майбутнього! (Бо так вимагає HTML 4.01)</i>
</blockquote>
=== Посилання ===
Як я вже казав, основною властивістю, яка відрізняє нормальний текст і гіпертекст, є гіперпосилання. Гіперпосилання створюються за допомогою тегу <nowiki><a></nowiki> з атрибутом href, який приймає значення потрібного нам URL. Наприклад, потрібно створити сторінку, яка містить посилання на цю статтю. Це може виглядати приблизно так:
<syntaxhighlight lang="html4strict">
<html>
<head><title>Посилання</title></head>
<body>
Тут можна знайти матеріали про web-дизайн:
<a href="http://uk.wikibooks.org/wiki/HTML">uk.wikibooks.org</a>
</body>
</html>
</syntaxhighlight>
Тепер на сторінці напис [http://uk.wikibooks.org/wiki/HTML uk.wikibooks.org] стане гіперпосиланням.
Зазвичай сторінки в інтернеті не сидять самотньо. Вони розміщуються купками, які називаються сайтами. Сайт – це за моїм визначенням набір сторінок та інших файлів, які мають спільну частину URL. Наприклад, всі сторінки, які починаються на <nowiki>http://www.microsoft.com</nowiki> належать до одного сайту однієї маленької комп’ютерної фірми. Далі йде символ “/”, і адреса продовжується.
Можна зробити в себе на комп’ютері маленьку модель сайту. Для цього потрібно створити новий каталог, в якому будемо розміщувати файли. Потім в каталозі розмістити файл index.htm. Якщо є якесь посилання на ваш сайт, без вказівки, який конкретно файл завантажувати, то буде завантажений саме index.htm. Далі ми можемо створити ще одну папку всередині нашої. Нехай вона називається subdir. Якщо в ній розмістити файл іndex.htm, то щоб перейти до нього потрібно буде написати: “www.ваш_сайт.com/subdir/”.
<blockquote>''При звертанні до каталогу завжди в кінці додавайте слеш. Якщо ви не будете додавати слеш, то сервер буде змушений виконувати два запити. Спочатку ваш, без слеша. Потім, коли він розбереться що то запит до каталога, він згенерує свій запит, з слешем, і вже його виконає.''</blockquote>
Крім гіпертекстових сторінок на сайті можна розміщувати будь-які інші файли. Тоді після клацання по посиланню буде з’являтись стандартний діалог завантаження, який може виглядати наприклад так:
[[Файл:Діалог завантаження файлу.png|frame|center|Діалог завантаження файлу.]]
Наприклад, якщо ви співак і хочете поділитись своїми піснями з іншими, ви можете покласти в папку з сайтом файл track1.mp3, а в файлі index.htm написати:
<syntaxhighlight lang="html4strict">
<html>
<head><title>Моя музика</title></head>
<body>
Я щойно записав новий трек. Ви можете <a href="track1.mp3">скачати його тут.</a>
</body>
</html>
</syntaxhighlight>
Якщо файли знаходяться в одному каталозі, то в атрибуті href достатньо написати назву файлу, щоб зробити посилання. Якщо ж ми маємо файли “site/1.htm” і “site/subdir/2.htm”, то щоб з першого зробити посилання на другий, а з другого на перший, треба написати href="subdir/2.htm" і href="../1.htm" відповідно. Такі адреси називаються відносними. Дві крапки означають “той каталог що вище”. Відносні адреси добрі тим, що коли ми перейменовуємо папку “site”, чи міняємо хостинг їх не потрібно змінювати.
Але цим можливості тегу <nowiki><a></nowiki> не вичерпуються. a – скорочено від anchor – що значить якір. За допомогою тегу <a> можна ставити в гіпертекстовому документі якорі, або говорячи простіше закладки, які дозволяють переходити в певне місце документа. Це особливо корисно, коли документ великий, і потрібно швидко переходити в ньому до певного розділу. Для цього існує атрибут id.
Щоб довго не пояснювати знову наведу приклад:
<syntaxhighlight lang="html4strict">
<html>
<head><title>Моя музика</title></head>
<body>
<h1>Зміст</h1>
<a href="#part1"><h2>Частина 1</h2></a>
<a href="#part2"><h2>Частина 2</h2></a>
<a href="#part2"><h2>Частина 2</h2></a>
<h1 id="part1">Частина 1</h1>
<p>Багато тексту</p>
<h1 id="part2">Частина 2</h1>
<p>Багато тексту</p>
<h1 id="part3">Частина 3</h1>
<p>Багато тексту</p>
</body>
</html>
</syntaxhighlight>
Коли ми робимо гіперпереходи в межах одної сторінки, то в атрибуті href просто пишемо знак шарпа (“#”), і назву закладки (те що написано в атрибуті id). А коли робимо перехід на закладку в іншій сторінці, то спочатку пишемо адресу сторінки, потім додаємо знак шарпа і закладку. Коли випадково робиться перехід на закладку якої не існує, нічого страшного не відбувається. Ми просто попадаємо на початок сторінки, як при звичайному переході.
<blockquote>''Взагалі то w3cschools писали про атрибут name, але крім того вони писали, що скоро цей атрибут буде відкинуто і замінено на id. Тому думаю краще використовувати новіший, і вдвічі коротший варіант. А чим коротша сторінка, тим швидше вона завантажиться :)''</blockquote>
Найчастіше сторінки завантажуються в тому вікні, де ви клацнули посилання. Але ми можемо вибрати місце де будуть завантажуватись сторінки. Для цього в тезі <nowiki><a></nowiki> існує атрибут target. Він може приймати значення _blank якщо нам потрібно завантажувати сторінку в новому вікні, _self, якщо нам нічого міняти не потрібно (воно і так завантажується в тому вікні де клацнули), _parent, якщо ми хочемо забрати з вікна фрейми, і відкрити сторінку на все вікно.
== Елементи оформлення ==
=== Підведемо риску ===
Інколи ви щось пишете, пишете, і раптом відчуваєте, що потрібно підвести риску.
----
Робиться це просто як новий рядок: <nowiki><hr /></nowiki> (horisontal ruler). Взагалі то в цього тегу є атрибути які настроюють зовнішній вигляд, але їх використання в нових стандартах небажане. Дозволені тільки загальні атрибути, такі як id, class, style і атрибути подій, але це теми наступного розділу.
=== Картинки ===
До цього моменту ми прочитали дуже багато тексту про текст. Звісно – текст найважливіша частина будь-якої сторінки (якщо звісно це не сторінка якої небудь галереї), але суцільний текст штука доволі нудна. Ілюстрований текст виглядає набагато краще. Щоб вставити в текст зображення використовують тег <nowiki><img></nowiki>. Його атрибут src, задає джерело (source) – файл в якому міститься картинка. Цей тег одинарний, що означає, що коли ми пишемо код, який відповідає найновішим стандартам, його потрібно закінчувати так: />.
Інколи картинки не відображаються. Це відбувається з різних причин. Тим не менш, потрібно щоб користувач і в таких випадках знав, що ви хотіли йому показати. Для цього картинки мають атрибут alt. Він задає текст, який буде відображатись на місці картинки, в тих випадках, коли сама картинка недоступна.
<blockquote>''Не варто забувати про те, що картинки дуже довго завантажуються при повільному доступі до інтернету. Та навіть коли доступ в інтернет достатньо швидкий, деякі користувачі виключають завантаження картинок з метою економії. І це зауваження актуальне навіть в 2011 році. Тому не нехтуйте атрибутом alt.''</blockquote>
Також ми можемо змінити розміри картинки. Наприклад, якщо ми маємо маленьке зображення, ми можемо його розтягнути. Щоправда тоді воно буде відображатись дещо розмито. Також можна змінювати розміри зображення разом зі зміною розмірів вікна браузера. Для цього розміри вказують у відсотках. Розміри задаються атрибутами width і height. Приклад:
<syntaxhighlight lang="html4strict">
<html>
<head><title>Картинки</title></head>
<body>
<img src="image.jpg" alt="Маленька картинка" title="Маленька картинка" width="100" height="100"/><br/>
<img src="image.jpg" alt="Велика картинка" title="Велика картинка" width="400" height="400"/><br/>
<img src="image.jpg" alt="Широка картинка" title="Широка картинка" width="100%" height="400"/><br/>
</body>
</html>
</syntaxhighlight>
Картинки можуть бути поміщені всередині тегів гіперпосилання, тоді клацання по них буде аналогічним до клацання по звичайних посиланнях. Навколо картинки з’явиться синя рамка. Але є ще цікавіший спосіб зробити з картинки гіперпосилання…
=== Карти ===
Зображення можна поділити на області різної форми, кожна з яких може посилатися в інше місце. Для цього за допомогою тегу <nowiki><map></nowiki> задають карту. Атрибут id, який ідентифікує карту, використовується для зв’язку з малюнком. Щоб малюнок призначити в якості карти, потрібно в атрибуті usemap малюнка написати ідентифікатор карти, яку використовує малюнок. Всередині тегу карти містяться теги областей, які задаються тегами <nowiki><area></nowiki>. Знову ж таки, цей тег одинарний і хоче щоб його правильно закривали. Атрибут href задає адресу посилання, атрибут nohref, якщо призначити йому значення true, виключає зону з карти. Атрибут shape задає форму області: rect – прямокутна, circle – круг, і poly для багатокутника.
<syntaxhighlight lang="html4strict">
<img src="planets.gif" width="145" height="126" usemap="#planetmap">
<map id="planetmap" name="planetmap">
<area shape="rect" coords="0,0,82,126" alt="Sun" href="sun.htm">
<area shape="circle" coords="90,58,3" alt="Mercury" href="mercur.htm">
<area shape="circle" coords="124,58,8" alt="Venus" href="venus.htm">
</map>
</syntaxhighlight>
Приклад безсовісно свиснуто [http://www.w3schools.com/html/tryit.asp?filename=tryhtml_areamap звідси]. Дуже хороше місце, щоб потренуватись, без зайвої мороки.
Форму задають за допомогою атрибуту coords, який містить чотири координати (ліво, верх, право, низ) для прямокутника, три (координати центра і радіус) для кола, і парну кількість для багатокутника (координати кожної вершини). Координати можна дізнатись багатьма способами. Можна в графічному редакторі подивитись. А якщо форма складна, точок багато, то можна і спеціальну програму використати. Щось подібне до [http://www.carlosag.net/Tools/XMap/ X-Map]. Хоча, якщо чесно, ні цією програмою, ні картами я не користувався. Але якщо таке є, то треба давати можливість людям знати. Інакше книжка якась не солідна буде.
== Подання інформації структуровано ==
Ми вже вміємо оформлювати текст в абзаци, заголовки, розділи, сторінки. Але текст може утворювати і складніші структури, які покращують оформлення і розуміння тексту. Люди більше люблять, коли їм показують таблиці і списки, аніж просто набір абзаців (звісно крім художньої літератури). Тому зараз поговоримо про:
=== Списки ===
Списки в HTML бувають трьох видів: упорядковані (ordered list) <nowiki><ol></nowiki>, невпорядковані (unordered list) <nowiki><ul></nowiki>, і списки означень (definition list) <nowiki><dl></nowiki>. Елементи двох перших списків задаються тегом <nowiki><li></nowiki> (list item). Елементом списку може бути будь-який текст, картинки, абзаци, і навіть інші списки. Наприклад, впорядкований список задають так:
<syntaxhighlight lang="html">
<ol>
<li>Раз</li>
<li>Два</li>
<li>Три</li>
</ol>
</syntaxhighlight>
Виглядає це так:
# Раз
# Два
# Три
Список означень складніший, але не набагато. В ньому є два види елементів – термін (dl term) <nowiki><dt></nowiki>, де записують термін, який будуть означати, і після нього означення (dl definition), в тегах <nowiki><dd></nowiki>.
=== Таблиці ===
Таблиці зручно задавати за допомогою HTML, бо в HTML можна робити вкладені елементи. Таблиця також складається з вкладених елементів. Таблиця (<nowiki><table></nowiki>) складається з рядків (<nowiki><tr></nowiki> – table row), кожен з яких також складається з клітинок (<nowiki><td></nowiki> – table data). А всередині клітинки може бути вже все що завгодно. Навіть ще одна таблиця. Виглядає це так:
{|border=1
|-
|Рядок 1 Стовпець 1 || Рядок 1 Стовпець 2 || Рядок 1 Стовпець 3
|-
|Рядок 2 Стовпець 1 || Рядок 2 Стовпець 2 || Рядок 2 Стовпець 3
|-
|Рядок 3 Стовпець 1 || Рядок 3 Стовпець 2 || Рядок 3 Стовпець 3
|}
<syntaxhighlight lang="html4strict">
<table border="1">
<tr>
<td>Рядок 1 Стовпець 1</td>
<td>Рядок 1 Стовпець 2</td>
<td>Рядок 1 Стовпець 3</td>
</tr>
<tr>
<td>Рядок 2 Стовпець 1</td>
<td>Рядок 2 Стовпець 2</td>
<td>Рядок 2 Стовпець 3</td>
</tr>
<tr>
<td>Рядок 3 Стовпець 1</td>
<td>Рядок 3 Стовпець 2</td>
<td>Рядок 3 Стовпець 3</td>
</tr>
</table>
</syntaxhighlight>
По замовчуванню таблиці відображаються без меж :) . Тобто межі невидимі. Це іноді корисно, але іноді ми хочемо, щоб межі було видно. Для цього задають значення атрибуту <code>border</code>. Він задає товщину меж таблиці, правда тільки зовнішніх меж. Якщо його значення нуль, то межі не відображається.
Інколи треба назвати стовпці чи рядки, тоді використовують клітинку заголовку. Для цього замість тегу <nowiki><td></nowiki> пишуть <nowiki><th></nowiki>. Виглядає це так:
{|border=1
|-
! !! Стовпець 1 !! Стовпець 2
|-
!Рядок 1
| Рядок 1 Стовпець 1
| Рядок 1 Стовпець 2
|-
!Рядок 2
| Рядок 2 Стовпець 1
| Рядок 2 Стовпець 2
|}
А пишеться отак:
<syntaxhighlight lang="html4strict">
<table border="1">
<tr><td></td><th>Стовпець 1</th><th>Стовпець 2</th></tr>
<tr><th>Рядок 1</th><td>Рядок 1 Стовпець 1</td><td>Рядок 1 Стовпець 2</td></tr>
<tr><th>Рядок 2</th><td>Рядок 2 Стовпець 1</td><td>Рядок 2 Стовпець 2</td></tr>
</table>
</syntaxhighlight>
Варто зауважити, що такий спосіб кращий аніж писати вміст клітинки в тегах <nowiki><b></nowiki> чи <nowiki><strong></nowiki>. І не тільки тому, що так коротше. А і тому, що потім можна буде застосувати до заголовків таблиці окремі стилі.
Деякі браузери не відображають порожні клітинки (тобто не обводять їх рамкою). Можете подивитись що робить ваш, в попередньому прикладі верхня ліва клітинка порожня. Щоб обдурити браузер і змусити його відображати клітинку так ніби там щось є, ми можемо покласти туди невидимий символ – . Це символ незламного пропуску :) (Non Breakable SPace). Назвали його незламним, тому що слова розділені таким пропуском переносяться на наступний рядок тільки разом.
Клітинки таблиці можна об'єднувати. Робиться це за допомогою атрибутів colspan і rowspan тегу <nowiki><td></nowiki>. colspan вказує на скільки колонок буде пролягати дана клітинка, а rowspan на скільки рядків. Такий код:
<syntaxhighlight lang="html4strict">
<table border="1">
<tr><td colspan="2">Рядок 1 Стовпець 1 простягяється на два вправо</td><td>Рядок 1 Стовпець 3</td></tr>
<tr><td>Рядок 2 Стовпець 1</td><td rowspan="3">Рядок 2 Стовпець 2 простягяється на 2 вниз</td><td>Рядок 2 Стовпець 3</td></tr>
<tr><td>Рядок 3 Стовпець 1</td><td>Рядок 3 Стовпець 3</td></tr>
</table>
</syntaxhighlight>
Дає такий результат:
<table border="1">
<tr><td colspan="2">Рядок 1 Стовпець 1 простягяється на два вправо</td><td>Рядок 1 Стовпець 3</td></tr>
<tr><td>Рядок 2 Стовпець 1</td><td rowspan="3">Рядок 2 Стовпець 2 простягяється на 2 вниз</td><td>Рядок 2 Стовпець 3</td></tr>
<tr><td>Рядок 3 Стовпець 1</td><td>Рядок 3 Стовпець 3</td></tr>
</table>
Крім рядків таблиця може мати заголовок. Тег <nowiki><caption></nowiki> призначений для створення заголовка до таблиці і може розміщуватись тільки в середині тега <table>, причому зразу після відкриваючого тега. Такий заголовок представляє собою текст по замовчуванню відображений перед таблицею і описує її.
Також можна виділити рядки таблиці в групи з різним функціональним призначенням і призначити їм різні стилі. Ой як мені не терпиться вже дійти до стилів. Але по порядку. Можна виділити заголовочну частину <nowiki><thead></nowiki>, основну частину <nowiki><tbody></nowiki> і підсумок <nowiki><tfoot></nowiki>.
== Посилання ==
* http://bunyk.wordpress.com/2009/04/25/html-tutorial/
[[Категорія:Мови розмітки]]
[[Категорія:Мови програмування]]
{{Стадія|50%}}
ac7zupar1iou3z7u2494gusft4emcoz
Пориньте у Python 3
0
3277
36867
36828
2022-08-03T18:41:10Z
Володимир Груша
985
wikitext
text/x-wiki
Пориньте у Python 3 ({{lang-en|Dive into Python 3}}) [[w:Марк Пілігрим|Марка Пілігрима]] розповідає про Python 3 та його відмінності від попередньої версії.
Англійський текст знаходиться за адресою http://www.diveintopython3.net
[[Python|<== Інші підручники мови Python]]
== Зміст ==
[[Файл:Ballpython020.jpg|500px|right|Шшшш... Мову назвали не на мою честь? Кого це хвилює?]]
# [[Файл:75%.svg]] [[Пориньте у Python 3/Що нового?|Що нового в "Пориньте у Python 3"?]]
# [[Файл:75%.svg]] [[Пориньте у Python 3/Встановлення|Встановлення]]
# [[Файл:75%.svg]] [[Пориньте у Python 3/Ваша перша програма|Ваша перша програма]]
# [[Файл:75%.svg]] [[Пориньте у Python 3/Стандартні типи даних|Стандартні типи даних]]
# [[Файл:75%.svg]] [[Пориньте у Python 3/Вирази над структурами|Вирази над структурами]]
# [[Файл:75%.svg]] [[Пориньте у Python 3/Текст|Текст]]
# [[Файл:75%.svg]] [[Пориньте у Python 3/Регулярні вирази|Регулярні вирази]]
# [[Файл:75%.svg]] [[Пориньте у Python 3/Замикання та генератори|Замикання та генератори]]
# [[Файл:75%.svg]] [[Пориньте у Python 3/Класи та ітератори|Класи та ітератори]]
# [[Файл:75%.svg]] [[Пориньте у Python 3/Детальніше про ітератори|Детальніше про ітератори]]
# [[Файл:75%.svg]] [[Пориньте у Python 3/Модульне тестування|Модульне тестування]]
# [[Файл:75%.svg]] [[Пориньте у Python 3/Рефакторинг|Рефакторинг]]
# [[Файл:75%.svg]] [[Пориньте у Python 3/Файли|Файли]]
# [[Файл:75%.svg]] [[Пориньте у Python 3/XML|XML]]
# [[Файл:75%.svg]] [[Пориньте у Python 3/Серіалізація об'єктів|Серіалізація об'єктів]]
# [[Файл:75%.svg]] [[Пориньте у Python 3/Веб-сервіси HTTP|Веб-сервіси HTTP]]
# [[Файл:75%.svg]] [[Пориньте у Python 3/Приклад: Перенесення chardet на Python 3|Приклад: Перенесення chardet на Python 3]]
# [[Файл:75%.svg]] [[Пориньте у Python 3/Пакування бібліотек|Пакування бібліотек]]
# [[Файл:75%.svg]] [[Пориньте у Python 3/Імена магічних методів|Імена магічних методів]]
# [[Файл:75%.svg]] [[Пориньте у Python 3/Що читати далі?|Що читати далі?]]
Позначення прогресу роботи над перекладом, для кожного розділу:
* Роботу почато (0%): [[Файл:00%.svg]],
* Робота в розпалі (25%): [[Файл:25%.png]],
* Робота наближається до завершення (50%): [[Файл:50%.png]],
* Залишились дрібниці (вичитка, вичистка, оформлення) (75%): [[Файл:75%.png]],
* Готово (100%): [[Файл:100 percent.svg]]
{{Стадія|100%}}
[[Категорія:Python]]
[[Категорія:Пориньте у Python 3]]
[[Категорія:Мови програмування]]
9tffts6bc6ymez998e8lmm5lbn2yuma
Чисельні методи. Лабораторний практикум
0
3338
36875
34840
2022-08-03T19:02:30Z
Володимир Груша
985
wikitext
text/x-wiki
{{Примітка версії для друку}}
Даний підручник буде містити набір лабораторних робіт з чисельних методів, та поради з їх виконання. Код в основному буде написаний мовою [[Python]], але можливо пізніше додати і інші версії.
== Зміст ==
[[File:Himmelblau function.svg|200px|right]]
#[[Чисельні методи. Лабораторний практикум/Мета, методи, та вимоги виконання лаболаторних робіт|Мета, методи, та вимоги виконання лаболаторних робіт]]
#[[Чисельні методи. Лабораторний практикум/Розв'язування нелінійних алгебраїчних рівнянь|Розв'язування нелінійних алгебраїчних рівнянь]]
#[[Чисельні методи. Лабораторний практикум/Розв'язування систем лінійних алгебраїчних рівнянь|Розв'язування систем лінійних алгебраїчних рівнянь]]
#[[Чисельні методи. Лабораторний практикум/Інтерполювання функцій|Інтерполювання функцій]]
#[[Чисельні методи. Лабораторний практикум/Проблеми власних значень|Проблеми власних значень]]
#[[Чисельні методи. Лабораторний практикум/Чисельне інтегрування|Чисельне інтегрування]]
#[[Чисельні методи. Лабораторний практикум/Чисельне диференціювання|Чисельне диференціювання]]
#[[Чисельні методи. Лабораторний практикум/Коротка довідка по MatPlotLib|Коротка довідка по MatPlotLib]]
#[[Чисельні методи. Лабораторний практикум/Коротка довідка з NumPy|Коротка довідка з NumPy]]
== Посилання ==
#[http://cybportal.univ.kiev.ua/wiki/%D0%A7%D0%9C Чисельні методи на CybWiki]
[[Категорія:Чисельні методи. Лабораторний практикум]]
[[Категорія:Інформатика]]
{{Стадія|50%}}
jbeynfzzgaezr4qze4and4p1ktvhanw
Освоюємо Java
0
3521
36855
36851
2022-08-03T12:05:07Z
Володимир Груша
985
/* Детальний зміст */
wikitext
text/x-wiki
<div class="infobox" style="float:right; font-size:85%; line-height:130%">
{{Java/Chapters}}
</div>
'''Java''' (вимовляється Джава; у нас інколи Ява) — об'єктно-орієнтована мова програмування, випущена компанією Sun Microsystems у 1995 році як основний компонент платформи Java. Синтаксис мови багато в чому походить від C та C++. Java програми виконуються у середовищі віртуальної машини Java. Java програми компілюються у байткод, який при виконанні інтерпретується віртуальною машиною для конкретної платформи. В 2009 році Sun Microsystems придбала компанія Oracle, яка продовжує розвивати "Джава".
Даний підручник орієнтований на вивчення Java як людьми з мінімальним рівнем знання програмування, так і людей - які хочуть покращити свої знання з певних нюансів мови.
Долучайтесь до доповнення та виправлення даного підручника. детальніше на сторінці [[Обговорення:Освоюємо Java|обговорення]]).
Якщо знайшли помилку або неточність, будь ласка виправте її, або напишіть про неї на сторінці [[Обговорення:Освоюємо Java|обговорення]].
Деякі нюанси мови java, які не включені у підручник, винесено в [[Освоюємо Java/ЧаП|ЧаП]]
Рівень готовності розділів, позначено відповідним квадратиком: [[Файл:00%.svg]] [[Файл:25%.svg]] [[Файл:50%.svg]] [[Файл:75%.svg]] [[Файл:100 percent.svg]]
<br clear="left">
== Детальний зміст ==
<div class="references-small" style="-moz-column-count:2; column-count:2; -webkit-column-count:2;">
# [[Освоюємо Java/Загальний огляд та історія Java|Загальний огляд та історія Java]] [[Файл:75%.png]]
# [[Освоюємо Java/Встановлення і налаштування середовища розробки|Встановлення і налаштування середовища розробки]] [[Файл:100%.png]]
#* [[Освоюємо Java/Встановлення і налаштування середовища розробки#JDK та його встановлення|JDK та його встановлення]]
#* [[Освоюємо Java/Встановлення і налаштування середовища розробки#Привіт світе!|Привіт світе!]]
#* [[Освоюємо Java/Встановлення і налаштування середовища розробки#Середовище розробки|Середовище розробки]]
#* [[Освоюємо Java/Встановлення і налаштування середовища розробки#Документація|Документація]]
#[[Освоюємо Java/Основи|Основи]] [[Файл:100%.png]]
#*[[Освоюємо Java/Основи#Коментарі|Коментарі]]
#*[[Освоюємо Java/Основи#Типи даних|Типи даних]]
#*[[Освоюємо Java/Основи#Змінні|Змінні]]
#*[[Освоюємо Java/Основи#Оператори|Оператори]]
# [[Освоюємо Java/Вступ в класи та методи|Вступ в класи та методи]] [[Файл:100 percent.svg]]
#*[[Освоюємо Java/Вступ в класи та методи#Класи|Класи]]
#*[[Освоюємо Java/Вступ в класи та методи#Методи|Методи]]
#*[[Освоюємо Java/Вступ в класи та методи#Конструктори|Конструктори]]
# [[Освоюємо Java/Керування порядком виконання|Керування порядком виконання]] [[Файл:100 percent.svg]]
#*[[Освоюємо Java/Керування порядком виконання#Блоки|Блоки]]
#*[[Освоюємо Java/Керування порядком виконання#Умовні інструкції|Умовні інструкції]]
#*[[Освоюємо Java/Керування порядком виконання#Цикли|Цикли]]
#**[[Освоюємо Java/Керування порядком виконання#Цикл while|Цикл while]]
#**[[Освоюємо Java/Керування порядком виконання#Цикл do/while|Цикл do/while]]
#**[[Освоюємо Java/Керування порядком виконання#Цикл з лічильником for|Цикл з лічильником for]]
#**[[Освоюємо Java/Керування порядком виконання#Цикл «for each»|Цикл «for each»]]
#* [[Освоюємо Java/Керування порядком виконання#Інструкції, що порушують порядок виконання|Інструкції, що порушують порядок виконання]]
#* [[Освоюємо Java/Керування порядком виконання#Множинний вибір (switch)|Множинний вибір (switch)]]
# [[Освоюємо Java/Масиви|Масиви]] [[Файл:100 percent.svg]]
#* [[Освоюємо Java/Масиви#Одновимірні масиви|Одновимірні масиви]]
#* [[Освоюємо Java/Масиви#Багатовимірні масиви|Багатовимірні масиви]]
# [[Освоюємо Java/Рядки|Рядки]] [[Файл:100%.png]]
#* [[Освоюємо Java/Рядки#Спецсимволи|Спецсимволи]]
#* [[Освоюємо Java/Рядки#Конкатенація|Конкатенація]]
#* [[Освоюємо Java/Рядки#Робота з рядками|Робота з рядками]]
#* [[Освоюємо Java/Рядки#Підрядки|Підрядки]]
#* [[Освоюємо Java/Рядки#Порівняння рядків|Порівняння рядків]]
#* [[Освоюємо Java/Рядки#Приведення до типу|Приведення до типу]]
#* [[Освоюємо Java/Рядки#Кодові точки та кодові одиниці|Кодові точки та кодові одиниці]]
#* [[Освоюємо Java/Рядки#String API|String API]]
#* [[Освоюємо Java/Рядки#StringBuilder|StringBuilder]]
# [[Освоюємо Java/Методи|Методи]] [[Файл:100%.png]]
#* [[Освоюємо Java/Методи#Перевантаження методів|Перевантаження методів]]
#* [[Освоюємо Java/Методи#Заміщення методів|Заміщення методів]]
# [[Освоюємо Java/Об'єкти і класи|Об'єкти і класи]] [[Файл:75%.png]]
#* [[Освоюємо Java/Об'єкти і класи#Парадигма ООП|Парадигма ООП]]
#* [[Освоюємо Java/Об'єкти і класи#Об'єкти та об'єктні змінні|Об'єкти та об'єктні змінні]]
#* [[Освоюємо Java/Об'єкти і класи#Пакети|Пакети]]
#* [[Освоюємо Java/Об'єкти і класи#Інкапсуляція|Інкапсуляція]]
#* [[Освоюємо Java/Об'єкти і класи#Успадкування|Успадкування]]
#* [[Освоюємо Java/Об'єкти і класи#Поліморфізм|Поліморфізм]]
#* [[Освоюємо Java/Об'єкти і класи#Абстрактні класи|Абстрактні класи]]
#* [[Освоюємо Java/Об'єкти і класи#Інтерфейси|Інтерфейси]]
# [[Освоюємо Java/Винятки|Винятки]] [[Файл:75%.png]]
#* Винятки в java
#* Типи винятків
#* Конструкція try
#* Throw
#* Throws
# [[Освоюємо Java/Графічний інтерфейс користувача|Графічний інтерфейс користувача]] [[Файл:50%.png]]
#* Робота з графікою (Swing та AWT)
#** Створення фреймів (вікон)
#** Робота з фреймами
#* Обробка подій
# [[Освоюємо Java/Аплети|Аплети]] [[Файл:100%.png]]
# [[Освоюємо Java/Колекції|Колекції]] [[Файл:50%.png]]
#* [[Освоюємо Java/Колекції#Реалізації інтерфейсу Collection|Інтерфейс Collection]]
#** [[Освоюємо Java/Колекції#Клас ArrayList та використання ітератора|Клас ArrayList]]
#** [[Освоюємо Java/Колекції#Клас LinkedList|Клас LinkedList]]
#** [[Освоюємо Java/Колекції#Клас HashSet|Клас HashSet]]
#** [[Освоюємо Java/Колекції#Клас LinkedHashSet|Клас LinkedHashSet]]
#** [[Освоюємо Java/Колекції#Клас TreeSet|Клас TreeSet]]
#** [[Освоюємо Java/Колекції#Клас PriorityQueue|Клас PriorityQueue]]
#** [[Освоюємо Java/Колекції#Клас ArrayDeque|Клас ArrayDeque]]
#* [[Освоюємо Java/Колекції#Інтерфейс Map та класи, що його реалізують|Інтерфейс Map]]
#** [[Освоюємо Java/Колекції#Клас HashMap|Клас HashMap]]
#** [[Освоюємо Java/Колекції#Клас TreeMap|Клас TreeMap]]
# [[Освоюємо Java/Менеджери розташування|Менеджери розташування]] [[Файл:100%.png]]
#* [[Освоюємо Java/Менеджери розташування#FlowLayout|FlowLayout]]
#* [[Освоюємо Java/Менеджери розташування#BorderLayout|BorderLayout]]
#* [[Освоюємо Java/Менеджери розташування#GridLayout|GridLayout]]
#* [[Освоюємо Java/Менеджери розташування#BoxLayout|BoxLayout]]
#* [[Освоюємо Java/Менеджери розташування#CardLayout|CardLayout]]
#* [[Освоюємо Java/Менеджери розташування#GridBagLayout|GridBagLayout]]
#* [[Освоюємо Java/Менеджери розташування#Абсолютне позиціонування|Абсолютне позиціонування]]
# [[Освоюємо Java/Графічні компоненти Swing|Графічні компоненти Swing]] [[Файл:25%.png]]
# [[Освоюємо Java/Потоки вводу-виводу|Потоки вводу/виводу]] [[Файл:25%.svg]]
# [[Освоюємо Java/Узагальнення|Узагальнення]] [[Файл:25%.png]]
# [[Освоюємо Java/Паралелізм|Паралелізм]] [[Файл:00%.png]]
# Серіалізація [[Файл:00%.png]]
</div>
'''Література'''
* Програмування мовою Java / Олексій Васильєв. - Навчальна книга Богдан. 2020. 696 с.
* Core Java. Volume I, Fundamentals (11th edition) / Cay S. Horstmann. — Pearson. 2018
* Java: The Complete Reference, Eleventh Edition /Herbert Schildt. - Oracle Press. 2019. - 1871 p.
* Learning Java 5th Edition/ Marc Loy, Patrick Niemeyer, Daniel Leuck. - O'Reilly Media. 2020 - 1248 p.
'''Корисні лінки'''
* [http://easy-code.com.ua/2011/04/visim-mifiv-pro-java/ Вісім міфів про Java //EasyCode - статті, що стосуються програмування українською]
* [http://leepoint.net/notes-java/index.html Java Notes - детальний англомовний ресурс]
* [http://ukrtechlibrary.wordpress.com/category/%d0%bf%d1%80%d0%be%d0%b3%d1%80%d0%b0%d0%bc%d1%83%d0%b2%d0%b0%d0%bd%d0%bd%d1%8f/java/ Підручники Java українською]
* [http://www.java2s.com/ Приклади програм та документація по Java. (англ)]
* [http://ukr-technologies.blogspot.com/ Матеріали по Java]
* [ftp://inethub.olvi.net.ua/pub/KPI/Selena/Method/1%20course/Object-Oriented%20Analysis%20and%20Programming/Labs_ua/Index.htm Основи програмування та алгоритмічні мови]
* [http://idndist.lp.edu.ua/moodle/library/books/0021/index_.html Об'єктно-орієнтоване програмування в Java (курс лекцій)]
* [https://www.youtube.com/watch?v=RfVNoetxxHA&list=PLxxPga8YS0l7Bory4_a9RHhg7NAQiCyrq Відеоуроки Java українською//Віртуальна Академія]
* [https://java.happycodings.com/ Java Programming Example Codes]
'''Дивіться також на Вікіпідручнику'''
* [[Функціональне програмування на Java]]
* [[Веб-програмування на Java]]
[[Категорія:Освоюємо Java]]
[[Категорія:Java]]
[[Категорія:Мови програмування]]
[[Категорія:Підручники, близькі до завершення]]
[[cs:Kurz programování v Javě]]
[[de:Java Standard]]
[[en:Java Programming]]
[[es:Programación en Java]]
[[fr:Programmation Java]]
[[it:Java]]
[[hu:Java Programozás]]
[[ka:Java]]
[[nl:Programmeren in Java]]
[[pl:Java]]
[[pt:Java]]
[[ru:Java]]
awyo2exrp04xlbmh0feup3ndo6fn3ab
36858
36855
2022-08-03T17:46:03Z
Володимир Груша
985
/* Детальний зміст */
wikitext
text/x-wiki
<div class="infobox" style="float:right; font-size:85%; line-height:130%">
{{Java/Chapters}}
</div>
'''Java''' (вимовляється Джава; у нас інколи Ява) — об'єктно-орієнтована мова програмування, випущена компанією Sun Microsystems у 1995 році як основний компонент платформи Java. Синтаксис мови багато в чому походить від C та C++. Java програми виконуються у середовищі віртуальної машини Java. Java програми компілюються у байткод, який при виконанні інтерпретується віртуальною машиною для конкретної платформи. В 2009 році Sun Microsystems придбала компанія Oracle, яка продовжує розвивати "Джава".
Даний підручник орієнтований на вивчення Java як людьми з мінімальним рівнем знання програмування, так і людей - які хочуть покращити свої знання з певних нюансів мови.
Долучайтесь до доповнення та виправлення даного підручника. детальніше на сторінці [[Обговорення:Освоюємо Java|обговорення]]).
Якщо знайшли помилку або неточність, будь ласка виправте її, або напишіть про неї на сторінці [[Обговорення:Освоюємо Java|обговорення]].
Деякі нюанси мови java, які не включені у підручник, винесено в [[Освоюємо Java/ЧаП|ЧаП]]
Рівень готовності розділів, позначено відповідним квадратиком: [[Файл:00%.svg]] [[Файл:25%.svg]] [[Файл:50%.svg]] [[Файл:75%.svg]] [[Файл:100 percent.svg]]
<br clear="left">
== Детальний зміст ==
<div class="references-small" style="-moz-column-count:2; column-count:2; -webkit-column-count:2;">
# [[Освоюємо Java/Загальний огляд та історія Java|Загальний огляд та історія Java]] [[Файл:75%.png]]
# [[Освоюємо Java/Встановлення і налаштування середовища розробки|Встановлення і налаштування середовища розробки]] [[Файл:100%.png]]
#* [[Освоюємо Java/Встановлення і налаштування середовища розробки#JDK та його встановлення|JDK та його встановлення]]
#* [[Освоюємо Java/Встановлення і налаштування середовища розробки#Привіт світе!|Привіт світе!]]
#* [[Освоюємо Java/Встановлення і налаштування середовища розробки#Середовище розробки|Середовище розробки]]
#* [[Освоюємо Java/Встановлення і налаштування середовища розробки#Документація|Документація]]
#[[Освоюємо Java/Основи|Основи]] [[Файл:100%.png]]
#*[[Освоюємо Java/Основи#Коментарі|Коментарі]]
#*[[Освоюємо Java/Основи#Типи даних|Типи даних]]
#*[[Освоюємо Java/Основи#Змінні|Змінні]]
#*[[Освоюємо Java/Основи#Оператори|Оператори]]
# [[Освоюємо Java/Вступ в класи та методи|Вступ в класи та методи]] [[Файл:100 percent.svg]]
#*[[Освоюємо Java/Вступ в класи та методи#Класи|Класи]]
#*[[Освоюємо Java/Вступ в класи та методи#Методи|Методи]]
#*[[Освоюємо Java/Вступ в класи та методи#Конструктори|Конструктори]]
# [[Освоюємо Java/Керування порядком виконання|Керування порядком виконання]] [[Файл:100 percent.svg]]
#*[[Освоюємо Java/Керування порядком виконання#Блоки|Блоки]]
#*[[Освоюємо Java/Керування порядком виконання#Умовні інструкції|Умовні інструкції]]
#*[[Освоюємо Java/Керування порядком виконання#Цикли|Цикли]]
#**[[Освоюємо Java/Керування порядком виконання#Цикл while|Цикл while]]
#**[[Освоюємо Java/Керування порядком виконання#Цикл do/while|Цикл do/while]]
#**[[Освоюємо Java/Керування порядком виконання#Цикл з лічильником for|Цикл з лічильником for]]
#**[[Освоюємо Java/Керування порядком виконання#Цикл «for each»|Цикл «for each»]]
#* [[Освоюємо Java/Керування порядком виконання#Інструкції, що порушують порядок виконання|Інструкції, що порушують порядок виконання]]
#* [[Освоюємо Java/Керування порядком виконання#Множинний вибір (switch)|Множинний вибір (switch)]]
# [[Освоюємо Java/Масиви|Масиви]] [[Файл:100 percent.svg]]
#* [[Освоюємо Java/Масиви#Одновимірні масиви|Одновимірні масиви]]
#* [[Освоюємо Java/Масиви#Багатовимірні масиви|Багатовимірні масиви]]
# [[Освоюємо Java/Рядки|Рядки]] [[Файл:100%.png]]
#* [[Освоюємо Java/Рядки#Спецсимволи|Спецсимволи]]
#* [[Освоюємо Java/Рядки#Конкатенація|Конкатенація]]
#* [[Освоюємо Java/Рядки#Робота з рядками|Робота з рядками]]
#* [[Освоюємо Java/Рядки#Підрядки|Підрядки]]
#* [[Освоюємо Java/Рядки#Порівняння рядків|Порівняння рядків]]
#* [[Освоюємо Java/Рядки#Приведення до типу|Приведення до типу]]
#* [[Освоюємо Java/Рядки#Кодові точки та кодові одиниці|Кодові точки та кодові одиниці]]
#* [[Освоюємо Java/Рядки#String API|String API]]
#* [[Освоюємо Java/Рядки#StringBuilder|StringBuilder]]
# [[Освоюємо Java/Методи|Методи]] [[Файл:100%.png]]
#* [[Освоюємо Java/Методи#Перевантаження методів|Перевантаження методів]]
#* [[Освоюємо Java/Методи#Заміщення методів|Заміщення методів]]
# [[Освоюємо Java/Об'єкти і класи|Об'єкти і класи]] [[Файл:75%.png]]
#* [[Освоюємо Java/Об'єкти і класи#Парадигма ООП|Парадигма ООП]]
#* [[Освоюємо Java/Об'єкти і класи#Об'єкти та об'єктні змінні|Об'єкти та об'єктні змінні]]
#* [[Освоюємо Java/Об'єкти і класи#Пакети|Пакети]]
#* [[Освоюємо Java/Об'єкти і класи#Інкапсуляція|Інкапсуляція]]
#* [[Освоюємо Java/Об'єкти і класи#Успадкування|Успадкування]]
#* [[Освоюємо Java/Об'єкти і класи#Поліморфізм|Поліморфізм]]
#* [[Освоюємо Java/Об'єкти і класи#Абстрактні класи|Абстрактні класи]]
#* [[Освоюємо Java/Об'єкти і класи#Інтерфейси|Інтерфейси]]
# [[Освоюємо Java/Винятки|Винятки]] [[Файл:75%.png]]
#* Винятки в java
#* Типи винятків
#* Конструкція try
#* Throw
#* Throws
# [[Освоюємо Java/Графічний інтерфейс користувача|Графічний інтерфейс користувача]] [[Файл:50%.png]]
#* Робота з графікою (Swing та AWT)
#** Створення фреймів (вікон)
#** Робота з фреймами
#* Обробка подій
# [[Освоюємо Java/Аплети|Аплети]] [[Файл:100%.png]]
# [[Освоюємо Java/Колекції|Колекції]] [[Файл:50%.png]]
#* [[Освоюємо Java/Колекції#Реалізації інтерфейсу Collection|Інтерфейс Collection]]
#** [[Освоюємо Java/Колекції#Клас ArrayList та використання ітератора|Клас ArrayList]]
#** [[Освоюємо Java/Колекції#Клас LinkedList|Клас LinkedList]]
#** [[Освоюємо Java/Колекції#Клас HashSet|Клас HashSet]]
#** [[Освоюємо Java/Колекції#Клас LinkedHashSet|Клас LinkedHashSet]]
#** [[Освоюємо Java/Колекції#Клас TreeSet|Клас TreeSet]]
#** [[Освоюємо Java/Колекції#Клас PriorityQueue|Клас PriorityQueue]]
#** [[Освоюємо Java/Колекції#Клас ArrayDeque|Клас ArrayDeque]]
#* [[Освоюємо Java/Колекції#Інтерфейс Map та класи, що його реалізують|Інтерфейс Map]]
#** [[Освоюємо Java/Колекції#Клас HashMap|Клас HashMap]]
#** [[Освоюємо Java/Колекції#Клас TreeMap|Клас TreeMap]]
#** [[Освоюємо Java/Колекції#Клас LinkedHashMap|Клас LinkedHashMap]]
# [[Освоюємо Java/Менеджери розташування|Менеджери розташування]] [[Файл:100%.png]]
#* [[Освоюємо Java/Менеджери розташування#FlowLayout|FlowLayout]]
#* [[Освоюємо Java/Менеджери розташування#BorderLayout|BorderLayout]]
#* [[Освоюємо Java/Менеджери розташування#GridLayout|GridLayout]]
#* [[Освоюємо Java/Менеджери розташування#BoxLayout|BoxLayout]]
#* [[Освоюємо Java/Менеджери розташування#CardLayout|CardLayout]]
#* [[Освоюємо Java/Менеджери розташування#GridBagLayout|GridBagLayout]]
#* [[Освоюємо Java/Менеджери розташування#Абсолютне позиціонування|Абсолютне позиціонування]]
# [[Освоюємо Java/Графічні компоненти Swing|Графічні компоненти Swing]] [[Файл:25%.png]]
# [[Освоюємо Java/Потоки вводу-виводу|Потоки вводу/виводу]] [[Файл:25%.svg]]
# [[Освоюємо Java/Узагальнення|Узагальнення]] [[Файл:25%.png]]
# [[Освоюємо Java/Паралелізм|Паралелізм]] [[Файл:00%.png]]
# Серіалізація [[Файл:00%.png]]
</div>
'''Література'''
* Програмування мовою Java / Олексій Васильєв. - Навчальна книга Богдан. 2020. 696 с.
* Core Java. Volume I, Fundamentals (11th edition) / Cay S. Horstmann. — Pearson. 2018
* Java: The Complete Reference, Eleventh Edition /Herbert Schildt. - Oracle Press. 2019. - 1871 p.
* Learning Java 5th Edition/ Marc Loy, Patrick Niemeyer, Daniel Leuck. - O'Reilly Media. 2020 - 1248 p.
'''Корисні лінки'''
* [http://easy-code.com.ua/2011/04/visim-mifiv-pro-java/ Вісім міфів про Java //EasyCode - статті, що стосуються програмування українською]
* [http://leepoint.net/notes-java/index.html Java Notes - детальний англомовний ресурс]
* [http://ukrtechlibrary.wordpress.com/category/%d0%bf%d1%80%d0%be%d0%b3%d1%80%d0%b0%d0%bc%d1%83%d0%b2%d0%b0%d0%bd%d0%bd%d1%8f/java/ Підручники Java українською]
* [http://www.java2s.com/ Приклади програм та документація по Java. (англ)]
* [http://ukr-technologies.blogspot.com/ Матеріали по Java]
* [ftp://inethub.olvi.net.ua/pub/KPI/Selena/Method/1%20course/Object-Oriented%20Analysis%20and%20Programming/Labs_ua/Index.htm Основи програмування та алгоритмічні мови]
* [http://idndist.lp.edu.ua/moodle/library/books/0021/index_.html Об'єктно-орієнтоване програмування в Java (курс лекцій)]
* [https://www.youtube.com/watch?v=RfVNoetxxHA&list=PLxxPga8YS0l7Bory4_a9RHhg7NAQiCyrq Відеоуроки Java українською//Віртуальна Академія]
* [https://java.happycodings.com/ Java Programming Example Codes]
'''Дивіться також на Вікіпідручнику'''
* [[Функціональне програмування на Java]]
* [[Веб-програмування на Java]]
[[Категорія:Освоюємо Java]]
[[Категорія:Java]]
[[Категорія:Мови програмування]]
[[Категорія:Підручники, близькі до завершення]]
[[cs:Kurz programování v Javě]]
[[de:Java Standard]]
[[en:Java Programming]]
[[es:Programación en Java]]
[[fr:Programmation Java]]
[[it:Java]]
[[hu:Java Programozás]]
[[ka:Java]]
[[nl:Programmeren in Java]]
[[pl:Java]]
[[pt:Java]]
[[ru:Java]]
5emsrx0pf9f59urq4ievgchuhdduhuf
36862
36858
2022-08-03T18:10:33Z
Володимир Груша
985
/* Детальний зміст */
wikitext
text/x-wiki
<div class="infobox" style="float:right; font-size:85%; line-height:130%">
{{Java/Chapters}}
</div>
'''Java''' (вимовляється Джава; у нас інколи Ява) — об'єктно-орієнтована мова програмування, випущена компанією Sun Microsystems у 1995 році як основний компонент платформи Java. Синтаксис мови багато в чому походить від C та C++. Java програми виконуються у середовищі віртуальної машини Java. Java програми компілюються у байткод, який при виконанні інтерпретується віртуальною машиною для конкретної платформи. В 2009 році Sun Microsystems придбала компанія Oracle, яка продовжує розвивати "Джава".
Даний підручник орієнтований на вивчення Java як людьми з мінімальним рівнем знання програмування, так і людей - які хочуть покращити свої знання з певних нюансів мови.
Долучайтесь до доповнення та виправлення даного підручника. детальніше на сторінці [[Обговорення:Освоюємо Java|обговорення]]).
Якщо знайшли помилку або неточність, будь ласка виправте її, або напишіть про неї на сторінці [[Обговорення:Освоюємо Java|обговорення]].
Деякі нюанси мови java, які не включені у підручник, винесено в [[Освоюємо Java/ЧаП|ЧаП]]
Рівень готовності розділів, позначено відповідним квадратиком: [[Файл:00%.svg]] [[Файл:25%.svg]] [[Файл:50%.svg]] [[Файл:75%.svg]] [[Файл:100 percent.svg]]
<br clear="left">
== Детальний зміст ==
<div class="references-small" style="-moz-column-count:2; column-count:2; -webkit-column-count:2;">
# [[Освоюємо Java/Загальний огляд та історія Java|Загальний огляд та історія Java]] [[Файл:75%.png]]
# [[Освоюємо Java/Встановлення і налаштування середовища розробки|Встановлення і налаштування середовища розробки]] [[Файл:100%.png]]
#* [[Освоюємо Java/Встановлення і налаштування середовища розробки#JDK та його встановлення|JDK та його встановлення]]
#* [[Освоюємо Java/Встановлення і налаштування середовища розробки#Привіт світе!|Привіт світе!]]
#* [[Освоюємо Java/Встановлення і налаштування середовища розробки#Середовище розробки|Середовище розробки]]
#* [[Освоюємо Java/Встановлення і налаштування середовища розробки#Документація|Документація]]
#[[Освоюємо Java/Основи|Основи]] [[Файл:100%.png]]
#*[[Освоюємо Java/Основи#Коментарі|Коментарі]]
#*[[Освоюємо Java/Основи#Типи даних|Типи даних]]
#*[[Освоюємо Java/Основи#Змінні|Змінні]]
#*[[Освоюємо Java/Основи#Оператори|Оператори]]
# [[Освоюємо Java/Вступ в класи та методи|Вступ в класи та методи]] [[Файл:100 percent.svg]]
#*[[Освоюємо Java/Вступ в класи та методи#Класи|Класи]]
#*[[Освоюємо Java/Вступ в класи та методи#Методи|Методи]]
#*[[Освоюємо Java/Вступ в класи та методи#Конструктори|Конструктори]]
# [[Освоюємо Java/Керування порядком виконання|Керування порядком виконання]] [[Файл:100 percent.svg]]
#*[[Освоюємо Java/Керування порядком виконання#Блоки|Блоки]]
#*[[Освоюємо Java/Керування порядком виконання#Умовні інструкції|Умовні інструкції]]
#*[[Освоюємо Java/Керування порядком виконання#Цикли|Цикли]]
#**[[Освоюємо Java/Керування порядком виконання#Цикл while|Цикл while]]
#**[[Освоюємо Java/Керування порядком виконання#Цикл do/while|Цикл do/while]]
#**[[Освоюємо Java/Керування порядком виконання#Цикл з лічильником for|Цикл з лічильником for]]
#**[[Освоюємо Java/Керування порядком виконання#Цикл «for each»|Цикл «for each»]]
#* [[Освоюємо Java/Керування порядком виконання#Інструкції, що порушують порядок виконання|Інструкції, що порушують порядок виконання]]
#* [[Освоюємо Java/Керування порядком виконання#Множинний вибір (switch)|Множинний вибір (switch)]]
# [[Освоюємо Java/Масиви|Масиви]] [[Файл:100 percent.svg]]
#* [[Освоюємо Java/Масиви#Одновимірні масиви|Одновимірні масиви]]
#* [[Освоюємо Java/Масиви#Багатовимірні масиви|Багатовимірні масиви]]
# [[Освоюємо Java/Рядки|Рядки]] [[Файл:100%.png]]
#* [[Освоюємо Java/Рядки#Спецсимволи|Спецсимволи]]
#* [[Освоюємо Java/Рядки#Конкатенація|Конкатенація]]
#* [[Освоюємо Java/Рядки#Робота з рядками|Робота з рядками]]
#* [[Освоюємо Java/Рядки#Підрядки|Підрядки]]
#* [[Освоюємо Java/Рядки#Порівняння рядків|Порівняння рядків]]
#* [[Освоюємо Java/Рядки#Приведення до типу|Приведення до типу]]
#* [[Освоюємо Java/Рядки#Кодові точки та кодові одиниці|Кодові точки та кодові одиниці]]
#* [[Освоюємо Java/Рядки#String API|String API]]
#* [[Освоюємо Java/Рядки#StringBuilder|StringBuilder]]
# [[Освоюємо Java/Методи|Методи]] [[Файл:100%.png]]
#* [[Освоюємо Java/Методи#Перевантаження методів|Перевантаження методів]]
#* [[Освоюємо Java/Методи#Заміщення методів|Заміщення методів]]
# [[Освоюємо Java/Об'єкти і класи|Об'єкти і класи]] [[Файл:75%.png]]
#* [[Освоюємо Java/Об'єкти і класи#Парадигма ООП|Парадигма ООП]]
#* [[Освоюємо Java/Об'єкти і класи#Об'єкти та об'єктні змінні|Об'єкти та об'єктні змінні]]
#* [[Освоюємо Java/Об'єкти і класи#Пакети|Пакети]]
#* [[Освоюємо Java/Об'єкти і класи#Інкапсуляція|Інкапсуляція]]
#* [[Освоюємо Java/Об'єкти і класи#Успадкування|Успадкування]]
#* [[Освоюємо Java/Об'єкти і класи#Поліморфізм|Поліморфізм]]
#* [[Освоюємо Java/Об'єкти і класи#Абстрактні класи|Абстрактні класи]]
#* [[Освоюємо Java/Об'єкти і класи#Інтерфейси|Інтерфейси]]
# [[Освоюємо Java/Винятки|Винятки]] [[Файл:75%.png]]
#* Винятки в java
#* Типи винятків
#* Конструкція try
#* Throw
#* Throws
# [[Освоюємо Java/Графічний інтерфейс користувача|Графічний інтерфейс користувача]] [[Файл:50%.png]]
#* Робота з графікою (Swing та AWT)
#** Створення фреймів (вікон)
#** Робота з фреймами
#* Обробка подій
# [[Освоюємо Java/Аплети|Аплети]] [[Файл:100%.png]]
# [[Освоюємо Java/Колекції|Колекції]] [[Файл:50%.png]]
#* [[Освоюємо Java/Колекції#Реалізації інтерфейсу Collection|Інтерфейс Collection]]
#** [[Освоюємо Java/Колекції#Клас ArrayList та використання ітератора|Клас ArrayList]]
#** [[Освоюємо Java/Колекції#Клас LinkedList|Клас LinkedList]]
#** [[Освоюємо Java/Колекції#Клас HashSet|Клас HashSet]]
#** [[Освоюємо Java/Колекції#Клас LinkedHashSet|Клас LinkedHashSet]]
#** [[Освоюємо Java/Колекції#Клас TreeSet|Клас TreeSet]]
#** [[Освоюємо Java/Колекції#Клас PriorityQueue|Клас PriorityQueue]]
#** [[Освоюємо Java/Колекції#Клас ArrayDeque|Клас ArrayDeque]]
#* [[Освоюємо Java/Колекції#Інтерфейс Map та класи, що його реалізують|Інтерфейс Map]]
#** [[Освоюємо Java/Колекції#Клас HashMap|Клас HashMap]]
#** [[Освоюємо Java/Колекції#Клас TreeMap|Клас TreeMap]]
#** [[Освоюємо Java/Колекції#Клас LinkedHashMap|Клас LinkedHashMap]]
# [[Освоюємо Java/Менеджери розташування|Менеджери розташування]] [[Файл:100%.png]]
#* [[Освоюємо Java/Менеджери розташування#FlowLayout|FlowLayout]]
#* [[Освоюємо Java/Менеджери розташування#BorderLayout|BorderLayout]]
#* [[Освоюємо Java/Менеджери розташування#GridLayout|GridLayout]]
#* [[Освоюємо Java/Менеджери розташування#BoxLayout|BoxLayout]]
#* [[Освоюємо Java/Менеджери розташування#CardLayout|CardLayout]]
#* [[Освоюємо Java/Менеджери розташування#GridBagLayout|GridBagLayout]]
#* [[Освоюємо Java/Менеджери розташування#Абсолютне позиціонування|Абсолютне позиціонування]]
# [[Освоюємо Java/Графічні компоненти Swing|Графічні компоненти Swing]] [[Файл:25%.png]]
# [[Освоюємо Java/Потоки вводу-виводу|Потоки вводу/виводу]] [[Файл:25%.svg]]
# [[Освоюємо Java/Узагальнення|Узагальнення]] [[Файл:25%.png]]
# [[Освоюємо Java/Паралелізм|Паралелізм]] [[Файл:00%.png]]
# Серіалізація [[Файл:00%.png]]
# Лямда-вирази [[Файл:00%.png]]
</div>
'''Література'''
* Програмування мовою Java / Олексій Васильєв. - Навчальна книга Богдан. 2020. 696 с.
* Core Java. Volume I, Fundamentals (11th edition) / Cay S. Horstmann. — Pearson. 2018
* Java: The Complete Reference, Eleventh Edition /Herbert Schildt. - Oracle Press. 2019. - 1871 p.
* Learning Java 5th Edition/ Marc Loy, Patrick Niemeyer, Daniel Leuck. - O'Reilly Media. 2020 - 1248 p.
'''Корисні лінки'''
* [http://easy-code.com.ua/2011/04/visim-mifiv-pro-java/ Вісім міфів про Java //EasyCode - статті, що стосуються програмування українською]
* [http://leepoint.net/notes-java/index.html Java Notes - детальний англомовний ресурс]
* [http://ukrtechlibrary.wordpress.com/category/%d0%bf%d1%80%d0%be%d0%b3%d1%80%d0%b0%d0%bc%d1%83%d0%b2%d0%b0%d0%bd%d0%bd%d1%8f/java/ Підручники Java українською]
* [http://www.java2s.com/ Приклади програм та документація по Java. (англ)]
* [http://ukr-technologies.blogspot.com/ Матеріали по Java]
* [ftp://inethub.olvi.net.ua/pub/KPI/Selena/Method/1%20course/Object-Oriented%20Analysis%20and%20Programming/Labs_ua/Index.htm Основи програмування та алгоритмічні мови]
* [http://idndist.lp.edu.ua/moodle/library/books/0021/index_.html Об'єктно-орієнтоване програмування в Java (курс лекцій)]
* [https://www.youtube.com/watch?v=RfVNoetxxHA&list=PLxxPga8YS0l7Bory4_a9RHhg7NAQiCyrq Відеоуроки Java українською//Віртуальна Академія]
* [https://java.happycodings.com/ Java Programming Example Codes]
'''Дивіться також на Вікіпідручнику'''
* [[Функціональне програмування на Java]]
* [[Веб-програмування на Java]]
[[Категорія:Освоюємо Java]]
[[Категорія:Java]]
[[Категорія:Мови програмування]]
[[Категорія:Підручники, близькі до завершення]]
[[cs:Kurz programování v Javě]]
[[de:Java Standard]]
[[en:Java Programming]]
[[es:Programación en Java]]
[[fr:Programmation Java]]
[[it:Java]]
[[hu:Java Programozás]]
[[ka:Java]]
[[nl:Programmeren in Java]]
[[pl:Java]]
[[pt:Java]]
[[ru:Java]]
9m9j48azwps77evp5kbdk8jzhdyxqd8
Scala
0
3548
36876
36443
2022-08-03T19:03:23Z
Володимир Груша
985
wikitext
text/x-wiki
[[File:Scala-full-color.svg|right]]
[[:w:Scala_(мова_програмування)|Scala]] — мультипарадигмова мова програмування, що поєднує властивості об'єктно-орієнтованого та функційного програмування.
*[[Scala/Установлення|Установлення]]
==Мова==
* [[Scala/Coursera|Конспект Coursera]]
*[[Scala/Привіт, світ!|Привіт, світ!]]
*[[Scala/Змінні|Змінні]]
*[[Scala/Методи|Методи]]
*[[Scala/Ітерація|Ітерація]]
*[[Scala/Функції|Функції]]
*[[Scala/Класи і об'єкти|Класи і об'єкти]]
*[[Scala/Основні типи|Основні типи]]
*[[Scala/Поліморфізм конструктора типу|Поліморфізм конструктора типу]]
*[[Scala/Рівні доступу|Рівні доступу]]
*[[Scala/Колекції|Колекції]]
==Бібліотеки/Утиліти==
*[[Ammonite]]
*[[Sbt|Sbt - simple-build-tool]]
*[[Scala/Тестування]]
*[[Scala/Робота з базами даних]]
*[[Scala/Web Frameworks and Application stacks]]
**[[Lift]]
*[[Scala/Desktop UI]]
*[[Scala/Паралельність]]
*[[Scala/Обчислення]]
*[[Scala/Графіка]]
== Посилання ==
*[[Scala/Література|Література]]
[[Категорія:Мови програмування]]
[[Категорія:Scala|*]]
{{Стадія|25%}}
iemm27s5jgd06rdobz6uvx42x6zqjqd
CSS
0
3871
36877
30936
2022-08-03T19:04:10Z
Володимир Груша
985
wikitext
text/x-wiki
Даний підручник спробує навчити вас використовувати каскадні таблиці стилів — важливий елемент веб-дизайну. Перед його прочитанням бажано мати певне уявлення про [[HTML]].
'''Каскадні таблиці стилів''' (англ. Cascading Style Sheets) — спеціальна мова, що використовується для запису оформлення сторінок, написаних мовами розмітки даних.
== Основні поняття ==
Таблиці стилів дають змогу спростити процес створення сторінок і поліпшити їхній зовнішній вигляд. Концепція стилів подібна до ідеї стилів, яка реалізована в сучасних текстових редакторах — текст спочатку вводять, а потім форматують, користуючись стилями. Застосування стилів дає змогу вводити на сторінку потрібні тексти та інші елементи, не задумуючись над їхнім зовнішнім виглядом і розташуванням.
Таблиці стилів програміст зазвичай створює окремо від html-файлу. Під час створення html-файлу він концентрує увагу на змісті сторінки, а не на її зовнішньому вигляді, а під час створення таблиці стилів — навпаки. Отже, стилі дають змогу розмежувати етапи створення html-файлу й удосконалення зовнішнього вигляду сторінки.
Вважатимемо, що таблиця стилів уже створена. Тепер нам потрібно забезпечити взаємодію таблиці з html-файлом. Розглянемо три способи такої взаємодії: зв'язування, імпортування, вбудовування.
=== Зв'язування ===
Таблицю стилів створюють і зберігають в окремому файлі з розширенням ".css". Таку таблицю називають зовнішньою. Щоб зв'язати основний файл з таблицею стилів, у середині тега <nowiki><head></nowiki> застосовують одинарний тег <nowiki><link></nowiki> з інформацією про таблицю:
<syntaxhighlight lang="html4strict">
<head>
<link href="адреса таблиці стилів"
type="text/css"
rel="stylesheet"
title="назва таблиці стилів">
</head>
</syntaxhighlight>
=== Імпортування ===
Це те ж саме, що і зв'язування, але взаємодію файлів забезпечують засобами тегу <nowiki><style></nowiki> і команди @import URL("адреса таблиці стилів")
=== Вбудовування ===
Якщо таблицю створено лише для деякого конкретного html-файлу, то її розташовують у цьому файлі за допомогою контейнера <nowiki><style></nowiki>. Таку
таблицю стилів називають внутрішньою або вбудованою.
Також стиль можна вбудувати прямо в html-тег за допомогою атрибуту style, наприклад:
<syntaxhighlight lang="html4strict">
<span style="color: red">RED</span>
</syntaxhighlight>
Це дасть нам блок з текстом червоного кольору: <span style="color: red">RED</span>
== Мова CSS ==
Таблиця стилів складається з правил, а правило — з назви тега чи списку назв тегів і описів стилів, які діятимуть у межах деякого html-файлу.
Опис стилю — це послідовність пар властивість:значення, які записують через крапку з комою та охоплюють фігурними дужками.
Отже, загальний вигляд правила такий:
<syntaxhighlight lang="html4strict">
Селектор {
властивість1: значення1;
властивість2: значення2;
властивістьN: значенняN;
}
</syntaxhighlight>
Приклад правила для одного тега:
<syntaxhighlight lang="html4strict">
p {
color: red;
}
</syntaxhighlight>
Браузер виводить на екрані тексти всіх абзаців червоним кольором.
Ось приклад складнішого правила для списку тегів:
<syntaxhighlight lang="html4strict">
h3,li {
color: green;
font-family: pragmatica;
font-size: 16pt;
text-align: left;
border-style: ridge;
border-width: 2mm;
}
</syntaxhighlight>
Браузер виведе всі заголовки третього рівня h3 і елементи списків li зеленим кольором, шрифтом Прагматика розміру 16 пунктів, вирівняє їх до лівого краю вікна й охопить рамкою товщиною 2 мм з видавленим контуром (ridge).
== Властивості стилів та їх значення ==
Імена властивостей складаются з одного чи декількох англійських слів, що записуются через риску. Властивість діє лише в межах тега, зазначеного у відповідному правилі.
Властивості стилів наведені у таблиці:
{|class="wikitable"
|-
!Властивість !! Значення !!Пояснення
|-
|background-attachment || fixed, scroll || Тло фіксоване чи прокручуєтся
|-
|background-color || red, green, #343434 || Колір тла
|-
|background-image || url("Адреса графічного файлу для тла") || Фонове зображення
|-
|background-position || 0% 0% || Початкове положення тла
|-
|background-repeat || repeat, repeat-x, repeat-y, no-repeat || Повторює зображення
|-
|border-top/border-right/border-bottom/border-left/border || 4mm || Рамка
|-
|border-color || red, green, #343434 || Колір рамки
|-
|border-style || none, dotted, dashed, solid, double, groove, ridge, inset, outset || Стиль рамки
|-
|border-width || 2mm, 3mm || Товщина рамки
|-
|font-family || arial, sans-serif || Назва шрифта
|-
|font-size || 16px || Розмір шрифта
|-
|font-style || normal, italic, oblique || Стиль шрифта
|-
|font-variant || normal, small-caps || Варіант шрифта
|-
|font-weight || normal(400), bold(700), bolder, lighter, 100 - 900 || Жирність шрифта
|-
|word-spacing || 1mm, 2mm || Відстань між словами
|-
|letter-spacing || 1mm || Відстань між символами
|-
|line-height || 2mm, 4mm || Відстань між рядками
|-
|text-align || left, right, center, justify || Вирівнювання тексту
|-
|text-decoration || none, underline, blink, overline, line-through || Оформлення тексту
|-
|text-indent || 2cm || Абзацний відступ
|-
|text-transform || none, uppercase, lowercase, capitalize || Трансформація тексту
|-
|vertical-align || baseline, sub, super, top, text-top, middle, bottom, text-bottom || Вертикальне вирівнювання
|-
|white-space || normal, pre, nowrap, pre-wrap, pre-line || Пробіли та перенесення між словами
|-
|margin-top/margin-right/margin-bottom/margin-left/margin || 4mm || Зовнішній відступ
|-
|padding-top/padding-right/padding-bottom/padding-left/padding || 4mm || Внутрішній відступ
|-
|height|| 4cm || Висота елемента
|-
|width || 14cm || Ширина елемента
|-
|float || none, left, right || Обтікання об'єкта текстом
|-
|clear || none, left, right, both || Заборона обтікання
|-
|color || red, green, #343434 || Колір елемента
|-
|list-style-image || url("Адреса графічного файлу маркера списку") || Зображення для маркера
|-
|list-style-position || inside, outside || Позиція маркера
|-
|list-style-type || disc, circle, square, decimal, lower-alpha, lower-roman, upper-alpha, upper-roman || Вигляд маркера
|-
|position || static, relative, absolute, fixed || Спосіб позиціонування елемента
|-
|top/right/bottom/left || px, in, pt, %, auto тощо || Позиціонування елемента
|-
|z-index || ціле число, auto || Положення елемента за віссю z
|-
|display || block, inline-block, inline, list-item, none, table, table-row, table-cell || Поведінка елемента в документі
|-
|visibility || visible, hidden, collapse || Відобразити чи сховати елемент
|-
|overflow || visible, hidden, scroll, auto || Спосіб відображення вмісту елемента, якщо він повністю не вміщується в задану область
|-
|clip || shape(rect), auto || Визначає прямокутну область, де буде показано частину елемента
|-
|outline-color/outline-style/outline-width/outline || значення, аналогічні border || Зовнішня рамка
|-
|cursor || default, pointer, help, wait, progress, text, move, crosshair, auto || Вигляд курсору
|}
== Теги <nowiki><style>,<div>,<span></nowiki> ==
Внутрішні таблиці стилів описують у головному файлі в контейнері тега <nowiki><head>...</head></nowiki> за допомогою тега-контейнера <nowiki><style>...</style></nowiki>.
Правила можуть починатися або з назви тега без кутових дужок, або з деякого слова користувача, перед яким є крапка. Це слово стає назвою типу, який можна застосувати в контейнері тега <nowiki><BODY></nowiki> до іншого текстового блока, фрагмена тексту чи деякого елемента, наприклад:
<syntaxhighlight lang="html4strict">
.mystyle1 {
color: red;
font-size: 40pt;
margin-top: 30px;
}
.mystyle2 {
color: black;
font-size: 16pt;
margin-top: -50px;
}
</syntaxhighlight>
Для відокремлення текстового блока, до якого застосовуватимуть стиль, призначений тег-контейнер <nowiki><DIV параметр></DIV></nowiki> з
параметром <nowiki>CLASS</nowiki>, який задає конкретний стиль, що діятиме на блок: <nowiki><DIV CLASS=назва стилю>блок</DIV></nowiki>.
Для відокремлення у блоці текстового фрагмента, для якого будуть переозначувати стиль, застосовують тег-контейнер <nowiki><SPAN>...</SPAN>
</nowiki>
== Селектори CSS ==
=== Селектор class ===
Припустимо, ми хочемо зробити сторінку, на якій буде два види абзаців <nowiki><p></nowiki>, причому обидва види будуть постійно чергуватися і часто повторюватися. Приклад такої сторінки — інтерв'ю, в якому чергуются питання журналіста і відповіді людини. Звичайно, при створені такої сторінки ми захочемо візуально відділити питання і відповіді одне від одного. Якщо б нам необхідно було це робити можливостями CSS, які ми розглянули вище, то ми мали б створити дві різні таблиці стилів. На щастя, це нам не потрібно. Ми можемо створити в одній таблиці стилів два різних класи абзаців за допомогою селектора класу. Це буде виглядати так:
<syntaxhighlight lang="html4strict">
<html>
<head>
...
<style>
...
p.ask {
font-style: italic;
font-weight: bold;
font-family: Arial, sans-serif;
font-size: 10pt;
color: gray;
margin-left: 15px;
}
p.answer {
font-family: 'Times New Roman', serif;
font-size: 12pt;
color: black;
}
...
</style>
...
</head>
<body>
...
<p class="ask">Питання журналіста</p>
<p class="answer">Відповідь</p>
...
</body>
</html>
</syntaxhighlight>
В наведеному прикладі питання журналіста будуть відображатися шрифтом Arial сірого кольору, напівжирним курсивом, розміром 10 пунктів з відступом 15 пікселів від лівого краю сторінки. Відповіді ж будуть відображені шрифтом Times New Roman розміром 12 пунктів чорного кольору. Ви можете створювати будь-яку кількість класів для будь-яких елементів сторінки.
=== Селектор id ===
Візьмемо наступний приклад. Наприклад, ви хочете створити на сторінці які-небудь унікальні предмети, до яких в майбутньому хочете звертатись за допомогою [[w:JavaScript|JavaScript]]. Можливо, ці елементи будуть повторюватися на інших сторінках, і ви хотіли б задати їм єдине оформлення за допомогою CSS. На цей випадок в таблицях стилів є можливість присвоєння унікальним елементам ідентифікаторів (id). Ось приклад призначення ідентифікатора і правил CSS таким елементам:
<syntaxhighlight lang="html4strict">
<html>
<head>
...
<style>
...
input#green {
color: green;
}
input#red {
color: red;
}
...
</style>
...
</head>
<body>
...
<form ...>
<p>Текст, введений в це поле, буде відображений зеленим кольором:
<input type="text" id="green" name="info1" size="20"></p>
<p>Текст, введений в це поле, буде відображений червоним кольором:
<input type="text" id="red" name="info2" size="20"></p>
</form>
...
</body>
</html>
</syntaxhighlight>
Аналогічним чином унікальні ідентифікатори можуть бути призначені будь-якій кількості будь-яких елементів на сторінці.
[[Категорія:Мови розмітки]]
[[Категорія:Мови програмування]]
{{Стадія|25%}}
ffihk85086zk83xc3k67xu7153eybab
Розробка програм для Windows Phone
0
4601
36879
34971
2022-08-03T19:06:21Z
Володимир Груша
985
wikitext
text/x-wiki
[[Файл:Windows-phone-7-games.jpg|350px|безрамки|праворуч]]
Платформа Windows Phone дозволяє розробникам проявити свою творчість у створенні застосувань для Windows® Phone. Вона побудована на основі існуючих інструментів Microsoft і технологій, таких як Visual Studio, Expression Blend, Silverlight та XNA Framework.
== Огляд ==
Усі програми для Windows Phone 7 пишуться на .NET керованих мовах програмування, таких як [[w:C Sharp|C#]], [[Visual Basic .NET]]...
Для розробки програмного забеспечення доступно два фреймворки:
* '''Silverlight''' для створення інтерактивних застосувань,з можливістю застосування '''XAML'''-розмітки для описання зовнішнього вигляду елементів інтерфейсу.
* Фреймворк '''XNA''' для створення ігор на основі '''DirectX''' технології, що дає змогу отримати досвід розробки захоплюючих і цікавих 2D і 3D ігор та застосувань.
Після виходу версії Windows Phone 7.5, ви можете поєднувати Silverlight та XNA в одному застосуванні для створення зручного інтерфейсу і динамічної графіки.<ref>[http://msdn.microsoft.com/en-us/library/ff402535(v=vs.92).aspx msdn.microsoft.com] Application Platform Overview for Windows Phone</ref>
== Зміст ==
# [[Розробка програм для Windows Phone/Встановлення Windows Phone SDK|Встановлення Windows Phone SDK]]
# [[Розробка програм для Windows Phone/Емулятор Windows Phone|Емулятор Windows Phone]]
# '''Silverlight'''
#* [[Розробка програм для Windows Phone/Створення першої Silverlight програми|Створення першої програми]]
#* [[Розробка програм для Windows Phone/Динамічне розташування компонентів|Динамічне розташування компонентів]]
#* [[Розробка програм для Windows Phone/Навігація (Silverlight)|Навігація]]
# '''XNA'''
#* [[Розробка програм для Windows Phone/Створення першої XNA програми для Windows Phone|Створення першої програми]]
#* [[Розробка програм для Windows Phone/XNA - Робота із сенсорним екраном|Робота із сенсорним екраном]]
# '''Сенсори і сервіси'''
#* [[Розробка програм для Windows Phone/Акселерометр|Акселерометр]]
#* [[Розробка програм для Windows Phone/Географічне положення|Географічне положення]]
== Примітки ==
{{reflist}}
== Література ==
* [http://msdn.microsoft.com/en-us/library/ff402526(v=vs.92).aspx msdn.microsoft.com], How to: Create Your First Windows Phone App
* [http://www.charlespetzold.com/phone/ Programming Windows Phone 7], Charles Petzold
[[Категорія:Розробка програм для Windows Phone]]
[[Категорія:Мови програмування]]
[[Категорія:Програмне забезпечення]]
{{Стадія|25%}}
taesnqf2d3k870yfm80wd1bi34tothq
C Sharp
0
4630
36872
36471
2022-08-03T18:58:48Z
Володимир Груша
985
wikitext
text/x-wiki
{{стадія|25%}}
'''C#''' - це мова програмування створена спеціально для роботи у середовищі Microsoft .NET Framework.
Мова [[w:C Sharp|C#]] була розроблена з урахуванням сильних і слабких особливостей інших мов, зокрема Java і C++. Специфікація мови C# була написана [[w:Андерс Гейлсберг|Андерсом Гейлсбергом]], Скотом Вілтамутом та Пітером Гольде. Андерс Хейлсберг відомий у світі програмування як автор компілятора Turbo Pascal і лідер команди, яка створила Delphi.
Ключові особливості мови C#:
* Компонентна орієнтованість
* Код зібраний воєдино (декларації і реалізації об'єднані разом)
* Уніфікована система типів і їх безпечність
* Автоматична і мануальна робота за пам'яттю
* Використання єдиної бібліотеки класів - CLR
== Зміст ==
# [[w:C Sharp|Загальні відомості]]
# [[C Sharp/Ідентифікатори|Ідентифікатори]]
# [[C Sharp/Типи|Типи]]
# [[C Sharp/Змінні|Змінні]]
# [[C Sharp/Операції|Операції]]
# [[C Sharp/Оператори|Оператори]]
#* [[C Sharp/Оператор if-else|Оператор if-else]]
#* [[C Sharp/Оператор switch|Оператор switch]]
#* [[C Sharp/Цикл while, do-while|Цикл while, do-while]]
#* [[C Sharp/Цикл for|Цикл for]]
#* [[C Sharp/Цикл foreach|Цикл foreach]]
#* [[C Sharp/Оператори переходу|Оператори переходу]]
# [[C Sharp/Простори імен|Простори імен]]
# [[C Sharp/Модифікатори доступу|Модифікатори доступу]]
# [[C Sharp/Структури і класи|Структури і класи]]
# [[C Sharp/Інтерфейси|Інтерфейси]]
# [[C Sharp/Наслідування|Наслідування]]
# [[C Sharp/Масиви|Масиви]]
# [[C Sharp/Перечислення|Перечислення]]
# [[C Sharp/Делегати|Делегати]]
# [[C Sharp/Події|Події]]
# [[C Sharp/Виключні ситуації і блок try...|Виключні ситуації і блок try...]]
# [[C Sharp/Атрибути|Атрибути]]
# [[C Sharp/"Небезпечний" код і вказівники|"Небезпечний" код і вказівники]]
# [[C Sharp/Директиви препроцесору|Директиви препроцесору]]
== Ключові слова C# ==
{{C Sharp/Ключові слова}}
== Література ==
* [http://msdn.microsoft.com msdn.microsoft.com]
* "C# Essentials, 2nd Edition", Ben Albahari, Peter Drayton, Brad Merrill, ISBN: 0-596-00315-3
[[Категорія:Мови програмування]]
[[Категорія:C Sharp]]
{{Стадія|25%}}
ib4oax4evlm69vek8gzend4vhlsiqyr
Освоюємо Java/Потоки вводу-виводу
0
4783
36881
34279
2022-08-03T19:20:35Z
Володимир Груша
985
/* Джерела інформації */
wikitext
text/x-wiki
Доволі часто необхідно здійснювати читання даних із файлів, різноманітних пристроїв, мережевих ресурсів, тощо, все це здійснюється за допомогою '''потоків вводу/виводу'''.
==Концепція потоків вводу/виводу==
Для читання даних із чогось в програмі створюється вхідний потік, для виводу даних кудись - створюється вихідний потік. З практичної точки зору, при об'єктно орієнтованому програмуванні, вам необхідно створити два об'єкти, які уособлюватимуть ці потоки і вказати в кожному з них з чим вони зв'язані (наприклад, задати шлях до файлу, чи ідентифікатор порту комп'ютера, чи мережеву URL адресу і т.п.). Якщо нам потрібно прийняти дані, то використовується один об'єкт, якщо передати дані — звертаємось до іншого об'єкта.
[[Файл:Streams.jpg|center]]
==Ієрархія потоків вводу/виводу==
Класи потоків в Java формують дві ієрархії класів: '''''символьні потоки (Character Streams)''''' та '''''байтові потоки (Byte Streams)'''''. Як зрозуміло з назв, перші потоки орієнтовані на роботу з символами Юнікоду, а інші з послідовностями байт. Практичну будь-яку передачу інформації можна реалізувати за допомогою байтових потоків, проте доволі часто така інформація представляється у вигляді символів, тож для таких даних зручніше використовувати символьні потоки. В java для організації потоків вводу-виводу, програмістам надано біля півсотні класів. Насправді, для створення вводу-виводу достатньо лише кілька класів, проте в залежності від задачі деякі класи реалізовують більш зручні засоби для отримання, передачі і деякої попередньої обробки даних.
(даний пункт незавершений, необхідно зробити схеми ієрарій потоків, то розписати коротко основні класи.)
==Робота з файлами==
===Байтові потоки===
Розглянемо приклад роботи з файлами за допомогою байтових потоків. У нас є два файли, необхідно скопіювати один файл у інший. Для цього ми створюємо два байтові потоки: вхідний потік, через який читатиметься наш файл first.txt і створюємо інший вихідний (output) потік, який записуватиме прочитані дані у second.txt. Для цього будемо використовувати два класи '''FileInputStream''' та '''FileOutputStream'''.
<syntaxhighlight lang="java">
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class CopyBytes {
public static void main(String[] args) throws IOException {
//створюємо об'єктні змінні, які посилатимуться на наші потоки
FileInputStream in = null;
FileOutputStream out = null;
// При помилках читання/запису можуть генеруватися винятки, тож потрібно перехопити їх
// Наприклад, помилка може виникнути, при відсутності файлу first.txt у вказаному місці
try {
// створюємо вхідний і вихідний потік
// файл first.txt повинен вже існувати
// якщо second.txt не буде існувати,
// то буде створений при спробі запису
in = new FileInputStream("d:\\first.txt");
out = new FileOutputStream("d:\\second.txt");
int c;
//Допоки з файлу first.txt не буде прочинато всі байти,
//читаємо байти з файлу first.txt і записуємо даний байт у second.txt
//якщо потік не повертає -1(не досягнено кінець файлу),
//то копіюємо наступний байт
while ((c = in.read()) != -1) {
out.write(c);
}
} finally { //дії коли не знайдено файли
if (in != null) {
in.close();
}
if (out != null) {
out.close();
}
}
}
}
</syntaxhighlight>
Як бачимо алгоритм роботи з файлами доволі простий. Спочатку створюємо вхідний потік, далі створюємо вихідний потік. Читаємо перший байт, першого файлу і записуємо його у другий файл, далі переходимо до наступного байту і так допоки усі байти першого файлу не будуть прочитані. В разі виникнення виняткової ситуації, закриваємо наші потоки, а разом з ними і наші файли(не варто забувати закривати потоки, задля звільнення ресурсів комп'ютера. Необхідно згадати, що при читанні/записі файлу застосовується своєрідний вказівник на вміст файлу(неявно для нас). В даному випадку після кожного прочитаного байту вказівник неявним для нас чином переміщується по вмісту файлу на один байт і т.д.
В даному випадку ми використали низькорівневі байтові потоки. Вони годяться для копіювання даних з одного місця в інший, проте символи можуть представлятися не одним байтом. Тому коли ми захочемо, наприклад, вивести вміст файлу на екран, ми отримаємо проблеми із виводом символів. Так у нашому випадку, якщо файл буде латиницею, то використавши у циклі інструкцію: <syntaxhighlight lang="java">System.out.print(Character.toChars(c));</syntaxhighlight>
ми одержимо текст у читабельному виді. Оскільки в Юнікоді для представлення латиниці достатньо одного байту. Якщо ж файл кирилицею, текст буде виведений карлючками, оскільки робота перетворення байт у символи пройшло не зовсім вірно (кириличні літери представляються двома байтами). Дану проблему можна вирішити кількома способами. Найбільш підковані програмісти можуть спробувати власноруч здійснити перетворення байтів у символи з використанням бітових операцій, проте це дещо незручний спосіб і потрібно враховувати кодування символів. Інший спосіб більш легший: замість того, щоб читати по одному байту, ми можемо прочитати зразу ж увесь вміст файлу у масив і перетворити його у текстовий рядок потрібного кодування:
<syntaxhighlight lang="java">
byte []b=new byte[10000]; // масив для вмісту файлу
int k=in.read(b); // читаємо в масив та отримуємо кількість прочитаних байт
//використовуємо конструктор String,
//який перетворює масив у рядок
//із відповідним кодуванням символів
String s = new String(b, 0, k, "cp1251");
System.out.println(s);
</syntaxhighlight>
Якщо необхідно визначити потрібне кодування, то це можна зробити за допомогою читання відповідних системних властивостей:
<syntaxhighlight lang="java">String encoding= System.getProperty("file.encoding");</syntaxhighlight>
І все ж, коли наперед відомо, що ми працюємо із текстовими файлами, то більш елегантним і простішим рішенням буде використання символьних потоків. Тоді Java візьме на себе правильну роботу із кодуванням символів.
===Символьні потоки===
Наступний приклад вирішує проблему з читанням кирилиці із файлу з наступним її відображенням на екран. На відміну від попереднього прикладу, тепер використовуються символьні потоки, що створюються на основі класів: '''FileReader, FileWriter'''.
<syntaxhighlight lang="java">
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class CopyCharacters {
public static void main(String[] args) throws IOException {
FileReader inputStream = null;
FileWriter outputStream = null;
try {
inputStream = new FileReader("d:\\first.txt");
outputStream = new FileWriter("d:\\second.txt");
int c;
while ((c = inputStream.read()) != -1) {
//посимвольно записуємо у файл і виводимо на екран
outputStream.write(c);
System.out.print(Character.toChars(c));
}
} finally {
if (inputStream != null) {
inputStream.close();
}
if (outputStream != null) {
outputStream.close();
}
}
}
}
</syntaxhighlight>
Як бачимо крім назви класів, на оcнові, яких ми створюємо потоки в коді нічого суттєво більше не змінилося. Нам не потрібно іти на різного роду хитрощі, щоб правильно працювати із символами.
Ось результат по виводу на екран вмісту файлу із прикладу CopyBytes.java(байтові потоки):
<pre>?????? ????, ??????????? ?????!</pre>
а ось при використанні прикладу із CopyCharacters.java(символьні потоки):
<pre>
Привіт тобі, божевільний світе!
</pre>
===Буферизовані потоки===
Читання вмісту файлу по байтах не дуже хороша ідея, якщо файл доволі великий. Адже це зайве навантаження на обчислювальні ресурси комп'ютера. Тому більш кращим варіантом є читання тексту цілими блоками. Наприклад, рядками. Рядки у файлах прийнято завершувати символом нового рядка("\n") та символом переходу на новий рядок("\r"). Може бути присутній як один з цих символів так і обидва ("\r\n"), в залежності від того хто і яким чином створював файл.
Читання блоків файлу відбувається через так звані буферизовані потоки, що працюють через буфер в пам'яті комп'ютера. При читанні даних з файлу, дані передаються в програму коли буфер буде порожнім, при записі у файл буфер спочатку повинен заповнитись. Для буферизованого вводу/виводу існує чотири класи. Для буферизованих байтових потоків: '''BufferedInputStream та BufferedOutputStream'''. Для буферизованих символьних потоків: '''BufferedReader та BufferedWriter'''. Інколи корисно вивільнити дані з буфера до повного його заповнення у окремих критичних точках,це можна зробити з допомогою методу flush.
Далі наведено, дещо модифікований вищенаведений приклад, що використовує буферизовані потоки:
<syntaxhighlight lang="java">
import java.io.FileReader;
import java.io.FileWriter;
import java.io.BufferedReader;
import java.io.PrintWriter;
import java.io.IOException;
public class CopyLines {
public static void main(String[] args) throws IOException {
BufferedReader inputStream = null;
PrintWriter outputStream = null;
try {
inputStream = new BufferedReader(new FileReader("d:\\first.txt"));
outputStream = new PrintWriter(new FileWriter("d:\\second.txt"));
String l;
//тепер читаємо дані цілими рядками
while ((l = inputStream.readLine()) != null) {
outputStream.println(l);
}
} finally {
if (inputStream != null) {
inputStream.close();
}
if (outputStream != null) {
outputStream.close();
}
}
}
}
</syntaxhighlight>
Як бачимо наші буферизовані потоки обгорнули звичайні небуферизовані потоки:
<syntaxhighlight lang="java">
inputStream = new BufferedReader(new FileReader("d:\\first.txt"));
outputStream = new PrintWriter(new FileWriter("d:\\second.txt"));
</syntaxhighlight>
Тепер ми можемо використовувати метод readLine і читати дані з файлу цілими рядками тексту:
<syntaxhighlight lang="java">inputStream.readLine())</syntaxhighlight>
та записувати дані у файл також цілими рядками:
<syntaxhighlight lang="java">outputStream.println(l);</syntaxhighlight>
Деякі потоки можуть обгортати інші потоки не лише заради буферизації.
==Робота з COM-портом==
Інколи постає необхідність роботи з різноманітними пристроями через COM-порт. Для роботи з портом застосовуються звичайні байтові або ж символьні потоки вводу/виводу, проте основна проблема - це необхідність відповідного API пакету Java для роботи з ними. У JDK немає стандартного пакету. Тому необхідно встановити додаткову бібліотеку для роботи з послідовними та паралельними портами. Послідовний (COM-порт) доволі поширений в даний час, багато апаратного обладнання працює на ньому. Навіть в сучасному він використовується доволі часто. Сучасні прилади підключаються до USB, проте в багатьох використовується перехідник USB-COM, що дозволяє розробникам програмного забезпечення працювати з приладом через добре знайомий і легкий інтерфейс RS232 (COM).
Існує декілька java бібліотек для роботи з COM-портом , які побудовані з використанням Native-методів. Свого часу була популярна javax.Comm, її можна використовувати до цих пір, проте в даний час бібліотеку ніхто не підтримує, її розвиток не відбувається. На зміну javax.Comm прийшла інша java бібліотека – RXTX. Методи в RXTX для роботи з COM-портом ідентичні до методів javax.Comm.
Детальніше тут:
* [http://rxtx.qbang.org/wiki/index.php/Main_Page Головна сторінка підтримки проекту RXTX ] (англ)
* [http://ukr-technologies.blogspot.com/2012/10/com-java.html Стаття присвячена роботі з COM-портом] (укр)
==Ком'ютерні мережі==
Передача даних через мережу здійснюється через сокети (Sockets).
(Ще не написано)
==Джерела інформації==
* [http://docs.oracle.com/javase/tutorial/essential/io/streams.html Потоки вводу/виводу. Офіційний оновлюваний посібник Java від Oracle] (англ.)
* [http://enos.itcollege.ee/~jpoial/docs/tutorial/essential/io/overview.html Версія офіційного посібника по Java за 2005 рік (більш ілюстрований)] (англ.)
{{Гортання сторінок|Графічні компоненти Swing|Узагальнення}}
[[Категорія:Освоюємо Java]]
skc2y7ngl1ni15pvdcsz7qwe47ry7xd
PHP
0
4807
36878
34149
2022-08-03T19:05:17Z
Володимир Груша
985
wikitext
text/x-wiki
{{Примітка версії для друку}}
[[File:Webysther 20160423 - Elephpant.svg|250px|без рамки|right]]
'''PHP''' (також може означати філіпінське песо) — популярна мова програмування, хоча й не така страшна, як мова опису шаблонів. На ній написано більшість сайтів інтернету, зокрема наш вікіпідручник, на якому ви це оце читаєте. Тому іноді таки є необхідність її знати. Сподіваємось цей підручник допоможе вам швидко і без зайвої мороки її вивчити.
== Зміст ==
<div style="-moz-column-count:2; column-count:2; -webkit-column-count:2;">
# [[Файл:25%.png]] [[PHP/Введення та основи|Введення, основи синтаксису та типи даних]]
# [[Файл:25%.png]] [[PHP/Змінні, вирази і оператори|Змінні, вирази і оператори]]
# [[Файл:00%.png]] [[PHP/Керуючі конструкції|Керуючі конструкції (розгалудження, цикли)]]
# [[Файл:00%.png]] [[PHP/Масиви|Масиви]]
# [[Файл:00%.png]] [[PHP/Функції|Функції]]
# [[Файл:00%.png]] [[PHP/Форми|HTLM-форми і cookies]]
# [[Файл:00%.png]] [[PHP/Класи і об'єкти|Класи і об'єкти]]
# [[Файл:00%.png]] [[PHP/Помилки|Помилки]]
# [[Файл:00%.png]] [[PHP/Робота з файлами та модулями|Робота з файлами та модулями]]
# [[Файл:00%.png]] [[PHP/PHP і бази даних|PHP і бази даних]]
</div>
=== Позначення ===
Позначення прогресу роботи над главами та розділами:
* [[Файл:00%.svg]] - роботу розпочато (1%),
* [[Файл:25%.png]] - робота в розпалі (25%),
* [[Файл:50%.png]] - найголовніше написано (50%),
* [[Файл:75%.png]] - залишились дрібниці (вичитка, вичистка, оформлення) (75%),
* [[Файл:100 percent.svg]] - роботу завершено (100%).
==Література==
* {{книга |автор = Робін Ніксон
|заголовок = Создаем динамические веб-сайты с помощью PHP, MySQL, JavaScript, CSS и HTML5
|оригінал = Learning PHP, MySQL & JavaScript: With jQuery, CSS & HTML5
|видання = 4 |видавництво = Питер |рік = 2016 |сторінок = 768
|тираж = 1000 |isbn = 978-5-496-02146-3}}
== Посилання ==
* [https://secure.php.net/manual/ru/langref.php php.net] — офіційний довідник мови {{comment|''(рос.)''|документація українською мовою перекладена не повністю}}
* [https://phpbuilder.ru/ua/learn Уроки PHP для початківців]
[[Категорія: Мови програмування]]
[[Категорія:PHP]]
{{Стадія|25%}}
oiia8v30l732ovztk4vnv45yv11m61r
Веб-програмування на Java
0
4965
36863
33589
2022-08-03T18:32:44Z
Володимир Груша
985
wikitext
text/x-wiki
{{Примітка версії для друку}}
Для освоєння матеріалу необхідно ознайомитись з мовою розмітки веб-сторінок HTML та вивчити власне саму мову програмування Java (так зване Java Core - досл. ядро Java). Для цього можете скористатися відповідними вікіпідручниками «[[HTML]]» та «[[Освоюємо Java]]».
Долучайтесь до покращення даного вікіпідручника. Якщо знайдете помилки або ж неточності, виправте їх або напишіть про них на сторінці [[Обговорення:Веб-програмування на Java|обговорення]].
==Вступ==
Мова програмування Java розроблялася як платформа для програмування різноманітних пристроїв. Проте стрімкий розвиток інтернет-технологій змусив творців java працювати і в цьому напрямку. Початково ставка робилася на аплети, проте через певні проблеми ранніх віртуальних машин джави із швидкодією та безпекою, аплети так і не змогли скласти конкуренцію іншим дещо подібним технологіям як то flash. Проблема безпеки аплетів до цих пір актуальна. Компанія Google з 1 вересня 2015 року припинила підтримку плагінів NPAPI, в наслідок чого, плагіни на основі NPAPI (Silverlight, Java-applet и Unity) у Google Chrome працювати не будуть<ref>https://java.com/en/download/faq/chrome.xml Java and Google Chrome Browser </ref>. В 1997 році Sun розпочав роботу над новою інтернет-технологією JSP, а згодом з'явилася і успішно розвивається ціла платформа Java Enterprise Edition (JEE), яка включає цілий ряд технологій для розробки повноцінних серверних інтернет-додатків. В результаті java змогла закріпитися у світі-веб програмування і успішно конкурувати із іншими аналогічними веб-технологіями.
Основною веб-технологій, що базуються на java є серверні сторінки джави (Java Server Pages, JSP) та сервлети (Servlets). Даний вікіпідручник фокусується саме на їх описі.
==Встановлюємо Apache Tomcat==
Для розробки та виконання серверних сторінок Java (JSP) та сервлетів необхідний спеціальний засіб, так званий сервлет контейнер. Існує декілька реалізацій сервлет контейнерів як платних так і безкоштовних. Apache Tomcat безкоштовний контейнер сервлетів розроблений фірмою Apache Software Foundation, яка відома також тим що займається розробкою одного з найпопулярніших веб-серверів Apache.
Процес встановлення Apache Tomcat на вашому локальному комп'ютері доволі простий:
1. Звантажте Tomcat із офіційного сайту [http://tomcat.apache.org/ tomcat.apache.org]. Тут зараз ідеться про встановлення Tomcat 7.
2. Якщо ви звантажили архів, розпакуйте його в каталог, наприклад, у C:\Tomcat7.
3. Запустіть командний рядок і зайдіть у каталог C:\Tomcat7\bin та наберіть:
<pre>
startup
</pre>
Скоріш за все ви отримаєте наступне повідомлення:
<pre>
C:\tomcat7\bin>startup
Neither the JAVA_HOME nor the JRE_HOME environment variable is defined
At least one of these environment variable is needed to run this program
</pre>
Це означає що для запуску потрібно певним чином вказати де встановлено Java (вірніше де встановлено JDK - Java Development Kit). Це можна зробити кількома способами. Можна зайти у змінні середовища і створити змінну JAVA_HOME. Інколи в літературі так і вказують. Проте це не дуже хороший спосіб надіятись на системні змінні і ставити себе в залежність від системи. Найкращий спосіб відредагувати файл catalina.bat.
4. Тож у каталозі C:\tomcat7\bin знайдіть catalina.bat і відредагуйте його. Вписавши наступний рядок:
<pre>
set JAVA_HOME=c:\jdk7
</pre>
Звичайно ж потрібно вказати де у вас знаходиться JDK.
5. Спробуйте знову запустити Apache Tomcat. Повинно вийте, щось на зразок такого:
<pre>
C:\tomcat7\bin>startup
Using CATALINA_BASE: "C:\tomcat7"
Using CATALINA_HOME: "C:\tomcat7"
Using CATALINA_TMPDIR: "C:\tomcat7\temp"
Using JRE_HOME: "c:\jdk7"
Using CLASSPATH: "C:\tomcat7\bin\bootstrap.jar;C:\tomcat7\bin\tomcat-juli.
jar"
C:\tomcat7\bin>catalina.bat
</pre>
Паралельно повинно запуститися консольне вікно із повідомленням що сервер запустився.
6. Щоб перевірити чи дійсно усе працює. Наберіть у браузері:
<pre>
http://localhost:8080/
</pre>
Повинна з'явитися сторінка із привітанням. На даній сторінці можна перейти на сторінку examples (пошукайте відповідне посилання, у tomcat7 воно знаходиться у розділі Developer Quick Start) де можна запустити тестові JSP та сервлети.
7. Щоб зупинити Tomcat наберіть в командному рядку:
<pre>C:\tomcat7\bin>shutdown</pre>
==IDE вам на допомогу==
На відміну від звичайного програмування на java, для написання яких цілком достатньо JDK та блокнота, веб-програмування вимагає дещо більше зусиль. Тому створення серверних сторінок java (JSP) та сервлетів користуючись лише блокнотом може бути довгим та нудним процесом. Передусім тому, що необхідне створення каталогів із певними назвами та деяких конфігураційних файлів в форматі .xml. Багато ранніх книжок розпочиналися з детального опису даних каталогів, їхнього призначення та як писати правильно відповідні .xml файли. Сучасні графічні середовища розробки, дозволяють не так детально вглиблюватися в цю тему і беруть значну кількість рутинної роботи на себе. Зокрема надають зручні графічні форми для редагування файлів конфігурації.
Ви можете вибрати, наприклад, NetBeans або ж Eclipse, або ж інше популярне графічне середовище розробки, яке дозволяє створити заготовку веб-застосунку(web application). В основному після встановлення графічного середовища розробки, все що необхідно від користувача, це вказати IDE де знаходиться Tomcat. Після чого можна працювати. В кожному IDE це робиться по своєму, тому тут не буде наводитися як це робиться. Ви просто можете пошукати відповідний опис в інтернеті чи навіть відповідний відеоурок, яких зараз чимало або ж можете розібратися самі.
==Привіт JSP==
Коли ви користуєтеся браузерами і натискаєте на певному посиланні чи кнопці, ви відправляєте HTTP запит на веб-сервер. Найпростіше, коли ви маєте діло із статичними HTML сторінками, тобто, ті які описані на HTML і ви просто здійснюєте переходи з однієї html сторінки на іншу сторінку. Тоді веб-сервер (що є спеціальною програмою, а в нашому випадку його функції частково виконує Tomcat) вибирає запитану вами сторінку і пересилає її вашому браузеру, який опрацьовує її і виводить вам на екран у читабельному симпатичному вигляді. Інше діло, коли вам потрібно, щоб нова сторінка видала вам щось специфічне, в залежності від того, що ви натиснули. Наприклад, ви вводите прізвище та ім’я, а у відповідь вам необхідно одержати телефон введеної вами особи. Тоді на веб-сервері повинна бути відповідна програма/скрипт, що могла б звернутися до певного файлу чи бази даних, знайшла б необхідний телефон і сформувала б вам відповідну html сторінку із потрібними вам даними. Такі програми можуть писатися на різноманітних мовах веб-програмування. Якщо ви працювали з такими мовами як PHP чи Perl, то дана концепція не буде вам новою. Освоїти JSP та сервлети не складніше за освоєння даних мов, проте потребує попереднього вивчення власне самої Java.
Для реалізації вищенаведеної задачі з допомогою джави, можна скористатися або ж сервлетом або ж серверною сторінкою джави (JSP). Сервлет – це серверна програма написана суто на Java. JSP – це по суті HTML сторінка з розширенням .JSP, де поміж звичайними HTML тегами вставлені ще так звані JSP скриптлети (JSP scriptlets) та спеціальні JSP вирази (JSP expressions). Якщо вам не потрібно робити великих обчислень, то краще створювати JSP. Якщо ж для вашої задачі вам потрібно писати багато коду на Java, то звичайно що простіше зробити це у сервлеті.
Насправді кожна серверна сторінка джави перед виконанням перетворюється у сервлет. Це відбувається при першому зверненні до неї користувача. Здійснює перетворення і компіляцію так званий JSP процесор (JSP engine). При повторному зверненні користувача, зразу ж буде викликатись уже скомпільований сервлет.
''Для прикладу, розробимо веб-прикладення, яке складатиметься з двох сторінок. Першою буде проста сторінка з формою для введення логіна та паролю (index.jsp). При натисненні кнопки «Підтвердити» відбуватиметься запит до іншої сторінки, яка просто виведе введені користувачем логін та пароль (hello.jsp).''
Для початку створіть відповідний проект для вашого веб-прикладення (web application) у вашому інтегрованому середовищі розробки. У NetBeans, наприклад, це робиться через пункт меню File->New Project після чого вибираємо у діалоговому вікні зі списку категорію Java Web та вид проекту Web Application. В результаті введення назви вашого проекту з’явиться ряд каталогів з головним файлом index.jsp. Після деякого редагування це і буде перша наша сторінка. Практично схожим чином діємо і в інших IDE.
Ось перша сторінка:
<syntaxhighlight lang="html4strict">
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>JSP Page</title>
</head>
<body>
<h1>Введіть логін та пароль</h1>
<form name="hello" action="hello.jsp" method="post">
<table border="0">
<tbody>
<tr>
<td>Логін: </td>
<td><input type="text" name="login" value="" size="15" /></td>
</tr>
<tr>
<td>Пароль:</td>
<td><input type="password" name="password" value="" size="15" /><br/></td>
</tr>
<tr>
<td></td>
<td> <input type="submit" value="Підтвердити" name="submit" /><br/></td>
</tr>
</tbody>
</table>
</form>
</body>
</html>
</syntaxhighlight>
Якщо ви знаєте html, то практично усе вам повинно бути зрозумілим. На сторінці присутня форма для створення запиту і в таблиці розміщуються елементи форми: два текстових поля та кнопка.
Лише перший рядок може викликати запитання – це власне і є спеціальне jsp вставлення. Вона просто коротко описує нашу сторінку. Дану сторінку запросто можна написати і зберегти з розширенням .html, видаливши перший рядок. При натисненні кнопки на сервер був переданий запит з відповідними змінними та їхніми значеннями.
Якщо б у нас був не POST, а GET запит, то у браузері при переході на сторінку name.jsp ми б побачили:
<pre>http://localhost:8080/HelloApp/hello.jsp?login=volodimirg&password=qazwsx&submit=Підтвердити</pre>
Друга сторінка name.jsp буде більш цікавішою. Її створити можна у тому ж каталозі що і попередня сторінка.
<syntaxhighlight lang="java">
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>JSP Page</title>
</head>
<body>
<h3>Ви розкриті</h3>
<% String login=request.getParameter("login");
String password=request.getParameter("password");
String ipAddress=request.getRemoteAddr();
%>
Ваш логін:<%= login %><br/>
Ваш пароль: <%= password %><br/>
Ваша IP адреса: <%= ipAddress %>
</body>
</html>
</syntaxhighlight>
[[Файл:HelloJSP.png|350px|thumb|right|Вигляд index.jsp та hello.jsp у браузері]]
Як бачимо у нас є JSP скриптлет оточений обмежувачами <% та %>. Тут по суті іде звичайний java код.
Наш Scriplet витягує значення параметрів і зберігає їх у відповідних змінних. Щоб у потрібному місці вивести значення змінних, використовуються відповідні JSP вирази, наприклад, <%= login %> - вставляє в код сторінки значення змінної login.
Слід зазначити, що при використанні кирилиці можуть виникнути проблеми з правильним відображенням символів із запиту. Коли замість потрібних букв будуть зображені незрозумілі закарлючки та символи. Вся проблема у різних кодуваннях запиту і того, що використовує віртуальна машина java, tomcat, база даних і т.п. Якщо у вас в наведеному прикладі вивело саме так, то у випадку з POST запитом допоможе створення спеціального сервлета-фільтра, який викликається перед запитом певних сторінок та сервлетів. Приклад фільтру та вирішення інших проблем з кодуванням дивіться на [http://stackoverflow.com/questions/138948/how-to-get-utf-8-working-in-java-webapps| stackoverflow.com]. Даний фільтр повинен бути відповідним чином прописаний у файлі конфігурації web.xml.
<syntaxhighlight lang="xml">
<filter>
<filter-name>NewFilter</filter-name>
<filter-class>ua.vova.NewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>NewFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</syntaxhighlight>
Знову ж таки, щоб не заплутатись у файлах конфігурації, популярні IDE надають графічні форми для редагування файлів конфігурації, зокрема і для web.xml.
З GET запитом складніше. В інтернеті можна знайти ряд рекомендацій як усунути цю проблему, проте роз’яснення потребує більш кращого знання теми JSP та сервлетів. Наразі, просто замініть назву типу запиту з GET на POST у відповідних прикладах, або ж застосовуйте латинські літери.
==JSP скриптлети та вирази==
Отже існують JSP скриптлети та JSP вирази, що оточені відповідними JSP тегами. З скриптлетами зрозуміло — у них всередині знаходяться інструкції Java. Що ж та таке вирази? Коли ви пишете вираз ви по суті говорите, що результат його обчислення повинен виводитися на екран (тобто вставлятися в html сторінку як текст). При цьому можна обійтися і без змінної:
<syntaxhighlight lang="java"><%= request.getParameter("password") %></syntaxhighlight>
Зверніть увагу, що на відміну від інструкцій скриптлету, вираз не закінчується крапкою з комою. Виводити можна як примітивні типи так і об’єкти. Якщо результатом виразу є об’єкт, то ви повинні бути впевнені, що в ньому присутній метод toString. В іншому разі буде викликаний метод toString класу Object, що є предком усіх класів Java. Результатом цього буде виведено лише ім’я класу та хеш-код.
Можна комбінувати скриптлети та вирази. Наприклад, в одному скриптлеті ви стартуєте цикл. Далі після нього йде вираз, який виводить значення змінної, а далі знову скриптлет, який збільшує змінну і завершує цикл. Це працює по тій при чині, що вкінці-кінців при першому звернені JSP сторінка спочатку перетворюється в сервлет, а далі уже сервлет при кожному зверненні формує HTML сторінку.
==П’ять типів JSP тегів==
{| class="wikitable"
!Теги|| Назва || Застосування
|-
| <% %> || JSP скриптлет || для вставлення блоку інструкцій java
|-
| <%= %> || JSP вираз || для показу string значення виразу
|-
| <%@ %> || JSP директива || для встановлення умови, що стосується усього JSP
|-
| <%-- --%> || JSP коментар|| cказати JSP процесору, щоб ігнорував код
|-
| <%! %> || JSP оголошення|| для оголошення екземплярів змінних та методів для JSP
|}
Якщо нам потрібно імпортувати певні класи, необхідно вставити наступну JSP директиву (директива сторінки, page directive):
<syntaxhighlight lang="java"><%@ page import="java.util.Date, ua.mylibrary.*" %></syntaxhighlight>
Різниця між html-коментарем <!-- --> та JSP коментарем <%-- --%> в тому, що html коментар є частиною html сторінки і пересилається користувачу, лишень не виводиться при перегляді її браузером, а JSP коментар суто для розробника. Він не опрацьовується при компіляції JSP сторінки і відповідно не включається в html-код сторінки, яку користувач переглядає у браузері. Зауважте, що якщо у html коментарі присутні JSP теги, то вони будуть скомпільовані і опрацьовані. Тобто якщо там передбачається створення певного об’єкту, то об’єкт на сервері буде створений. Якщо там є JSP вираз, то він буде опрацьований і у html коментар буде вставлено відповідний текст. JSP ж коментарі не компілюються, не опрацьовуються і відповідно нічого не створюється, нікуди не вставляється і не відсилається.
Тож, щоб уникнути сюрпризів і неправильного виконання, у випадку з JSP скриптлетами, виразами, директивами, тощо, використовуйте JSP коментарі, html-коментарі в цьому вам не допоможуть .
В середині скриптлету можна застосовувати звичайні коментарі джави (// та /* */ ).
JSP оголошення дозволяють оголошувати змінні та методи, проте це не дуже добре робити в JSP сторінках. Основна причина в тому, що такі змінні не є безпечними з точки зору багатонитковості. Використання таких змінних та методів може призвести до ряду проблем, пов’язаними з використанням їх різними нитками. Оголошені в JSP змінні і методи є глобальними і потрібно вживати спеціальних заходів, щодо безпечної роботи із ними.
==JSP помилки==
При роботі з JSP найчастіше в браузері можна побачити помилку 404 та 500.
'''Error 404''' означає, що JSP не знайдено. Необхідно перевірити чи працює Tomcat і чи коректна URL адреса.
'''Error 500''' означає, що JSP знайдено, проте не скомпільовано через помилку в середині. Уважно читайте інформацію відображену в браузері, за якою можна визначити, що це за помилка і де в коді вона.
== Привіт сервлет ==
Тож наступна наша задача написати сервлет, щоб робив те ж саме, що і hello.jsp.
Кожен сервлет повинен розширювати клас HttpServlet. Для того, щоб обробляти запити нам потрібно замістити два методи doPost та doGet. Оскільки обом методам найчастіше потрібно робити одне і те ж, то ж визначають цю роботу у одному методі, а в іншому методі просто його викликають. Також можна визначити інший, власний метод, який би викликався із методів doPost та doGet. Останнє і зроблено в нашому прикладі.
<syntaxhighlight lang="java">
package ua.volodimirg;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class HelloFirstServlet extends HttpServlet {
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
try {
//витягуємо параметри із http запиту
String login=request.getParameter("login");
String password=request.getParameter("password");
String ipAddress=request.getRemoteAddr();
//відсилаємо html-сторінку
out.println("<!DOCTYPE html>");
out.println("<html>");
out.println("<head>");
out.println("<title>Servlet HelloFirstServlet</title>");
out.println("</head>");
out.println("<body>");
out.println("<h3>Ви розкриті</h3>");
out.println("Ваш логін: "+ login +"<br/>");
out.println("Ваш пароль: " + password +"<br/>");
out.println("Ваша IP адреса: "+ipAddress);
out.println("</body>");
out.println("</html>");
} finally {
out.close();
}
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
}
</syntaxhighlight>
Якщо ви знаєте джаву, то нічого складного у вищенаведеному коді для вас немає. Нове тут з’явилося, хіба що наступний рядок:
<syntaxhighlight lang="java">PrintWriter out = response.getWriter();</syntaxhighlight>
Тут ми створюємо потік виводу, який відсилатиме назад у браузер необхідний html-код. Далі просто іде запис необхідного коду у потік виводу.
Щоб створити сервлет у IDE, необхідно натиснути на проекті праву кнопку миші і ввести назву сервлету, та псевдонім за яким до нього будуть звертатися. Наприклад, в даному прикладі повна назва HelloFirstServlet, а звертатися до нього будемо просто HelloServlet. Щоб це зробити, нам потрібно зробити декілька дій.
Перш за все зробити відповідне мапування (англ. mapping) у файлі web.xml. Скоріш за все IDE само створить вам відповідний файл і пропише усе потрібне (у NetBeans необхідно всього лиш поставити відповідну галочку при створенні сервлету). Для вищенаведених прикладів було створено наступний web.xml файл:
<syntaxhighlight lang="xml">
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<filter>
<filter-name>NewFilter</filter-name>
<filter-class>ua.volodimirg.NewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>NewFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>HelloFirstServlet</servlet-name>
<servlet-class>ua.volodimirg.HelloFirstServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HelloFirstServlet</servlet-name>
<url-pattern>/HelloFirst</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>
30
</session-timeout>
</session-config>
</web-app>
</syntaxhighlight>
Якщо ви не створювали фільтра сервлетів з метою правильного читання кирилиці, то тегів із його згадкою у вашому web.xml не буде.
Зверніть увагу як вказано як потрібно звертатися до сервлету в URL-адресі:
<syntaxhighlight lang="xml"><url-pattern>/HelloFirst</url-pattern></syntaxhighlight>
Друге, що нам потрібно, це модифікувати index.jsp. У тегу form, замість посилання на hello.jsp, поставте HelloFirst.
<syntaxhighlight lang="java"><form name="hello" action="HelloFirst" method="post"></syntaxhighlight>
Якщо усе правильно зроблено, то у браузері ви отримуватимете те ж саме, що і при використанні hello.jsp. Лишень рядок адреси у браузері при переході на нову сторінку виглядатиме так:
<pre>http://localhost:8080/HelloApp/HelloFirst</pre>
Зауважте, як іде зверненні до сервлету. Використовується не точна назва сервлету, а коротка, яку ми написали в web.xml файлі в тегові <url-pattern>.
Загалом, найкращий спосіб програмування веб-прикладень на java – це комбінація сервлетів та jsp.
І на останок, як вже було сказано будь-яка сторінка jsp компілюється і створюється відповідний сервлет, який і опрацьовує запити від користувача. Якщо ви написали jsp і щось йде не так, хоча ніби все правильно, ви завжди можете глянути на код створеного сервлету. Для цього, після того як викликали в браузері відповідну jsp, скористайтесь пошуком в каталогах tomcat і ви обов’язково знайдете скомпільовані файли з розширенням .class та вихідні файли з розширенням .java. Останні файли можна відкрити і переглянути код створеного сервлету. Так, для вищенаведеного прикладу, при запуску index.jsp, файл index_jsp.java знаходився за адресою C:\tomcat\work\Catalina\localhost\HelloApp\org\apache\jsp. І звичайно ж ви можете скористатися засобами зневадження у вашому інтегрованому середовищі розробки для пошуку вад у коді.
==Сесії==
[[Файл:ManagerApp.png|350px|thumb|right|Менеджер прикладень Tomcat 7]]
Коли ви відкриваєте JSP сторінку у браузері на сервері відбувається відкриття сесії. Ви можете подивитися на відкриті сесії Томкету відвідавши відповідну сторінку: на основній сторінці Tomcat 7 необхідно натиснути кнопку Manager App. Вам буде запропоновано ввести логін та пароль. У файлі C:\tomcat\conf\tomcat-users.xml повинен бути описаний відповідний користувач. У Tomcat 7 на відміну від Tomcat 6 використовується декілька користувачів для доступу до різних сторінок і можливостей Tomcat. Так в даному випадку необхідний користувач manager-gui. Для нашого випадку, для доступу до менеджера прикладень, необхідно, щоб були присутні такі рядки у tomcat-users.xml:
<syntaxhighlight lang="xml">
<tomcat-users>
<role rolename="manager-gui" />
<user password="55" roles="manager-gui" username="tomcat1" />
</tomcat-users>
</syntaxhighlight>
Тож при такому описі користувача, на запит пароля необхідно ввести tomcat1 та пароль 55. Ви можете задати у файлі tomcat-users.xml власну назву користувача і пароль. Загалом Tomcat інформуватиме вас, які користувачі потрібні для доступу до його службових сторінок.
Утримавши доступу до менеджера прикладень, ви зможете побачити скільки сесій запущено для певного веб-прикладення.
Термін Сесія застосовується до взаємодії сервера і користувача від моменту перегляду першої сторінки на сервері до закриття браузера або ж до закінчення часу відведеного для сесії з користувачем від останнього його звернення до сервера (переважно 30 хв.).
Коли користувач працює з вашим сайтом, сервер підтримує сесію за посередництвом кукі (англ. cookie – дослівно. печиво, коржик, ще є пропозиція перекладати як "реп'яшок"). Коли Tomcat отримує HTTP запит від клієнта, він перевіряє чи запит містить кукі за назвою по замовчуванню JSESSIONID. Якщо кукі не знайдено, то створюється кукі з унікальним значенням і воно додається до HTTP-відповіді. Це і знаменує собою початок сесії. Все це відбувається автоматично і не потрібно реалізовувати самому. Якщо браузер приймає куки, він додаватиме їх до усіх наступних запитів до цього серверу.
Також кукі можна створювати самому, вони використовуються для збереження і передачі часто вводимих даних на стороні користувача, проте у браузері користувач може відключати можливість використання кукі, тому потрібно або попереджати користувача, щоб увімкнув їх, або ж писати код сторінок так, щоб можна було обходитися без кукі.
Переглянути ID сесії можна так:
<syntaxhighlight lang="java">
<%
HttpSession session1=request.getSession();
String s=session1.getId();
out.println(s);
%>
</syntaxhighlight>
В результаті в браузері буде виведено ряд чисел, на зразок: E873633EC113311CA0306882A0143936
Що дає нам сесія? Основна мета сесії – це передача певних даних між різними JSP сторінками та сервлетами, що пов’язані з певним користувачем. З програмної точки зору, сесія – це спеціальний об’єкт в якому ми можемо зберігати ім’я змінної та її значення, або ж навіть цілий об’єкт. Наступний рядок демонструє як зберегти певне значення:
<syntaxhighlight lang="java">session.setAttribute("MyAppOperator", "");</syntaxhighlight>
І коли потрібно отримати значення можна скористатися відповідним методом getAttribute:
<syntaxhighlight lang="java">
boolean isOperator = (session.getAttribute("MyAppOperator") != null);
if (isOperator) { ...
</syntaxhighlight>
Наступний приклад демонструє використання сесійної змінної для підрахування звернень до сторінки під час сесії:
<syntaxhighlight lang="java">
<%
String s=request.getSession().getId();
out.println("ID="+s);
Long k=(Long)session.getAttribute("Counter");
if (k==null) k=1L;
else k=k+1L;
session.setAttribute("Counter", k);
k=(Long)session.getAttribute("Counter");
out.println("<br/> k="+k);
%></syntaxhighlight>
Просто вставте даний код у JSP сторінку.
Зауважте, що лічильник збільшується при кожному зверненні до сторінки, допоки браузер не буде закритий.
Якщо вкінці добавити рядок:
<syntaxhighlight lang="java">session.invalidate();</syntaxhighlight>
то кожного разу буде відкриватися нова сесія. Метод invalidate так би мовити «вбиває» сесію. Також можна встановити максимальний інтервал неактивності. Як вже було сказано по замовчування через пів години бездіяльності користувача, сесію буде закрито. Проте це можна змінити:
<syntaxhighlight lang="java">
session.setMaxInactiveInterval(60*60*24); // один день
session.setMaxInactiveInterval (-1); // допоки не буде закритий браузер
</syntaxhighlight>
При необхідності можна перебрати усі атрибути, що зберігає сесія таким чином:
<syntaxhighlight lang="java">
Enumeration names=session.getAttributeNames();
while (names.hasMoreElements())
{
out.println((String) names.nextElement());
}
</syntaxhighlight>
==Рекомендована література==
* Murach's Java Servlets and JSP (2nd Edition) by J. Murach, A. Steelman . 2008. - 729 p.
* Head First Servlets and JSP, 2nd Edition by Bryan Basham, Kathy Sierra, Bert Bates. 2008. - 912 p.
* [http://cse.csusb.edu/turner/java_web_programming/contents/ Java Web Programming with Eclipse] by David A Turner, Jinseok Chae
* Beginning JSP, Jsf and Tomcat: Java Web Development by Giulio Zambon. 2012. - 436 p.
[[Категорія:Веб-програмування на Java]]
[[Категорія:Java]]
[[Категорія:Шкільні курси]]
{{Стадія|25%}}
[[Категорія:Мови програмування]]
hdj5705cn16nmgmjbhln0wvzieh7xtm
Освоюємо Java/Колекції
0
5118
36853
36852
2022-08-03T12:00:27Z
Володимир Груша
985
/* Клас HashMap */
wikitext
text/x-wiki
При об’єктно орієнтованому програмуванні доводиться працювати з великою кількістю об’єктів. Зручно мати засоби групування об’єктів. Для цих цілей в Java розроблено набір інтерфейсів і класів на їх основі під назвою колекції . В основі ієрархії колекцій знаходиться інтерфейс Collection.
==Структура колекцій==
Згадаймо, що інтерфейс – це клас, який не містить реалізації методів, а лише їхні оголошення. Можна реалізувати безліч реалізацій інтерфейсу. Програмісту, який використовуватиме ці реалізації, достатньо знати базовий інтерфейс для роботи з його реалізаціями, тобто знати методи, які передбачає даний інтерфейс.
Collection – базовий інтерфейс, крім нього на його основі в структурі колекцій є ще декілька інтерфейсів, які розширюють базовий інтерфейс Collection. Зокрема, List, Set та SortedSet. Окремо виділяють ще інтерфейс Map. Він не походить на пряму від інтерфейсу Collection, проте його також відносять до колекцій. На їх основі створено набір класів, які згодяться програмістам для більшості випадків роботи з набором об’єктів. Тож вам не прийдеться самим їх реалізовувати.
Якщо вам цікаво, для чого стільки різних класів в колекціях? Суть в тому, що різні класи по різному реалізовують роботу з даними. Одні класи швидше здійснюють читання даних, інші вставлення і видалення, одні перевіряють, щоб не було дублювань, інші дозволяють вставляти дані за певним ключем і т.п. Доволі важливо підібрати клас, який найкраще підходить для вашого завдання і забезпечить найбільшу швидкодію. Особливо це актуально, коли кількість об’єктів величезна.
==Реалізації інтерфейсу Collection==
===Клас ArrayList та використання ітератора===
Клас ArrayList призначений для читання об'єктів по індексу. Тож не дарма у назві є слово Array (масив). Після створення колекції на основі ArrayList, прочитати дані можна кількома способами. Наступний приклад демонструє створення ArrayList, його наповнення об'єктами типу String та їх читання за допомогою методу get (int index) та за допомогою ітератора.
<syntaxhighlight lang="java">
import java.util.ArrayList;
import java.util.ListIterator;
public class TestArrayList {
private ArrayList<String> a1;
public static void main(String[] args) {
TestArrayList test = new TestArrayList();
test.create();
test.getData();
test.iterateData();
}
void create() {
//створюємо і наповнюємо ArrayList
a1 = new ArrayList<String>();
a1.add("Привіт");
a1.add("тобі");
a1.add("божевільний");
a1.add("світе!");
}
//читаємо дані по індексу
void getData() {
for (int i = 0; i < a1.size(); i++) {
System.out.print(a1.get(i) + " ");
}
}
//Читаємо вміст ArrayList з допомогою ітератора
void iterateData() {
ListIterator<String> it = a1.listIterator();
while (it.hasNext()) {
System.out.print(it.next() + " ");
}
}
}
</syntaxhighlight>
Результат:
<PRE>Привіт тобі божевільний світе! Привіт тобі божевільний світе!</PRE>
Крім вищенаведених способів можна передати вміст ArrayList у звичайний масив за допомогою методу toArray(). Якщо ви хочете детально розібратися з ArrayList і його методами, то для цього також дивіться інформацію про інтерфейси Collection, List та Iterator.
Окремо розглянемо перегляд даних з допомогою ітератора.
<syntaxhighlight lang="java">ListIterator<String> it=a1.listIterator();</syntaxhighlight>
Таким чином створюється об’єкт ітератора, посилання на який передається об'єктній змінній it типу ListIterator. ListIterator – це інтерфейс, який розширює інтерфейс Iterator декількома новими методами. Базовими ж методами інтерфейсу Iterator є ті, що використані у нас в програмі, а саме:
* boolean hasNext() – повертає true, якщо ітерація має наступний елемент
* E next() - повертає наступний елемент ітерації (буква E вказує, що це може бути елемент будь-якого типу, детальніше див. розділ [[Освоюємо_Java/Узагальнення|Узагальнення]])
* void remove() – знищує останній елемент, що повертався ітератором
Тож у коді бачимо:
<syntaxhighlight lang="java">
while(it.hasNext()){
System.out.print(it.next()+" ");
}
</syntaxhighlight>
Цикл працює поки є елементи в ітераторі. Перевірка здійснюється за допомогою методу hasNext. А вивід елементів здійснюється за допомогою методу next. Перевірка за допомогою hasNext необхідна через те, що в разі відсутності наступного елементу при виклику методу next буде викинуто виняток NoSuchElementExeption.
Інтерфейсом ListIterator передбачено ще такі методи як add, hasPrevious, next, nextIndex, previous, previousIndex, set. Назви методів говорять самі за себе. Детальніше ви можете подивитися в документації по інтерфейсу ListIterator.
Клас Itr, який реалізовує інтерфейс ListIterator є внутрішнім класом класу AbstractList. ArrayList є нащадком класу AbstractList.
Для того, щоб ітератор міг працювати з певним об’єктом, клас даного об’єкту повинен реалізовувати інтерфейс Iterable:
<syntaxhighlight lang="java">
public interface Iterable<E>
{
Iterator<E> iterator();
}
</syntaxhighlight>
Інтерфейс Collection розширює даний інтерфейс.
Можна також перебрати елементи за допомогою перевантаженого з виходом java 5 циклу for (так званого “for each”):
<syntaxhighlight lang="java">
for (String str : a1) {
System.out.print(str+" ");
}
</syntaxhighlight>
При компіляції даний цикл перетворюється компілятором у цикл із ітератором.
ArrayList можна також перетворити у звичайний масив за допомогою методу toArray():
<syntaxhighlight lang="java">
String strArray[]= new String[a1.size()];
strArray=a1.toArray(strArray);
System.out.println(strArray[0]);
</syntaxhighlight>
Якщо ви погано розумієте вищенаведений приклад і як усе працює зверніться до розділів, що описують основні концепції об’єктно-орієнтованого програмування і, зокрема, розберіть детально теми інтерфейсів, абстрактних класів та поліморфізму.
===Клас LinkedList===
LinkedList — це структура даних, що являє собою пов’язаний список елементів (об’єктів).
Різниця між ArrayList та LinkedList полягає в тому, що ArrayList реалізований у вигляді масиву, а LinkedList у вигляді пов’язаних між собою об’єктів. ArrayList швидко виконує читання і заміну елементів (посилань на об’єкти), проте, щоб вставити новий елемнт в середину ArrayList або видалити існуючий в середині ArrayList здійснюється послідовний зсув цілого ряду елементів масиву. В LinkedList доволі швидко відбувається вставлення нового елементу або видалення існуючого. Це відбувається тому, що в середині реалізації LinkedList змінюються лише посилання на попередній і наступний об’єкти (елементи). Проте доступ до об’єктів по індексу в LinkedList відбувається повільніше ніж в ArrayList. Тож загалом, LinkedList корисний, коли необхідно часто вставляти та видаляти елементи зі списку, а в інших випадках краще використовувати ArrayList.
Існує два конструктури LinkedList:
<syntaxhighlight lang="java">
LinkedList()
LinkedList (Collection c)
</syntaxhighlight>
Перший конструктор створює пустий список, а другий – створює пов’язаний список із іншої колекції.
Клас LinkedList розширює клас AbstractSequentalList та реалізує інтерфейси List, Dequeue та Queue. Реалізація останніх двох інтерфейсів (черг) означає, що ми можемо працювати із пов’язаним списком як із стеком з використанням методів pop(), push(), poll(), pollFirst(), pollLast() і т.п. Детальніше дивіться документацію по заданим інтерфейсам.
Далі попрацюємо з LinkedList, який міститиме в якості елементів об’єктні змінні типу Car.
Спочатку реалізуємо наш клас Car:
<syntaxhighlight lang="java">
public class Car {
private String name;
private double price;
private int year;
public Car(String name, double price, int year) {
this.name = name;
this.price = price;
this.year=year;
}
@Override
public String toString() {
return "\n Car [name=" + name + ", price=" + price + ", year=" + year
+ "]";
}
}
</syntaxhighlight>
Клас Car містить лише поля, конструктор, який заповнює дані поля та заміщений метод toString(), який видаватиме нам інформацію про автомобіль у вигляді рядка.
Наступний клас демонструє роботу з LinkedList:
<syntaxhighlight lang="java">
import java.util.ArrayList;
import java.util.LinkedList;
public class TestLinkedList {
private LinkedList<Car> ll=new LinkedList<>();
public static void main(String[] args) {
TestLinkedList t=new TestLinkedList();
t.test();
}
void test(){
Car car1=new Car("Ferrary", 10800, 1995);
Car car2=new Car("Запорожець", 2600, 1989);
ll.add(car1);
ll.add(car2);
//додаємо в початок списку
ll.addFirst(new Car("Alfa Romeo 155", 11678, 2000));
ll.remove(car2); // видалити об'єкт
System.out.println("Після видалення car2: "+ll);
ll.remove(1); //видалити елемент за індексом
System.out.println("Після видалення першого елементу: "+ll);
Car myCar=ll.get(0);
System.out.println("Отриманий елемент за індексом [0]:"+myCar);
ll.set(0, car1); //замінити елемент за індексом
System.out.println("Замінений елемент за індексом [0]"+ll.get(0));
ArrayList<Car> arrList=new ArrayList<Car>();
arrList.add(car1);
arrList.add(car2);
ll.addAll(arrList); //додаємо вміст ArrayList у наш LinkedList
System.out.println("Після додавання ArrayList:"+ll);
}
}
</syntaxhighlight>
Результат виконання програми:
<PRE>
Після видалення car2: [
Car [name=Alfa Romeo 155, price=11678.0, year=2000],
Car [name=Ferrary, price=10800.0, year=1995]]
Після видалення першого елементу: [
Car [name=Alfa Romeo 155, price=11678.0, year=2000]]
Отриманий елемент за індексом [0]:
Car [name=Alfa Romeo 155, price=11678.0, year=2000]
Замінений елемент за індексом [0]
Car [name=Ferrary, price=10800.0, year=1995]
Після додавання ArrayList:[
Car [name=Ferrary, price=10800.0, year=1995],
Car [name=Ferrary, price=10800.0, year=1995],
Car [name=Запорожець, price=2600.0, year=1989]]
</PRE>
Перебирати елементи LinkedList також можна з допомогою ітератора та у циклі for earch.
Детальніше про методи класу дивіться документацію по класу [https://docs.oracle.com/javase/9/docs/api/java/util/LinkedList.html LinkedList].
===Клас HashSet===
HashSet – це клас призначений для зберігання даних у вигляді множини невпорядкованих елементів. Якщо потрібна впорядкована множина, то використовуйте TreeSet. HashSet також не гарантує стабільного порядку збереження об’єктів. Тобто при додаванні об’єктів порядок зберігання елементів змінюється. Вони можуть бути збережені як в кінці множити так і в середині. Якщо потрібен один порядок зберігання об’єктів використовуйте LinkedHashSet.
Сам термін «множина» означає, що елементи не будуть повторюватися. Для зберігання і пошуку елементів використовується хеш-код об’єкта. HashSet також може містити значення null. Власне всередині самої реалізації HashSet використовується клас HashMap, який дозволяє зберігати елементи у вигляді двох складових ключа та хеш-коду. У класі HashSet хеш-код недоступний і використовується неявно для користувача.
Клас HashSet розширює клас AbstractSet та реалізує інтерфейс Set. Також реалізовує інтерфейси Serializable та Clonable.
HashSet має такі конструктори:
<pre>
HashSet()
HashSet (Collection c)
HashSet (int об’єм)
HashSet (int об’єм, float коефіцієнт_заповнення)
</pre>
Коефіцієнт заповнення – це число в межах 0.0 до 1.0, що представляє собою частку заповнення HashSet при якій об’єм HashSet буде збільшений. По замовчуванню в конcтрукторах, що не задають коефіцієнт заповнення, використовується значення 0.75.
Наступний приклад демонструє роботу із HashSet.
<syntaxhighlight lang="java">
import java.util.HashSet;
public class TestHashSet {
HashSet<String> hs=new HashSet<String>();
public static void main(String[] args) {
TestHashSet test=new TestHashSet();
test.test();
}
void test(){
hs.add("Австралія");
hs.add("Україна");
hs.add("США");
System.out.println("1) Три країни: "+hs+" розмір="+hs.size());
hs.add("Австралія"); // помилки не буде, але в HashSet нічого не поміняється
System.out.println("2) Після спроби додати Авcтралію ще раз: "+hs);
hs.remove("США"); //видаляємо США з множини
hs.add("Німеччина");
hs.add("Англія");
hs.add(null);
hs.add(null); // другий раз не додаситься
System.out.println("3)"+hs);
System.out.println("4) Чи містить множина Німеччину? "+hs.contains("Німеччина"));
System.out.println("5) Множина пуста? "+hs.isEmpty());
//можемо також отримати ітератор, або ж перебрати множину у for earch
for (String str:hs){
System.out.println(str);
}
hs.clear(); // очистити
System.out.println("6) Розмір після очищення="+hs.size());
}
}
</syntaxhighlight>
Результат виконання:
<pre>
1) Три країни: [Австралія, Україна, США] розмір=3
2) Після спроби додати Австралію ще раз: [Австралія, Україна, США]
3)[null, Австралія, Німеччина, Україна, Англія]
4) Чи містить множина Німеччину? true
5) Множина пуста? false
null
Австралія
Німеччина
Україна
Англія
6) Розмір після очищення=0
</pre>
Зробити копію хеш множини можна так:
<pre>
HashSet<String> hsc=(HashSet)hs.clone();
</pre>
Слід зауважити, що метод clone() здійснює поверхневе (shadow) копіювання, тобто копіюються лише адреси об’єктів, які містяться у екземплярі класу HashSet, а не самі об’єкти.
При використанні ітератор може викидати виняток ConcurrentModificationException, якщо HashSet було змінено. Щоб уникнути таких випадків слід використовувати методи ітератора для зміни HashSet.
Клас HashSet несинхронізоватий для багатопоточності, проте його можна синхронізувати використовуючи метод synchronizedSet класу Collections:
<pre>
Set s = Collections.synchronizedSet (new HashSet (...))
</pre>
У класу String перевизначені такі методи як equal та hashcode, що дає можливість коректного порівняння їхніх хеш-кодів та значень і уникати випадків, коли будуть додаватися ідентичні рядки, незалежно від того, чи вони зберігаються в різних комірках пам’яті. Проте при використанні власних класів, на практиці для правильного функціонування HashSet (без повторення об'єктів з однаковим станом, наприклад, ідентичними полями) у класах необхідно замістити методи equals() та hashcode() самому. Так, якщо ми створимо класи оболонки, що міститимуть String поле countryName із однаковим значенням, наприклад, “Австрія”, то у нас два об'єкти вважатимуться різні, оскільки у них буде різний Хеш-код, тож вони будуть додані до HashSet. В таких випадках необхідно продумати методи equals() та hashcode().
===Клас LinkedHashSet===
Клас <code>LinkedHashSet</code> розширює клас HashSet не додаючи ніяких нових методів. Працює він дещо довше за HashSet проте зберігає порядок в якому елементи додаються до нього. Відповідно це дозволяє організувати послідовну ітерацію вставлення та витягнення елементів. Всі конструктори та методи роботи з LinkedHashSet аналогічні методам класу HashSet.
===Клас TreeSet===
Клас TreeSet дозволяє створювати відсортовану множину. Тобто елементи не повторюються та зберігаються у відсортованому порядку. Для зберігання елементів застосовується бінарна деревоподібна структура. Об'єкти зберігаються в відсортованому порядку по зростанню. Час доступу та одержання елементів доволі малий, тому клас TreeSet підходить для зберігання великих об’ємів відсортованих даних, які повинні бути швидко знайдені.
Клас TreeSet розширює клас AbstractSet та реалізує інтерфейс NavigableSet. NavigableSet реалізується на базі TreeMap.
В класі доступні чотири конструктори:
<syntaxhighlight lang="java">
TreeSet ()
TreeSet(Collection с)
TreeSet(Comparator компаратор)
TreeSet(SortedSet ss)
</syntaxhighlight>
Третій конструктор дозволяє задавати власний компаратор, відповідно до якого буде відбуватися сортування об’єктів. Так об’єкти класу String не потребують реалізації власного компаратора, проте якщо ви хочете зберігати в класі TreeSet розроблені вами об’єкти, то потрібно задавати компаратор для цих об’єктів. Такий компаратор може реалізовувати сортування об’єктів по певному полю, наприклад по Прізвищу, якщо ваш клас зберігаю інформацію про осіб. Можна реалізувати ланцюжок компараторів з використанням методу thenComparing() класу Comparator.
TreeSet не може містити значення null. Також TreeSet не синхронізований клас, як і інші класи колекцій при потребі його потрібно синхронізувати з використанням методу Collections.synchronizedSet().
Розглянемо приклад роботи TreeSet з компаратором. Використаємо клас Car, який був попередньо використаний при роботі з LinkedList додавши лише гетер та сетер методи.
<syntaxhighlight lang="java">
public class Car {
private String name;
private double price;
private int year;
public Car(String name, double price, int year) {
this.name = name;
this.price = price;
this.year=year;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
@Override
public String toString() {
return "\n Car [name=" + name + ", price=" + price + ", year=" + year+ "]";
}
}
</syntaxhighlight>
Клас компаратора CarsComparator виглядає так:
<syntaxhighlight lang="java">
import java.util.Comparator;
public class CarsComparator implements Comparator {
@Override
public int compare(Car car1, Car car2) {
if(car1.getYear() > car2.getYear())
return 1;
else if (car1.getYear() < car2.getYear())
return -1;
else return 0;
}
}
</syntaxhighlight>
Наша програма з TreeSet:
<syntaxhighlight lang="java">
import java.util.Comparator;
import java.util.TreeSet;
public class TestTreeSet{
CarsComparator comp=new CarsComparator();
TreeSet<Car> ts1=new TreeSet<>(comp);
public static void main(String[] args) {
TestTreeSet t=new TestTreeSet();
t.test();
}
void test(){
Car car1=new Car("Ferrary", 12000, 1988);
Car car2=new Car("Ford", 13000, 1955);
Car car3=new Car("Toyota", 13500, 2003);
Car car4=new Car("Citroen", 12000, 2014);
Car car5=new Car("Mercedes-Benz", 15000, 2011);
ts1.add(car1);
ts1.add(car2);
ts1.add(car3);
ts1.add(car4);
ts1.add(car5);
System.out.println("Сортування по роках: "+ts1);
//Зворотній компаратор для TreeSet(Java8)
TreeSet<Car> ts2=new TreeSet<>(comp.reversed());
ts2.addAll(ts1); //додати вміст попереднього TreeSet у новий
System.out.println("Зворотнє сортування:"+ts2);
}
}
</syntaxhighlight>
Результат виконання:
<pre>
Сортування по роках: [
Car [name=Ford, price=13000.0, year=1955],
Car [name=Ferrary, price=12000.0, year=1988],
Car [name=Toyota, price=13500.0, year=2003],
Car [name=Mercedes-Benz, price=15000.0, year=2011],
Car [name=Citroen, price=12000.0, year=2014]]
Зворотнє сортування:[
Car [name=Citroen, price=12000.0, year=2014],
Car [name=Mercedes-Benz, price=15000.0, year=2011],
Car [name=Toyota, price=13500.0, year=2003],
Car [name=Ferrary, price=12000.0, year=1988],
Car [name=Ford, price=13000.0, year=1955]]
</pre>
Реалізація інтерфейсу NavigableSet забезпечила клас TreeSet доволі корисними методами як то ceiling(), floor(), headset(), higher(), pollFirst(), pollLast(), subset(), tailSet(), iterator(), descendingIterator(), descendingSet(). Використовуючи їх можна організувати доволі зручний вибір елементів з TreeSet. Див. детальніше документацію по TreeSet.
===Клас PriorityQueue===
PriorityQueue дозволяє реалізувати чергу на основі пріоритету. Така черга може бути корисна, наприклад, у разі необхідності обслуговування клієнтів згідно пріоритету. При зберіганні чисел в пріоритетній черзі, така черга гарантує, що першим елементом завжди буде найменший елемент. При цьому не гарантується ніякий стабільний послідовний порядок збереження елементів. Після додавання або видалення елементу з пріоритетної черги, порядок зберігання елементів в цій черзі змінюється таким чином, що в голові черги опиняється найменший елемент згідно його природнього порядку або згідно заданого компаратора.
<syntaxhighlight lang="java">
PriorityQueue має наступні конструктори:
PriorityQueue() //початковий об’єм становить 11
PriorityQueue(int початковий_об’єм)
PriorityQueue(Comparator comparator)
PriorityQueue(int початковий_об'єм, Comparator компаратор)
PriorityQueue(Collection с)
PriorityQueue(PriorityQueue с)
PriorityQueue(SortedSet с)
</syntaxhighlight>
Таким чином в разі потреби можна задати власний компаратор для видачі елементів у потрібному нам порядку.
PriorityQueue не може містити null. PriorityQueue розширює AbstractQueue та реалізує інтерфейси Serializable, Iterable, Collection, Queue.
Реалізація інтерфейсу Queue говорить нам, що в PriorityQueue доступні такі методи роботи з чергою:
*add(E e) – додати вказаний елемент у чергу
*element() – отримати, але не видаляти, елемент з голови черги
*offer(E e)- додати визначений елемент у чергу
*peek() – отримати елемент з голови черги, але не видаляти його. Повертає null, якщо черга порожня
*poll() – отримати та видалити елемент з голови черги
*remove() - отримати та видалити елемент з голови черги
Крім того в PriorityQueue достуні методи, що наявні і в інших колекціях як то: clear(), comparator(), contains(), iterator(), spliterator(), size(), toArray() тощо.
Приклад:
<syntaxhighlight lang="java">
import java.util.PriorityQueue;
public class TestPriorityQueue {
public static void main(String[] args) {
PriorityQueue<Integer> pq= new PriorityQueue<>(11);
pq.add(750);
pq.add(50);
pq.offer(1);
pq.add(300);
pq.add(25);
pq.add(2);
pq.offer(20);
pq.add(5);
pq.add(40);
System.out.println("Порядок зберігання елементів"+pq);
// Отримуємо і видаляємо елемент з голови черги
while (!pq.isEmpty()) {
System.out.println("Отримали: "+pq.poll());
System.out.println("Новий порядок:"+pq);
}
}
}
</syntaxhighlight>
Результат:
<pre>
Порядок зберігання елементів[1, 5, 2, 25, 300, 50, 20, 750, 40]
Отримали: 1
Новий порядок:[2, 5, 20, 25, 300, 50, 40, 750]
Отримали: 2
Новий порядок:[5, 25, 20, 750, 300, 50, 40]
Отримали: 5
Новий порядок:[20, 25, 40, 750, 300, 50]
Отримали: 20
Новий порядок:[25, 50, 40, 750, 300]
Отримали: 25
Новий порядок:[40, 50, 300, 750]
Отримали: 40
Новий порядок:[50, 750, 300]
Отримали: 50
Новий порядок:[300, 750]
Отримали: 300
Новий порядок:[750]
Отримали: 750
Новий порядок:[]
</pre>
Таким чином за допомогою методу poll() (його можна також замінити методом remove()), ми можемо отримувати елементи масиву у відсортованому порядку, незважаючи на те, що в самій пріоритетній черзі елементи зберігаються у іншому порядку.
===Клас ArrayDeque===
ArrayDeque (читається як аррейдек) – це клас який забезпечує двосторонню чергу. Іншими словами - це автоматично зростаючий масив, що дозволяє нам додавати або видаляти елементи з обох боків черги. ArrayDeque може бути використано як стек (LIFO, останній ввійшов - перший вийшов) або ж як черга (FIFO, перший ввійшов - перший вийшов).
ArrayDeque не може містити в якості елемента null.
Клас ArrayDeque швидший за клас Stack, якщо використовувати його в якості стеку і швидший за LinkedList, якщо використовувати в якості черги.
ArrayDeque розширює клас AbstractCollection та реалізує інтерфейси Deque, Cloneable, Serializable. Таким чином ми можемо використовувати для роботи з даним класом, як методи інтерфейсу Deque (який розширює інтерфейс Queue) так і методи інтерфейсу Collection.
Якщо використовується ітератор, то він буде викидати виняток ConcurrentModificationException, якщо вміст ArrayDeque був модифікований після створення ітератора. Таким чином ітератор необхідно з обережністю використовувати з ArrayDeque.
В ArrayDeque доступні наступні конструктори:
<syntaxhighlight lang="java">
ArrayDeque() // пустий ArrayDeque з початковим об’ємом 16 елентів
ArrayDeque(Collection c) // міститиме елементи колекції в порядку, що повертає ітератор даної колекції
ArrayDeque(int numElements) // дозволяє задати початковий об’єм
</syntaxhighlight>
При потребі збільшення об'єму, то він автоматично збільшується вдвічі.
Наступний приклад демонструє роботу із ArrayDeque у вигляді стека та у в вигляді черги:
<syntaxhighlight lang="java">
import java.util.ArrayDeque;
public class TestArrayDeque {
public static void main(String[] args) {
ArrayDeque<String> ad=new ArrayDeque<>();
System.out.println("Використання в якості стеку");
ad.push("Перший"); // метод інтерфуйсу Deque
ad.push("Другий");
ad.push("Третій");
System.out.println("Перший елемент ArrayDeque: "+ad.getFirst());//Отримуємо перший елемент, але не видаляємо
System.out.println("Вміст ArrayDeque: "+ad);
System.out.println(ad.pop()); //Отримуємо і видаляємо з вершини стеку
System.out.println(ad.pop()); //еквівалентно до removeFirst()
System.out.println(ad.pop());
//System.out.println(ad.pop()); //ArrayDeque порожній видасть NoSuchElementException
System.out.println();
System.out.println("Використання в якості черги");
ad.offer("Перший");
ad.offer("Другий");
ad.offer("Третій");
System.out.println("Перший елемент ArrayDeque: "+ad.getFirst());//Отримуємо перший елемент, але не видаляємо
System.out.println("Вміст ArrayDeque: "+ad);
System.out.println(ad.poll()); //витягнути і видалити з голови
System.out.println(ad.poll());
System.out.println(ad.poll());
System.out.println(ad.poll());
}
}
</syntaxhighlight>
Результат роботи:
<pre>
Використання в якості стеку
Перший елемент ArrayDeque: Третій
Вміст ArrayDeque: [Третій, Другий, Перший]
Третій
Другий
Перший
Використання в якості черги
Перший елемент ArrayDeque: Перший
Вміст ArrayDeque: [Перший, Другий, Третій]
Перший
Другий
Третій
null
</pre>
Дивіться також офіційну документацію по: [https://docs.oracle.com/javase/8/docs/api/java/util/Deque.html Інтерфейсу Deque] та
[https://docs.oracle.com/javase/8/docs/api/java/util/Collection.html Інтерфейсу Collection]
===Клас EnumSet===
Клас EnumSet — це одна з спеціалізованих реалізацій інтерфейсу Set для використання з перелічуваним типом даних (enum). EnumSet розширює AbstractSet та реалізує Cloneable та Serializable інтерфейси Java. EnumSet заміщує більшість методів інтерфейсів Set та Collection. EnumSet доволі швидка реалізація Set, швидша за HashSet, тому що всередині використовуються побітові операції, а не хеш-коди об’єктів.
EnumSet не синхронізований і повинен бути синхронізований ззовні, наприклад з використанням методу Collections.synchronizedSet(java.util.Set).
Всі елементи enum множини мають походити від єдиного перелічуваного типу, що вказується, коли множина створюється явно або неявно. EnumSet не дозволяє додавати значення null. Елементи зберігаються в порядку в якому їх подано в переліченні (enum).
EnumSet використовує безвідмовний (fail-safe) ітератор, що працює з копією EnumSet, тобто ітератор не буде викидати виняток ConcurrentModificationException, в разі зміни даних множини поза ітератором.
EnumSet – це відкритий абстрактний клас, який не має відкритого конструктора, для створення об’єкту EnumSet використовуються відповідні статичні факторні методи. В даних методах для створення EnumSet використовуються дві реалізації даного класу RegularEnumSet(для зберігання невеликих перелічень, до 64) та JumboEnumSet (для зберігання великих перелічень). Наступний приклад демонструє роботу з EnumSet:
<syntaxhighlight lang="java">
import java.util.EnumSet;
enum Colors
{
RED, GREEN, YELLOW, BLUE, BLACK
};
public class TestEnumSet
{
public static void main(String[] args)
{
// Створюємо множину
EnumSet<Colors> set1, set2, set3, set4, set5;
// Додаємо окремі елементи, порядок зберігання буде згідно порядку перелічення
set1 = EnumSet.of(Colors.RED, Colors.GREEN,
Colors.BLACK, Colors.BLUE);
// Заповнити тими елемнтами, яких нема у вказаній множині
set2 = EnumSet.complementOf(set1);
// Всі із даного перелічення
set3 = EnumSet.allOf(Colors.class);
// Додати усі елементи перелічення в діапазоні від GREEN до BLACK
set4 = EnumSet.range(Colors.GREEN, Colors.BLACK);
// створити пусту множину перелічень відповідного типу
set5= EnumSet.noneOf(Colors.class);
System.out.println("Set 1: " + set1);
System.out.println("Set 2: " + set2);
System.out.println("Set 3: " + set3);
System.out.println("Set 4: " + set4);
System.out.println("Set 5: " + set5);
}
}
</syntaxhighlight>
Результат роботи:
<pre>
Set 1: [RED, GREEN, BLUE, BLACK]
Set 2: [YELLOW]
Set 3: [RED, GREEN, YELLOW, BLUE, BLACK]
Set 4: [GREEN, YELLOW, BLUE, BLACK]
Set 5: []
</pre>
==Інтерфейс Map та класи, що його реалізують==
'''''Зіставлення''''' (англ. ''map'', також перекладають як ''відображення'')– це об’єкт який зіставляє ключ із відповідним значенням (key/value). Маючи ключ ви можете знайти його значення. І ключ, і значення є об’єктами. Ключ може бути унікальним, а значення може повторюватися. Деякі зіставлення можуть приймати null ключ і null значення, інші не можуть.
Зіставлення не підтримують Iterable інтерфейс. Тому ви не зможете використати ітератор для перебору вмісту зіставлення. Також ви не можете використовувати цикл for each. Проте можна перетворити зіставлення у інший тип колекції і вже на ньому можна отримати ітератор.
Основу зіставлень складає інтерфейс '''Map'''.
Map є узагальненим (див. розділ [[Освоюємо Java/Узагальнення|Узагальнення]]) і оголошений так:
<code>
interface Map<K, V>
</code>
де K – визначає тип ключа, а V визначає тип значення.
Інтерфейс '''SortedMap''' розширює інтерфейс Map і забезпечує, що вміст зберігається в порядку зростання, базуючись на значенні ключа.
Інтерфейс '''NavigableMap''' розширює SortedMap і забезпечує повернення вмісту базуючись на схожості ключа або ключів.
Інтерфейс '''Map.Entry''' – вкладений в Map інтерфейс і забезпечує роботу із вмістом зіставлення.
Класи, що реалізують інтерфейс Map наведені в таблиці.
{| class="wikitable" style="text-align: left; width: 800px;"
!Клас||Опис
|-
|AbstractMap ||Реалізує більшість інтерфейсу Map
|-
|EnumMap ||Розширює AbstractMap для використання з перелічуваними ключами.
|-
|HashMap ||HashMap розширює AbstractMap, щоб використовувати хеш таблиці.
|-
|TreeMap ||TreeMap розширює AbstractMap для використання дерев.
|-
|WeakHashMap ||WeakHashMap розширює AbstractMap для використання слабких ключів, що забезпечує утилізацію невикористовуваних ключів збирачем мусору
|-
|LinkedHashMap ||LinkedHashMap розширює HashMap дозволяючи ітерацію з вводом елементів в певному порядку
|-
|IdentityHashMap ||IdentityHashMap розширює AbstractMap і використовує рівність посилань при порівнянні документів
|}
===Клас HashMap===
HashMap розширює AbstractMap та реалізує інтерфейс Map. Клас не додає власних методів. Клас використовує хеш таблиці для зберігання зіставлення. HashMap не гарантує порядок елементів.
<code>
HashMap має наступні конструктори:
HashMap( )
HashMap(Map<? extends K, ? extends V> m)
HashMap(int capacity)
HashMap(int capacity, float fillRatio)
</code>
Перший створює HashMap по замовчуванню. Другий створює хеш зіставлення використовуючи елементи m. Третій задає ємність хеш зіставлення. Четвертий задає ємність(по замовчуванню 16) та коефіцієнт заповнення (по замовчуванню 0.75).
<syntaxhighlight lang="java">
package Map;
import java.util.HashMap;
import java.util.*;
import java.util.Set;
public class TestHashMap {
public static void main(String[] args) {
// створюємо об'єкт HashMap з назвою capitalCities
HashMap<String, String> capitalCities = new HashMap<String, String>();
// додаємо ключі і значення (Країна, Столиця)
capitalCities.put("Англія", "Лондон");
capitalCities.put("Німеччина", "Берлін");
capitalCities.put("Норвегія", "Осло");
capitalCities.put("США", "Вашингтон");
//вивести значення об'єкту capitalCities
System.out.println(capitalCities);
//звернутися до HashMap використовуючи ключ
System.out.println(" Отримати столицю США");
System.out.println(capitalCities.get("США"));
//Видалити Англію
System.out.println(" Видаляємо Англію");
capitalCities.remove("Англія");
System.out.println(capitalCities);
//видалити все можна так
//capitalCities.clear();
// друкуємо ключі
System.out.println(" Ключі:");
for (String i : capitalCities.keySet()) {
System.out.println(i);
}
// друкуємо значення
System.out.println(" Значення:");
for (String i : capitalCities.values()) {
System.out.println(i);
}
// Друкувати ключі і значення
System.out.println(" Ключі і значення:");
for (String i : capitalCities.keySet()) {
System.out.println("key: " + i + " value: " + capitalCities.get(i));
}
System.out.println("Використовуємо Map.Entry");
//одержати множину входжень
Set<Map.Entry<String,String>> set=capitalCities.entrySet();
//вивести множину входжень
for(Map.Entry<String, String> me: set) {
System.out.print(me.getKey()+": ");
System.out.println(me.getValue());
}
}
}
</syntaxhighlight>
Результат:
<pre>
{США=Вашингтон, Англія=Лондон, Норвегія=Осло, Німеччина=Берлін}
Отримати столицю США
Вашингтон
Видаляємо Англію
{США=Вашингтон, Норвегія=Осло, Німеччина=Берлін}
Ключі:
США
Норвегія
Німеччина
Значення:
Вашингтон
Осло
Берлін
Ключі і значення:
key: США value: Вашингтон
key: Норвегія value: Осло
key: Німеччина value: Берлін
Використовуємо Map.Entry
США: Вашингтон
Норвегія: Осло
Німеччина: Берлін
</pre>
Ключі і значення в HashMap є об’єктами. Якщо ми хочемо використати, наприклад, числа цілого типу (іnt) то використовуватиметься клас обгортка Integer. Так само і для інших примітивних типів.
===Клас TreeMap===
Клас '''TreeMap''' розширює '''AbstractMap''' та реалізує інтерфейс '''NavigableMap'''. TreeMap не містить методів крім тих, що визначені у NavigableMap та класі AbstractMap. Що забезпечує зберігання зіставлень за допомогою деревовидної структури. TreeMap забезпечує зберігання пар ключ/значення у відсортованому порядку (в порядку зростання), що забезпечує швидкий доступ до елементів. TreeMap по замовчуванню сортується за ключами. Для задання іншого сортування використовують компаратор.
TreeMap узагальнений клас і оголошується так:
<code>
class TreeMap<K,V>
</code>
де K – задає тип ключа, а V – задає тип значення.
TreeMap визначає наступні конструктори:
<pre>
TreeMap( )
TreeMap(Comparator<? super K> comp)
TreeMap(Map<? extends K, ? extends V> m)
TreeMap(SortedMap<K, ? extends V> sm)
</pre>
Перший створює пусте деревовидне зіставлення, що буде відсортоване використовуючи природній порядок ключів. Другий створює пусте зіставлення, що буде відсортоване використовуючи компаратор. Третій створює деревовидне зіставлення із входжень зіставлення m, що буде відсортоване в природньому порядку. Третій ініціалізує деревовидне зіставлення входженнями із sm з порядком сортуванням того ж sm.
<syntaxhighlight lang="java">
package Map;
import java.util.TreeMap;
import java.util.*;
public class TestTreeMap {
public static void main(String[] args) {
TreeMap<String, Integer> countries = new TreeMap<String, Integer>();
countries.put("Гваделупа",1);
countries.put("США",2);
countries.put("Гаваї",3);
countries.put("Бельгія", 4);
//вивести вміст
System.out.println(countries);
//вивести останній ключ
System.out.println("Останній ключ:"+countries.lastKey());
countries.put("Албанія", 5);
System.out.println(" Вміст зіставлення:");
// взяти множину входжень
Set<Map.Entry<String, Integer>> set = countries.entrySet();
// Вивести елементи
for(Map.Entry<String, Integer> me : set) {
System.out.print(me.getKey() + ": ");
System.out.println(me.getValue());
}
System.out.println();
}
}
</syntaxhighlight>
Результат:
<pre>
{Бельгія=4, Гаваї=3, Гваделупа=1, США=2}
Останній ключ:США
Вміст зіставлення:
Албанія: 5
Бельгія: 4
Гаваї: 3
Гваделупа: 1
США: 2
</pre>
(потребує доповнення)
==Алгоритми==
В структурі колекцій існує клас Collections, який надає ряд зручних статичних методів для роботи з даними. Нагадаємо, що статичні методи – це методи, які не потребують створення об'єктів і реалізують ряд додаткових алгоритмів по роботі з колекціями, як то сортування колекцій, знаходження максимального і мінімального елементу, перемішування, копіювання і т.п.
(необхідно розширити)
==Arrays==
(Ще не написано)
==Успадковані класи ==
Ранні версії Java не включали структуру Collections. Там було визначено декілька класів та інтерфейсів, що надавали методи для зберігання об'єктів. Структура Collections була додана в Java 2. (j2se 1.2). Тоді початкові класи були перероблені для підтримки інтерфейсів колекцій. Ці ранні класи також знані як успадковані класи (Legacy classes). В Java 5 успадковані класи та інтерфейси були перероблені для підтримки узагальнень. Їх підтримують, тому що до сих пір існує код, який їх використовує. Успадковані класи - синхронізовані. Класи входять в пакет java.util. Успадкованими є наступні класи:
* Dictionary
* HashTable
* Properties
* Stack
* Vector
Успадкованим є інтерфейс Enumaration, на заміну якому прийшов інтерфейс Iterator. Enumaration інтерфейс до сих пір використовується в декількох методах класів Vector та Properties.
==Додаткова література==
* [http://idndist.lp.edu.ua/moodle/library/books/0021/index06.html Плешко Д.Д. Лекція VІ. Колекції. (Об'єктно-орієнтоване програмування в Java)]
* [https://www.geeksforgeeks.org/collections-in-java-2/ Колекції в Java(англ)]
* [https://dzone.com/articles/working-with-hashcode-and-equals-in-java Робота з hashcode() та equals() (англ)]
* [https://docs.oracle.com/javase/8/docs/technotes/guides/collections/overview.html Огляд структори колекцій(англ)]
* [https://ukr-technologies.blogspot.com/search/label/Колекції Колекції Java]
{{Гортання сторінок|Графічний інтерфейс користувача|Менеджери розташування}}
[[Категорія:Освоюємо Java]]
baw46zc5wihy7kaokyk14tdihk7ul7a
36854
36853
2022-08-03T12:00:47Z
Володимир Груша
985
/* Клас TreeMap */
wikitext
text/x-wiki
При об’єктно орієнтованому програмуванні доводиться працювати з великою кількістю об’єктів. Зручно мати засоби групування об’єктів. Для цих цілей в Java розроблено набір інтерфейсів і класів на їх основі під назвою колекції . В основі ієрархії колекцій знаходиться інтерфейс Collection.
==Структура колекцій==
Згадаймо, що інтерфейс – це клас, який не містить реалізації методів, а лише їхні оголошення. Можна реалізувати безліч реалізацій інтерфейсу. Програмісту, який використовуватиме ці реалізації, достатньо знати базовий інтерфейс для роботи з його реалізаціями, тобто знати методи, які передбачає даний інтерфейс.
Collection – базовий інтерфейс, крім нього на його основі в структурі колекцій є ще декілька інтерфейсів, які розширюють базовий інтерфейс Collection. Зокрема, List, Set та SortedSet. Окремо виділяють ще інтерфейс Map. Він не походить на пряму від інтерфейсу Collection, проте його також відносять до колекцій. На їх основі створено набір класів, які згодяться програмістам для більшості випадків роботи з набором об’єктів. Тож вам не прийдеться самим їх реалізовувати.
Якщо вам цікаво, для чого стільки різних класів в колекціях? Суть в тому, що різні класи по різному реалізовують роботу з даними. Одні класи швидше здійснюють читання даних, інші вставлення і видалення, одні перевіряють, щоб не було дублювань, інші дозволяють вставляти дані за певним ключем і т.п. Доволі важливо підібрати клас, який найкраще підходить для вашого завдання і забезпечить найбільшу швидкодію. Особливо це актуально, коли кількість об’єктів величезна.
==Реалізації інтерфейсу Collection==
===Клас ArrayList та використання ітератора===
Клас ArrayList призначений для читання об'єктів по індексу. Тож не дарма у назві є слово Array (масив). Після створення колекції на основі ArrayList, прочитати дані можна кількома способами. Наступний приклад демонструє створення ArrayList, його наповнення об'єктами типу String та їх читання за допомогою методу get (int index) та за допомогою ітератора.
<syntaxhighlight lang="java">
import java.util.ArrayList;
import java.util.ListIterator;
public class TestArrayList {
private ArrayList<String> a1;
public static void main(String[] args) {
TestArrayList test = new TestArrayList();
test.create();
test.getData();
test.iterateData();
}
void create() {
//створюємо і наповнюємо ArrayList
a1 = new ArrayList<String>();
a1.add("Привіт");
a1.add("тобі");
a1.add("божевільний");
a1.add("світе!");
}
//читаємо дані по індексу
void getData() {
for (int i = 0; i < a1.size(); i++) {
System.out.print(a1.get(i) + " ");
}
}
//Читаємо вміст ArrayList з допомогою ітератора
void iterateData() {
ListIterator<String> it = a1.listIterator();
while (it.hasNext()) {
System.out.print(it.next() + " ");
}
}
}
</syntaxhighlight>
Результат:
<PRE>Привіт тобі божевільний світе! Привіт тобі божевільний світе!</PRE>
Крім вищенаведених способів можна передати вміст ArrayList у звичайний масив за допомогою методу toArray(). Якщо ви хочете детально розібратися з ArrayList і його методами, то для цього також дивіться інформацію про інтерфейси Collection, List та Iterator.
Окремо розглянемо перегляд даних з допомогою ітератора.
<syntaxhighlight lang="java">ListIterator<String> it=a1.listIterator();</syntaxhighlight>
Таким чином створюється об’єкт ітератора, посилання на який передається об'єктній змінній it типу ListIterator. ListIterator – це інтерфейс, який розширює інтерфейс Iterator декількома новими методами. Базовими ж методами інтерфейсу Iterator є ті, що використані у нас в програмі, а саме:
* boolean hasNext() – повертає true, якщо ітерація має наступний елемент
* E next() - повертає наступний елемент ітерації (буква E вказує, що це може бути елемент будь-якого типу, детальніше див. розділ [[Освоюємо_Java/Узагальнення|Узагальнення]])
* void remove() – знищує останній елемент, що повертався ітератором
Тож у коді бачимо:
<syntaxhighlight lang="java">
while(it.hasNext()){
System.out.print(it.next()+" ");
}
</syntaxhighlight>
Цикл працює поки є елементи в ітераторі. Перевірка здійснюється за допомогою методу hasNext. А вивід елементів здійснюється за допомогою методу next. Перевірка за допомогою hasNext необхідна через те, що в разі відсутності наступного елементу при виклику методу next буде викинуто виняток NoSuchElementExeption.
Інтерфейсом ListIterator передбачено ще такі методи як add, hasPrevious, next, nextIndex, previous, previousIndex, set. Назви методів говорять самі за себе. Детальніше ви можете подивитися в документації по інтерфейсу ListIterator.
Клас Itr, який реалізовує інтерфейс ListIterator є внутрішнім класом класу AbstractList. ArrayList є нащадком класу AbstractList.
Для того, щоб ітератор міг працювати з певним об’єктом, клас даного об’єкту повинен реалізовувати інтерфейс Iterable:
<syntaxhighlight lang="java">
public interface Iterable<E>
{
Iterator<E> iterator();
}
</syntaxhighlight>
Інтерфейс Collection розширює даний інтерфейс.
Можна також перебрати елементи за допомогою перевантаженого з виходом java 5 циклу for (так званого “for each”):
<syntaxhighlight lang="java">
for (String str : a1) {
System.out.print(str+" ");
}
</syntaxhighlight>
При компіляції даний цикл перетворюється компілятором у цикл із ітератором.
ArrayList можна також перетворити у звичайний масив за допомогою методу toArray():
<syntaxhighlight lang="java">
String strArray[]= new String[a1.size()];
strArray=a1.toArray(strArray);
System.out.println(strArray[0]);
</syntaxhighlight>
Якщо ви погано розумієте вищенаведений приклад і як усе працює зверніться до розділів, що описують основні концепції об’єктно-орієнтованого програмування і, зокрема, розберіть детально теми інтерфейсів, абстрактних класів та поліморфізму.
===Клас LinkedList===
LinkedList — це структура даних, що являє собою пов’язаний список елементів (об’єктів).
Різниця між ArrayList та LinkedList полягає в тому, що ArrayList реалізований у вигляді масиву, а LinkedList у вигляді пов’язаних між собою об’єктів. ArrayList швидко виконує читання і заміну елементів (посилань на об’єкти), проте, щоб вставити новий елемнт в середину ArrayList або видалити існуючий в середині ArrayList здійснюється послідовний зсув цілого ряду елементів масиву. В LinkedList доволі швидко відбувається вставлення нового елементу або видалення існуючого. Це відбувається тому, що в середині реалізації LinkedList змінюються лише посилання на попередній і наступний об’єкти (елементи). Проте доступ до об’єктів по індексу в LinkedList відбувається повільніше ніж в ArrayList. Тож загалом, LinkedList корисний, коли необхідно часто вставляти та видаляти елементи зі списку, а в інших випадках краще використовувати ArrayList.
Існує два конструктури LinkedList:
<syntaxhighlight lang="java">
LinkedList()
LinkedList (Collection c)
</syntaxhighlight>
Перший конструктор створює пустий список, а другий – створює пов’язаний список із іншої колекції.
Клас LinkedList розширює клас AbstractSequentalList та реалізує інтерфейси List, Dequeue та Queue. Реалізація останніх двох інтерфейсів (черг) означає, що ми можемо працювати із пов’язаним списком як із стеком з використанням методів pop(), push(), poll(), pollFirst(), pollLast() і т.п. Детальніше дивіться документацію по заданим інтерфейсам.
Далі попрацюємо з LinkedList, який міститиме в якості елементів об’єктні змінні типу Car.
Спочатку реалізуємо наш клас Car:
<syntaxhighlight lang="java">
public class Car {
private String name;
private double price;
private int year;
public Car(String name, double price, int year) {
this.name = name;
this.price = price;
this.year=year;
}
@Override
public String toString() {
return "\n Car [name=" + name + ", price=" + price + ", year=" + year
+ "]";
}
}
</syntaxhighlight>
Клас Car містить лише поля, конструктор, який заповнює дані поля та заміщений метод toString(), який видаватиме нам інформацію про автомобіль у вигляді рядка.
Наступний клас демонструє роботу з LinkedList:
<syntaxhighlight lang="java">
import java.util.ArrayList;
import java.util.LinkedList;
public class TestLinkedList {
private LinkedList<Car> ll=new LinkedList<>();
public static void main(String[] args) {
TestLinkedList t=new TestLinkedList();
t.test();
}
void test(){
Car car1=new Car("Ferrary", 10800, 1995);
Car car2=new Car("Запорожець", 2600, 1989);
ll.add(car1);
ll.add(car2);
//додаємо в початок списку
ll.addFirst(new Car("Alfa Romeo 155", 11678, 2000));
ll.remove(car2); // видалити об'єкт
System.out.println("Після видалення car2: "+ll);
ll.remove(1); //видалити елемент за індексом
System.out.println("Після видалення першого елементу: "+ll);
Car myCar=ll.get(0);
System.out.println("Отриманий елемент за індексом [0]:"+myCar);
ll.set(0, car1); //замінити елемент за індексом
System.out.println("Замінений елемент за індексом [0]"+ll.get(0));
ArrayList<Car> arrList=new ArrayList<Car>();
arrList.add(car1);
arrList.add(car2);
ll.addAll(arrList); //додаємо вміст ArrayList у наш LinkedList
System.out.println("Після додавання ArrayList:"+ll);
}
}
</syntaxhighlight>
Результат виконання програми:
<PRE>
Після видалення car2: [
Car [name=Alfa Romeo 155, price=11678.0, year=2000],
Car [name=Ferrary, price=10800.0, year=1995]]
Після видалення першого елементу: [
Car [name=Alfa Romeo 155, price=11678.0, year=2000]]
Отриманий елемент за індексом [0]:
Car [name=Alfa Romeo 155, price=11678.0, year=2000]
Замінений елемент за індексом [0]
Car [name=Ferrary, price=10800.0, year=1995]
Після додавання ArrayList:[
Car [name=Ferrary, price=10800.0, year=1995],
Car [name=Ferrary, price=10800.0, year=1995],
Car [name=Запорожець, price=2600.0, year=1989]]
</PRE>
Перебирати елементи LinkedList також можна з допомогою ітератора та у циклі for earch.
Детальніше про методи класу дивіться документацію по класу [https://docs.oracle.com/javase/9/docs/api/java/util/LinkedList.html LinkedList].
===Клас HashSet===
HashSet – це клас призначений для зберігання даних у вигляді множини невпорядкованих елементів. Якщо потрібна впорядкована множина, то використовуйте TreeSet. HashSet також не гарантує стабільного порядку збереження об’єктів. Тобто при додаванні об’єктів порядок зберігання елементів змінюється. Вони можуть бути збережені як в кінці множити так і в середині. Якщо потрібен один порядок зберігання об’єктів використовуйте LinkedHashSet.
Сам термін «множина» означає, що елементи не будуть повторюватися. Для зберігання і пошуку елементів використовується хеш-код об’єкта. HashSet також може містити значення null. Власне всередині самої реалізації HashSet використовується клас HashMap, який дозволяє зберігати елементи у вигляді двох складових ключа та хеш-коду. У класі HashSet хеш-код недоступний і використовується неявно для користувача.
Клас HashSet розширює клас AbstractSet та реалізує інтерфейс Set. Також реалізовує інтерфейси Serializable та Clonable.
HashSet має такі конструктори:
<pre>
HashSet()
HashSet (Collection c)
HashSet (int об’єм)
HashSet (int об’єм, float коефіцієнт_заповнення)
</pre>
Коефіцієнт заповнення – це число в межах 0.0 до 1.0, що представляє собою частку заповнення HashSet при якій об’єм HashSet буде збільшений. По замовчуванню в конcтрукторах, що не задають коефіцієнт заповнення, використовується значення 0.75.
Наступний приклад демонструє роботу із HashSet.
<syntaxhighlight lang="java">
import java.util.HashSet;
public class TestHashSet {
HashSet<String> hs=new HashSet<String>();
public static void main(String[] args) {
TestHashSet test=new TestHashSet();
test.test();
}
void test(){
hs.add("Австралія");
hs.add("Україна");
hs.add("США");
System.out.println("1) Три країни: "+hs+" розмір="+hs.size());
hs.add("Австралія"); // помилки не буде, але в HashSet нічого не поміняється
System.out.println("2) Після спроби додати Авcтралію ще раз: "+hs);
hs.remove("США"); //видаляємо США з множини
hs.add("Німеччина");
hs.add("Англія");
hs.add(null);
hs.add(null); // другий раз не додаситься
System.out.println("3)"+hs);
System.out.println("4) Чи містить множина Німеччину? "+hs.contains("Німеччина"));
System.out.println("5) Множина пуста? "+hs.isEmpty());
//можемо також отримати ітератор, або ж перебрати множину у for earch
for (String str:hs){
System.out.println(str);
}
hs.clear(); // очистити
System.out.println("6) Розмір після очищення="+hs.size());
}
}
</syntaxhighlight>
Результат виконання:
<pre>
1) Три країни: [Австралія, Україна, США] розмір=3
2) Після спроби додати Австралію ще раз: [Австралія, Україна, США]
3)[null, Австралія, Німеччина, Україна, Англія]
4) Чи містить множина Німеччину? true
5) Множина пуста? false
null
Австралія
Німеччина
Україна
Англія
6) Розмір після очищення=0
</pre>
Зробити копію хеш множини можна так:
<pre>
HashSet<String> hsc=(HashSet)hs.clone();
</pre>
Слід зауважити, що метод clone() здійснює поверхневе (shadow) копіювання, тобто копіюються лише адреси об’єктів, які містяться у екземплярі класу HashSet, а не самі об’єкти.
При використанні ітератор може викидати виняток ConcurrentModificationException, якщо HashSet було змінено. Щоб уникнути таких випадків слід використовувати методи ітератора для зміни HashSet.
Клас HashSet несинхронізоватий для багатопоточності, проте його можна синхронізувати використовуючи метод synchronizedSet класу Collections:
<pre>
Set s = Collections.synchronizedSet (new HashSet (...))
</pre>
У класу String перевизначені такі методи як equal та hashcode, що дає можливість коректного порівняння їхніх хеш-кодів та значень і уникати випадків, коли будуть додаватися ідентичні рядки, незалежно від того, чи вони зберігаються в різних комірках пам’яті. Проте при використанні власних класів, на практиці для правильного функціонування HashSet (без повторення об'єктів з однаковим станом, наприклад, ідентичними полями) у класах необхідно замістити методи equals() та hashcode() самому. Так, якщо ми створимо класи оболонки, що міститимуть String поле countryName із однаковим значенням, наприклад, “Австрія”, то у нас два об'єкти вважатимуться різні, оскільки у них буде різний Хеш-код, тож вони будуть додані до HashSet. В таких випадках необхідно продумати методи equals() та hashcode().
===Клас LinkedHashSet===
Клас <code>LinkedHashSet</code> розширює клас HashSet не додаючи ніяких нових методів. Працює він дещо довше за HashSet проте зберігає порядок в якому елементи додаються до нього. Відповідно це дозволяє організувати послідовну ітерацію вставлення та витягнення елементів. Всі конструктори та методи роботи з LinkedHashSet аналогічні методам класу HashSet.
===Клас TreeSet===
Клас TreeSet дозволяє створювати відсортовану множину. Тобто елементи не повторюються та зберігаються у відсортованому порядку. Для зберігання елементів застосовується бінарна деревоподібна структура. Об'єкти зберігаються в відсортованому порядку по зростанню. Час доступу та одержання елементів доволі малий, тому клас TreeSet підходить для зберігання великих об’ємів відсортованих даних, які повинні бути швидко знайдені.
Клас TreeSet розширює клас AbstractSet та реалізує інтерфейс NavigableSet. NavigableSet реалізується на базі TreeMap.
В класі доступні чотири конструктори:
<syntaxhighlight lang="java">
TreeSet ()
TreeSet(Collection с)
TreeSet(Comparator компаратор)
TreeSet(SortedSet ss)
</syntaxhighlight>
Третій конструктор дозволяє задавати власний компаратор, відповідно до якого буде відбуватися сортування об’єктів. Так об’єкти класу String не потребують реалізації власного компаратора, проте якщо ви хочете зберігати в класі TreeSet розроблені вами об’єкти, то потрібно задавати компаратор для цих об’єктів. Такий компаратор може реалізовувати сортування об’єктів по певному полю, наприклад по Прізвищу, якщо ваш клас зберігаю інформацію про осіб. Можна реалізувати ланцюжок компараторів з використанням методу thenComparing() класу Comparator.
TreeSet не може містити значення null. Також TreeSet не синхронізований клас, як і інші класи колекцій при потребі його потрібно синхронізувати з використанням методу Collections.synchronizedSet().
Розглянемо приклад роботи TreeSet з компаратором. Використаємо клас Car, який був попередньо використаний при роботі з LinkedList додавши лише гетер та сетер методи.
<syntaxhighlight lang="java">
public class Car {
private String name;
private double price;
private int year;
public Car(String name, double price, int year) {
this.name = name;
this.price = price;
this.year=year;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
@Override
public String toString() {
return "\n Car [name=" + name + ", price=" + price + ", year=" + year+ "]";
}
}
</syntaxhighlight>
Клас компаратора CarsComparator виглядає так:
<syntaxhighlight lang="java">
import java.util.Comparator;
public class CarsComparator implements Comparator {
@Override
public int compare(Car car1, Car car2) {
if(car1.getYear() > car2.getYear())
return 1;
else if (car1.getYear() < car2.getYear())
return -1;
else return 0;
}
}
</syntaxhighlight>
Наша програма з TreeSet:
<syntaxhighlight lang="java">
import java.util.Comparator;
import java.util.TreeSet;
public class TestTreeSet{
CarsComparator comp=new CarsComparator();
TreeSet<Car> ts1=new TreeSet<>(comp);
public static void main(String[] args) {
TestTreeSet t=new TestTreeSet();
t.test();
}
void test(){
Car car1=new Car("Ferrary", 12000, 1988);
Car car2=new Car("Ford", 13000, 1955);
Car car3=new Car("Toyota", 13500, 2003);
Car car4=new Car("Citroen", 12000, 2014);
Car car5=new Car("Mercedes-Benz", 15000, 2011);
ts1.add(car1);
ts1.add(car2);
ts1.add(car3);
ts1.add(car4);
ts1.add(car5);
System.out.println("Сортування по роках: "+ts1);
//Зворотній компаратор для TreeSet(Java8)
TreeSet<Car> ts2=new TreeSet<>(comp.reversed());
ts2.addAll(ts1); //додати вміст попереднього TreeSet у новий
System.out.println("Зворотнє сортування:"+ts2);
}
}
</syntaxhighlight>
Результат виконання:
<pre>
Сортування по роках: [
Car [name=Ford, price=13000.0, year=1955],
Car [name=Ferrary, price=12000.0, year=1988],
Car [name=Toyota, price=13500.0, year=2003],
Car [name=Mercedes-Benz, price=15000.0, year=2011],
Car [name=Citroen, price=12000.0, year=2014]]
Зворотнє сортування:[
Car [name=Citroen, price=12000.0, year=2014],
Car [name=Mercedes-Benz, price=15000.0, year=2011],
Car [name=Toyota, price=13500.0, year=2003],
Car [name=Ferrary, price=12000.0, year=1988],
Car [name=Ford, price=13000.0, year=1955]]
</pre>
Реалізація інтерфейсу NavigableSet забезпечила клас TreeSet доволі корисними методами як то ceiling(), floor(), headset(), higher(), pollFirst(), pollLast(), subset(), tailSet(), iterator(), descendingIterator(), descendingSet(). Використовуючи їх можна організувати доволі зручний вибір елементів з TreeSet. Див. детальніше документацію по TreeSet.
===Клас PriorityQueue===
PriorityQueue дозволяє реалізувати чергу на основі пріоритету. Така черга може бути корисна, наприклад, у разі необхідності обслуговування клієнтів згідно пріоритету. При зберіганні чисел в пріоритетній черзі, така черга гарантує, що першим елементом завжди буде найменший елемент. При цьому не гарантується ніякий стабільний послідовний порядок збереження елементів. Після додавання або видалення елементу з пріоритетної черги, порядок зберігання елементів в цій черзі змінюється таким чином, що в голові черги опиняється найменший елемент згідно його природнього порядку або згідно заданого компаратора.
<syntaxhighlight lang="java">
PriorityQueue має наступні конструктори:
PriorityQueue() //початковий об’єм становить 11
PriorityQueue(int початковий_об’єм)
PriorityQueue(Comparator comparator)
PriorityQueue(int початковий_об'єм, Comparator компаратор)
PriorityQueue(Collection с)
PriorityQueue(PriorityQueue с)
PriorityQueue(SortedSet с)
</syntaxhighlight>
Таким чином в разі потреби можна задати власний компаратор для видачі елементів у потрібному нам порядку.
PriorityQueue не може містити null. PriorityQueue розширює AbstractQueue та реалізує інтерфейси Serializable, Iterable, Collection, Queue.
Реалізація інтерфейсу Queue говорить нам, що в PriorityQueue доступні такі методи роботи з чергою:
*add(E e) – додати вказаний елемент у чергу
*element() – отримати, але не видаляти, елемент з голови черги
*offer(E e)- додати визначений елемент у чергу
*peek() – отримати елемент з голови черги, але не видаляти його. Повертає null, якщо черга порожня
*poll() – отримати та видалити елемент з голови черги
*remove() - отримати та видалити елемент з голови черги
Крім того в PriorityQueue достуні методи, що наявні і в інших колекціях як то: clear(), comparator(), contains(), iterator(), spliterator(), size(), toArray() тощо.
Приклад:
<syntaxhighlight lang="java">
import java.util.PriorityQueue;
public class TestPriorityQueue {
public static void main(String[] args) {
PriorityQueue<Integer> pq= new PriorityQueue<>(11);
pq.add(750);
pq.add(50);
pq.offer(1);
pq.add(300);
pq.add(25);
pq.add(2);
pq.offer(20);
pq.add(5);
pq.add(40);
System.out.println("Порядок зберігання елементів"+pq);
// Отримуємо і видаляємо елемент з голови черги
while (!pq.isEmpty()) {
System.out.println("Отримали: "+pq.poll());
System.out.println("Новий порядок:"+pq);
}
}
}
</syntaxhighlight>
Результат:
<pre>
Порядок зберігання елементів[1, 5, 2, 25, 300, 50, 20, 750, 40]
Отримали: 1
Новий порядок:[2, 5, 20, 25, 300, 50, 40, 750]
Отримали: 2
Новий порядок:[5, 25, 20, 750, 300, 50, 40]
Отримали: 5
Новий порядок:[20, 25, 40, 750, 300, 50]
Отримали: 20
Новий порядок:[25, 50, 40, 750, 300]
Отримали: 25
Новий порядок:[40, 50, 300, 750]
Отримали: 40
Новий порядок:[50, 750, 300]
Отримали: 50
Новий порядок:[300, 750]
Отримали: 300
Новий порядок:[750]
Отримали: 750
Новий порядок:[]
</pre>
Таким чином за допомогою методу poll() (його можна також замінити методом remove()), ми можемо отримувати елементи масиву у відсортованому порядку, незважаючи на те, що в самій пріоритетній черзі елементи зберігаються у іншому порядку.
===Клас ArrayDeque===
ArrayDeque (читається як аррейдек) – це клас який забезпечує двосторонню чергу. Іншими словами - це автоматично зростаючий масив, що дозволяє нам додавати або видаляти елементи з обох боків черги. ArrayDeque може бути використано як стек (LIFO, останній ввійшов - перший вийшов) або ж як черга (FIFO, перший ввійшов - перший вийшов).
ArrayDeque не може містити в якості елемента null.
Клас ArrayDeque швидший за клас Stack, якщо використовувати його в якості стеку і швидший за LinkedList, якщо використовувати в якості черги.
ArrayDeque розширює клас AbstractCollection та реалізує інтерфейси Deque, Cloneable, Serializable. Таким чином ми можемо використовувати для роботи з даним класом, як методи інтерфейсу Deque (який розширює інтерфейс Queue) так і методи інтерфейсу Collection.
Якщо використовується ітератор, то він буде викидати виняток ConcurrentModificationException, якщо вміст ArrayDeque був модифікований після створення ітератора. Таким чином ітератор необхідно з обережністю використовувати з ArrayDeque.
В ArrayDeque доступні наступні конструктори:
<syntaxhighlight lang="java">
ArrayDeque() // пустий ArrayDeque з початковим об’ємом 16 елентів
ArrayDeque(Collection c) // міститиме елементи колекції в порядку, що повертає ітератор даної колекції
ArrayDeque(int numElements) // дозволяє задати початковий об’єм
</syntaxhighlight>
При потребі збільшення об'єму, то він автоматично збільшується вдвічі.
Наступний приклад демонструє роботу із ArrayDeque у вигляді стека та у в вигляді черги:
<syntaxhighlight lang="java">
import java.util.ArrayDeque;
public class TestArrayDeque {
public static void main(String[] args) {
ArrayDeque<String> ad=new ArrayDeque<>();
System.out.println("Використання в якості стеку");
ad.push("Перший"); // метод інтерфуйсу Deque
ad.push("Другий");
ad.push("Третій");
System.out.println("Перший елемент ArrayDeque: "+ad.getFirst());//Отримуємо перший елемент, але не видаляємо
System.out.println("Вміст ArrayDeque: "+ad);
System.out.println(ad.pop()); //Отримуємо і видаляємо з вершини стеку
System.out.println(ad.pop()); //еквівалентно до removeFirst()
System.out.println(ad.pop());
//System.out.println(ad.pop()); //ArrayDeque порожній видасть NoSuchElementException
System.out.println();
System.out.println("Використання в якості черги");
ad.offer("Перший");
ad.offer("Другий");
ad.offer("Третій");
System.out.println("Перший елемент ArrayDeque: "+ad.getFirst());//Отримуємо перший елемент, але не видаляємо
System.out.println("Вміст ArrayDeque: "+ad);
System.out.println(ad.poll()); //витягнути і видалити з голови
System.out.println(ad.poll());
System.out.println(ad.poll());
System.out.println(ad.poll());
}
}
</syntaxhighlight>
Результат роботи:
<pre>
Використання в якості стеку
Перший елемент ArrayDeque: Третій
Вміст ArrayDeque: [Третій, Другий, Перший]
Третій
Другий
Перший
Використання в якості черги
Перший елемент ArrayDeque: Перший
Вміст ArrayDeque: [Перший, Другий, Третій]
Перший
Другий
Третій
null
</pre>
Дивіться також офіційну документацію по: [https://docs.oracle.com/javase/8/docs/api/java/util/Deque.html Інтерфейсу Deque] та
[https://docs.oracle.com/javase/8/docs/api/java/util/Collection.html Інтерфейсу Collection]
===Клас EnumSet===
Клас EnumSet — це одна з спеціалізованих реалізацій інтерфейсу Set для використання з перелічуваним типом даних (enum). EnumSet розширює AbstractSet та реалізує Cloneable та Serializable інтерфейси Java. EnumSet заміщує більшість методів інтерфейсів Set та Collection. EnumSet доволі швидка реалізація Set, швидша за HashSet, тому що всередині використовуються побітові операції, а не хеш-коди об’єктів.
EnumSet не синхронізований і повинен бути синхронізований ззовні, наприклад з використанням методу Collections.synchronizedSet(java.util.Set).
Всі елементи enum множини мають походити від єдиного перелічуваного типу, що вказується, коли множина створюється явно або неявно. EnumSet не дозволяє додавати значення null. Елементи зберігаються в порядку в якому їх подано в переліченні (enum).
EnumSet використовує безвідмовний (fail-safe) ітератор, що працює з копією EnumSet, тобто ітератор не буде викидати виняток ConcurrentModificationException, в разі зміни даних множини поза ітератором.
EnumSet – це відкритий абстрактний клас, який не має відкритого конструктора, для створення об’єкту EnumSet використовуються відповідні статичні факторні методи. В даних методах для створення EnumSet використовуються дві реалізації даного класу RegularEnumSet(для зберігання невеликих перелічень, до 64) та JumboEnumSet (для зберігання великих перелічень). Наступний приклад демонструє роботу з EnumSet:
<syntaxhighlight lang="java">
import java.util.EnumSet;
enum Colors
{
RED, GREEN, YELLOW, BLUE, BLACK
};
public class TestEnumSet
{
public static void main(String[] args)
{
// Створюємо множину
EnumSet<Colors> set1, set2, set3, set4, set5;
// Додаємо окремі елементи, порядок зберігання буде згідно порядку перелічення
set1 = EnumSet.of(Colors.RED, Colors.GREEN,
Colors.BLACK, Colors.BLUE);
// Заповнити тими елемнтами, яких нема у вказаній множині
set2 = EnumSet.complementOf(set1);
// Всі із даного перелічення
set3 = EnumSet.allOf(Colors.class);
// Додати усі елементи перелічення в діапазоні від GREEN до BLACK
set4 = EnumSet.range(Colors.GREEN, Colors.BLACK);
// створити пусту множину перелічень відповідного типу
set5= EnumSet.noneOf(Colors.class);
System.out.println("Set 1: " + set1);
System.out.println("Set 2: " + set2);
System.out.println("Set 3: " + set3);
System.out.println("Set 4: " + set4);
System.out.println("Set 5: " + set5);
}
}
</syntaxhighlight>
Результат роботи:
<pre>
Set 1: [RED, GREEN, BLUE, BLACK]
Set 2: [YELLOW]
Set 3: [RED, GREEN, YELLOW, BLUE, BLACK]
Set 4: [GREEN, YELLOW, BLUE, BLACK]
Set 5: []
</pre>
==Інтерфейс Map та класи, що його реалізують==
'''''Зіставлення''''' (англ. ''map'', також перекладають як ''відображення'')– це об’єкт який зіставляє ключ із відповідним значенням (key/value). Маючи ключ ви можете знайти його значення. І ключ, і значення є об’єктами. Ключ може бути унікальним, а значення може повторюватися. Деякі зіставлення можуть приймати null ключ і null значення, інші не можуть.
Зіставлення не підтримують Iterable інтерфейс. Тому ви не зможете використати ітератор для перебору вмісту зіставлення. Також ви не можете використовувати цикл for each. Проте можна перетворити зіставлення у інший тип колекції і вже на ньому можна отримати ітератор.
Основу зіставлень складає інтерфейс '''Map'''.
Map є узагальненим (див. розділ [[Освоюємо Java/Узагальнення|Узагальнення]]) і оголошений так:
<code>
interface Map<K, V>
</code>
де K – визначає тип ключа, а V визначає тип значення.
Інтерфейс '''SortedMap''' розширює інтерфейс Map і забезпечує, що вміст зберігається в порядку зростання, базуючись на значенні ключа.
Інтерфейс '''NavigableMap''' розширює SortedMap і забезпечує повернення вмісту базуючись на схожості ключа або ключів.
Інтерфейс '''Map.Entry''' – вкладений в Map інтерфейс і забезпечує роботу із вмістом зіставлення.
Класи, що реалізують інтерфейс Map наведені в таблиці.
{| class="wikitable" style="text-align: left; width: 800px;"
!Клас||Опис
|-
|AbstractMap ||Реалізує більшість інтерфейсу Map
|-
|EnumMap ||Розширює AbstractMap для використання з перелічуваними ключами.
|-
|HashMap ||HashMap розширює AbstractMap, щоб використовувати хеш таблиці.
|-
|TreeMap ||TreeMap розширює AbstractMap для використання дерев.
|-
|WeakHashMap ||WeakHashMap розширює AbstractMap для використання слабких ключів, що забезпечує утилізацію невикористовуваних ключів збирачем мусору
|-
|LinkedHashMap ||LinkedHashMap розширює HashMap дозволяючи ітерацію з вводом елементів в певному порядку
|-
|IdentityHashMap ||IdentityHashMap розширює AbstractMap і використовує рівність посилань при порівнянні документів
|}
===Клас HashMap===
HashMap розширює AbstractMap та реалізує інтерфейс Map. Клас не додає власних методів. Клас використовує хеш таблиці для зберігання зіставлення. HashMap не гарантує порядок елементів.
<code>
HashMap має наступні конструктори:
HashMap( )
HashMap(Map<? extends K, ? extends V> m)
HashMap(int capacity)
HashMap(int capacity, float fillRatio)
</code>
Перший створює HashMap по замовчуванню. Другий створює хеш зіставлення використовуючи елементи m. Третій задає ємність хеш зіставлення. Четвертий задає ємність(по замовчуванню 16) та коефіцієнт заповнення (по замовчуванню 0.75).
<syntaxhighlight lang="java">
package Map;
import java.util.HashMap;
import java.util.*;
import java.util.Set;
public class TestHashMap {
public static void main(String[] args) {
// створюємо об'єкт HashMap з назвою capitalCities
HashMap<String, String> capitalCities = new HashMap<String, String>();
// додаємо ключі і значення (Країна, Столиця)
capitalCities.put("Англія", "Лондон");
capitalCities.put("Німеччина", "Берлін");
capitalCities.put("Норвегія", "Осло");
capitalCities.put("США", "Вашингтон");
//вивести значення об'єкту capitalCities
System.out.println(capitalCities);
//звернутися до HashMap використовуючи ключ
System.out.println(" Отримати столицю США");
System.out.println(capitalCities.get("США"));
//Видалити Англію
System.out.println(" Видаляємо Англію");
capitalCities.remove("Англія");
System.out.println(capitalCities);
//видалити все можна так
//capitalCities.clear();
// друкуємо ключі
System.out.println(" Ключі:");
for (String i : capitalCities.keySet()) {
System.out.println(i);
}
// друкуємо значення
System.out.println(" Значення:");
for (String i : capitalCities.values()) {
System.out.println(i);
}
// Друкувати ключі і значення
System.out.println(" Ключі і значення:");
for (String i : capitalCities.keySet()) {
System.out.println("key: " + i + " value: " + capitalCities.get(i));
}
System.out.println("Використовуємо Map.Entry");
//одержати множину входжень
Set<Map.Entry<String,String>> set=capitalCities.entrySet();
//вивести множину входжень
for(Map.Entry<String, String> me: set) {
System.out.print(me.getKey()+": ");
System.out.println(me.getValue());
}
}
}
</syntaxhighlight>
Результат:
<pre>
{США=Вашингтон, Англія=Лондон, Норвегія=Осло, Німеччина=Берлін}
Отримати столицю США
Вашингтон
Видаляємо Англію
{США=Вашингтон, Норвегія=Осло, Німеччина=Берлін}
Ключі:
США
Норвегія
Німеччина
Значення:
Вашингтон
Осло
Берлін
Ключі і значення:
key: США value: Вашингтон
key: Норвегія value: Осло
key: Німеччина value: Берлін
Використовуємо Map.Entry
США: Вашингтон
Норвегія: Осло
Німеччина: Берлін
</pre>
Ключі і значення в HashMap є об’єктами. Якщо ми хочемо використати, наприклад, числа цілого типу (іnt) то використовуватиметься клас обгортка Integer. Так само і для інших примітивних типів.
===Клас TreeMap===
Клас '''TreeMap''' розширює '''AbstractMap''' та реалізує інтерфейс '''NavigableMap'''. TreeMap не містить методів крім тих, що визначені у NavigableMap та класі AbstractMap. Що забезпечує зберігання зіставлень за допомогою деревовидної структури. TreeMap забезпечує зберігання пар ключ/значення у відсортованому порядку (в порядку зростання), що забезпечує швидкий доступ до елементів. TreeMap по замовчуванню сортується за ключами. Для задання іншого сортування використовують компаратор.
TreeMap узагальнений клас і оголошується так:
<code>
class TreeMap<K,V>
</code>
де K – задає тип ключа, а V – задає тип значення.
TreeMap визначає наступні конструктори:
<pre>
TreeMap( )
TreeMap(Comparator<? super K> comp)
TreeMap(Map<? extends K, ? extends V> m)
TreeMap(SortedMap<K, ? extends V> sm)
</pre>
Перший створює пусте деревовидне зіставлення, що буде відсортоване використовуючи природній порядок ключів. Другий створює пусте зіставлення, що буде відсортоване використовуючи компаратор. Третій створює деревовидне зіставлення із входжень зіставлення m, що буде відсортоване в природньому порядку. Третій ініціалізує деревовидне зіставлення входженнями із sm з порядком сортуванням того ж sm.
<syntaxhighlight lang="java">
package Map;
import java.util.TreeMap;
import java.util.*;
public class TestTreeMap {
public static void main(String[] args) {
TreeMap<String, Integer> countries = new TreeMap<String, Integer>();
countries.put("Гваделупа",1);
countries.put("США",2);
countries.put("Гаваї",3);
countries.put("Бельгія", 4);
//вивести вміст
System.out.println(countries);
//вивести останній ключ
System.out.println("Останній ключ:"+countries.lastKey());
countries.put("Албанія", 5);
System.out.println(" Вміст зіставлення:");
// взяти множину входжень
Set<Map.Entry<String, Integer>> set = countries.entrySet();
// Вивести елементи
for(Map.Entry<String, Integer> me : set) {
System.out.print(me.getKey() + ": ");
System.out.println(me.getValue());
}
System.out.println();
}
}
</syntaxhighlight>
Результат:
<pre>
{Бельгія=4, Гаваї=3, Гваделупа=1, США=2}
Останній ключ:США
Вміст зіставлення:
Албанія: 5
Бельгія: 4
Гаваї: 3
Гваделупа: 1
США: 2
</pre>
(потребує доповнення)
==Алгоритми==
В структурі колекцій існує клас Collections, який надає ряд зручних статичних методів для роботи з даними. Нагадаємо, що статичні методи – це методи, які не потребують створення об'єктів і реалізують ряд додаткових алгоритмів по роботі з колекціями, як то сортування колекцій, знаходження максимального і мінімального елементу, перемішування, копіювання і т.п.
(необхідно розширити)
==Arrays==
(Ще не написано)
==Успадковані класи ==
Ранні версії Java не включали структуру Collections. Там було визначено декілька класів та інтерфейсів, що надавали методи для зберігання об'єктів. Структура Collections була додана в Java 2. (j2se 1.2). Тоді початкові класи були перероблені для підтримки інтерфейсів колекцій. Ці ранні класи також знані як успадковані класи (Legacy classes). В Java 5 успадковані класи та інтерфейси були перероблені для підтримки узагальнень. Їх підтримують, тому що до сих пір існує код, який їх використовує. Успадковані класи - синхронізовані. Класи входять в пакет java.util. Успадкованими є наступні класи:
* Dictionary
* HashTable
* Properties
* Stack
* Vector
Успадкованим є інтерфейс Enumaration, на заміну якому прийшов інтерфейс Iterator. Enumaration інтерфейс до сих пір використовується в декількох методах класів Vector та Properties.
==Додаткова література==
* [http://idndist.lp.edu.ua/moodle/library/books/0021/index06.html Плешко Д.Д. Лекція VІ. Колекції. (Об'єктно-орієнтоване програмування в Java)]
* [https://www.geeksforgeeks.org/collections-in-java-2/ Колекції в Java(англ)]
* [https://dzone.com/articles/working-with-hashcode-and-equals-in-java Робота з hashcode() та equals() (англ)]
* [https://docs.oracle.com/javase/8/docs/technotes/guides/collections/overview.html Огляд структори колекцій(англ)]
* [https://ukr-technologies.blogspot.com/search/label/Колекції Колекції Java]
{{Гортання сторінок|Графічний інтерфейс користувача|Менеджери розташування}}
[[Категорія:Освоюємо Java]]
oyuqkc84kqjr9qv5hq07egko1nfot83
36856
36854
2022-08-03T17:43:59Z
Володимир Груша
985
/* Клас TreeMap */
wikitext
text/x-wiki
При об’єктно орієнтованому програмуванні доводиться працювати з великою кількістю об’єктів. Зручно мати засоби групування об’єктів. Для цих цілей в Java розроблено набір інтерфейсів і класів на їх основі під назвою колекції . В основі ієрархії колекцій знаходиться інтерфейс Collection.
==Структура колекцій==
Згадаймо, що інтерфейс – це клас, який не містить реалізації методів, а лише їхні оголошення. Можна реалізувати безліч реалізацій інтерфейсу. Програмісту, який використовуватиме ці реалізації, достатньо знати базовий інтерфейс для роботи з його реалізаціями, тобто знати методи, які передбачає даний інтерфейс.
Collection – базовий інтерфейс, крім нього на його основі в структурі колекцій є ще декілька інтерфейсів, які розширюють базовий інтерфейс Collection. Зокрема, List, Set та SortedSet. Окремо виділяють ще інтерфейс Map. Він не походить на пряму від інтерфейсу Collection, проте його також відносять до колекцій. На їх основі створено набір класів, які згодяться програмістам для більшості випадків роботи з набором об’єктів. Тож вам не прийдеться самим їх реалізовувати.
Якщо вам цікаво, для чого стільки різних класів в колекціях? Суть в тому, що різні класи по різному реалізовують роботу з даними. Одні класи швидше здійснюють читання даних, інші вставлення і видалення, одні перевіряють, щоб не було дублювань, інші дозволяють вставляти дані за певним ключем і т.п. Доволі важливо підібрати клас, який найкраще підходить для вашого завдання і забезпечить найбільшу швидкодію. Особливо це актуально, коли кількість об’єктів величезна.
==Реалізації інтерфейсу Collection==
===Клас ArrayList та використання ітератора===
Клас ArrayList призначений для читання об'єктів по індексу. Тож не дарма у назві є слово Array (масив). Після створення колекції на основі ArrayList, прочитати дані можна кількома способами. Наступний приклад демонструє створення ArrayList, його наповнення об'єктами типу String та їх читання за допомогою методу get (int index) та за допомогою ітератора.
<syntaxhighlight lang="java">
import java.util.ArrayList;
import java.util.ListIterator;
public class TestArrayList {
private ArrayList<String> a1;
public static void main(String[] args) {
TestArrayList test = new TestArrayList();
test.create();
test.getData();
test.iterateData();
}
void create() {
//створюємо і наповнюємо ArrayList
a1 = new ArrayList<String>();
a1.add("Привіт");
a1.add("тобі");
a1.add("божевільний");
a1.add("світе!");
}
//читаємо дані по індексу
void getData() {
for (int i = 0; i < a1.size(); i++) {
System.out.print(a1.get(i) + " ");
}
}
//Читаємо вміст ArrayList з допомогою ітератора
void iterateData() {
ListIterator<String> it = a1.listIterator();
while (it.hasNext()) {
System.out.print(it.next() + " ");
}
}
}
</syntaxhighlight>
Результат:
<PRE>Привіт тобі божевільний світе! Привіт тобі божевільний світе!</PRE>
Крім вищенаведених способів можна передати вміст ArrayList у звичайний масив за допомогою методу toArray(). Якщо ви хочете детально розібратися з ArrayList і його методами, то для цього також дивіться інформацію про інтерфейси Collection, List та Iterator.
Окремо розглянемо перегляд даних з допомогою ітератора.
<syntaxhighlight lang="java">ListIterator<String> it=a1.listIterator();</syntaxhighlight>
Таким чином створюється об’єкт ітератора, посилання на який передається об'єктній змінній it типу ListIterator. ListIterator – це інтерфейс, який розширює інтерфейс Iterator декількома новими методами. Базовими ж методами інтерфейсу Iterator є ті, що використані у нас в програмі, а саме:
* boolean hasNext() – повертає true, якщо ітерація має наступний елемент
* E next() - повертає наступний елемент ітерації (буква E вказує, що це може бути елемент будь-якого типу, детальніше див. розділ [[Освоюємо_Java/Узагальнення|Узагальнення]])
* void remove() – знищує останній елемент, що повертався ітератором
Тож у коді бачимо:
<syntaxhighlight lang="java">
while(it.hasNext()){
System.out.print(it.next()+" ");
}
</syntaxhighlight>
Цикл працює поки є елементи в ітераторі. Перевірка здійснюється за допомогою методу hasNext. А вивід елементів здійснюється за допомогою методу next. Перевірка за допомогою hasNext необхідна через те, що в разі відсутності наступного елементу при виклику методу next буде викинуто виняток NoSuchElementExeption.
Інтерфейсом ListIterator передбачено ще такі методи як add, hasPrevious, next, nextIndex, previous, previousIndex, set. Назви методів говорять самі за себе. Детальніше ви можете подивитися в документації по інтерфейсу ListIterator.
Клас Itr, який реалізовує інтерфейс ListIterator є внутрішнім класом класу AbstractList. ArrayList є нащадком класу AbstractList.
Для того, щоб ітератор міг працювати з певним об’єктом, клас даного об’єкту повинен реалізовувати інтерфейс Iterable:
<syntaxhighlight lang="java">
public interface Iterable<E>
{
Iterator<E> iterator();
}
</syntaxhighlight>
Інтерфейс Collection розширює даний інтерфейс.
Можна також перебрати елементи за допомогою перевантаженого з виходом java 5 циклу for (так званого “for each”):
<syntaxhighlight lang="java">
for (String str : a1) {
System.out.print(str+" ");
}
</syntaxhighlight>
При компіляції даний цикл перетворюється компілятором у цикл із ітератором.
ArrayList можна також перетворити у звичайний масив за допомогою методу toArray():
<syntaxhighlight lang="java">
String strArray[]= new String[a1.size()];
strArray=a1.toArray(strArray);
System.out.println(strArray[0]);
</syntaxhighlight>
Якщо ви погано розумієте вищенаведений приклад і як усе працює зверніться до розділів, що описують основні концепції об’єктно-орієнтованого програмування і, зокрема, розберіть детально теми інтерфейсів, абстрактних класів та поліморфізму.
===Клас LinkedList===
LinkedList — це структура даних, що являє собою пов’язаний список елементів (об’єктів).
Різниця між ArrayList та LinkedList полягає в тому, що ArrayList реалізований у вигляді масиву, а LinkedList у вигляді пов’язаних між собою об’єктів. ArrayList швидко виконує читання і заміну елементів (посилань на об’єкти), проте, щоб вставити новий елемнт в середину ArrayList або видалити існуючий в середині ArrayList здійснюється послідовний зсув цілого ряду елементів масиву. В LinkedList доволі швидко відбувається вставлення нового елементу або видалення існуючого. Це відбувається тому, що в середині реалізації LinkedList змінюються лише посилання на попередній і наступний об’єкти (елементи). Проте доступ до об’єктів по індексу в LinkedList відбувається повільніше ніж в ArrayList. Тож загалом, LinkedList корисний, коли необхідно часто вставляти та видаляти елементи зі списку, а в інших випадках краще використовувати ArrayList.
Існує два конструктури LinkedList:
<syntaxhighlight lang="java">
LinkedList()
LinkedList (Collection c)
</syntaxhighlight>
Перший конструктор створює пустий список, а другий – створює пов’язаний список із іншої колекції.
Клас LinkedList розширює клас AbstractSequentalList та реалізує інтерфейси List, Dequeue та Queue. Реалізація останніх двох інтерфейсів (черг) означає, що ми можемо працювати із пов’язаним списком як із стеком з використанням методів pop(), push(), poll(), pollFirst(), pollLast() і т.п. Детальніше дивіться документацію по заданим інтерфейсам.
Далі попрацюємо з LinkedList, який міститиме в якості елементів об’єктні змінні типу Car.
Спочатку реалізуємо наш клас Car:
<syntaxhighlight lang="java">
public class Car {
private String name;
private double price;
private int year;
public Car(String name, double price, int year) {
this.name = name;
this.price = price;
this.year=year;
}
@Override
public String toString() {
return "\n Car [name=" + name + ", price=" + price + ", year=" + year
+ "]";
}
}
</syntaxhighlight>
Клас Car містить лише поля, конструктор, який заповнює дані поля та заміщений метод toString(), який видаватиме нам інформацію про автомобіль у вигляді рядка.
Наступний клас демонструє роботу з LinkedList:
<syntaxhighlight lang="java">
import java.util.ArrayList;
import java.util.LinkedList;
public class TestLinkedList {
private LinkedList<Car> ll=new LinkedList<>();
public static void main(String[] args) {
TestLinkedList t=new TestLinkedList();
t.test();
}
void test(){
Car car1=new Car("Ferrary", 10800, 1995);
Car car2=new Car("Запорожець", 2600, 1989);
ll.add(car1);
ll.add(car2);
//додаємо в початок списку
ll.addFirst(new Car("Alfa Romeo 155", 11678, 2000));
ll.remove(car2); // видалити об'єкт
System.out.println("Після видалення car2: "+ll);
ll.remove(1); //видалити елемент за індексом
System.out.println("Після видалення першого елементу: "+ll);
Car myCar=ll.get(0);
System.out.println("Отриманий елемент за індексом [0]:"+myCar);
ll.set(0, car1); //замінити елемент за індексом
System.out.println("Замінений елемент за індексом [0]"+ll.get(0));
ArrayList<Car> arrList=new ArrayList<Car>();
arrList.add(car1);
arrList.add(car2);
ll.addAll(arrList); //додаємо вміст ArrayList у наш LinkedList
System.out.println("Після додавання ArrayList:"+ll);
}
}
</syntaxhighlight>
Результат виконання програми:
<PRE>
Після видалення car2: [
Car [name=Alfa Romeo 155, price=11678.0, year=2000],
Car [name=Ferrary, price=10800.0, year=1995]]
Після видалення першого елементу: [
Car [name=Alfa Romeo 155, price=11678.0, year=2000]]
Отриманий елемент за індексом [0]:
Car [name=Alfa Romeo 155, price=11678.0, year=2000]
Замінений елемент за індексом [0]
Car [name=Ferrary, price=10800.0, year=1995]
Після додавання ArrayList:[
Car [name=Ferrary, price=10800.0, year=1995],
Car [name=Ferrary, price=10800.0, year=1995],
Car [name=Запорожець, price=2600.0, year=1989]]
</PRE>
Перебирати елементи LinkedList також можна з допомогою ітератора та у циклі for earch.
Детальніше про методи класу дивіться документацію по класу [https://docs.oracle.com/javase/9/docs/api/java/util/LinkedList.html LinkedList].
===Клас HashSet===
HashSet – це клас призначений для зберігання даних у вигляді множини невпорядкованих елементів. Якщо потрібна впорядкована множина, то використовуйте TreeSet. HashSet також не гарантує стабільного порядку збереження об’єктів. Тобто при додаванні об’єктів порядок зберігання елементів змінюється. Вони можуть бути збережені як в кінці множити так і в середині. Якщо потрібен один порядок зберігання об’єктів використовуйте LinkedHashSet.
Сам термін «множина» означає, що елементи не будуть повторюватися. Для зберігання і пошуку елементів використовується хеш-код об’єкта. HashSet також може містити значення null. Власне всередині самої реалізації HashSet використовується клас HashMap, який дозволяє зберігати елементи у вигляді двох складових ключа та хеш-коду. У класі HashSet хеш-код недоступний і використовується неявно для користувача.
Клас HashSet розширює клас AbstractSet та реалізує інтерфейс Set. Також реалізовує інтерфейси Serializable та Clonable.
HashSet має такі конструктори:
<pre>
HashSet()
HashSet (Collection c)
HashSet (int об’єм)
HashSet (int об’єм, float коефіцієнт_заповнення)
</pre>
Коефіцієнт заповнення – це число в межах 0.0 до 1.0, що представляє собою частку заповнення HashSet при якій об’єм HashSet буде збільшений. По замовчуванню в конcтрукторах, що не задають коефіцієнт заповнення, використовується значення 0.75.
Наступний приклад демонструє роботу із HashSet.
<syntaxhighlight lang="java">
import java.util.HashSet;
public class TestHashSet {
HashSet<String> hs=new HashSet<String>();
public static void main(String[] args) {
TestHashSet test=new TestHashSet();
test.test();
}
void test(){
hs.add("Австралія");
hs.add("Україна");
hs.add("США");
System.out.println("1) Три країни: "+hs+" розмір="+hs.size());
hs.add("Австралія"); // помилки не буде, але в HashSet нічого не поміняється
System.out.println("2) Після спроби додати Авcтралію ще раз: "+hs);
hs.remove("США"); //видаляємо США з множини
hs.add("Німеччина");
hs.add("Англія");
hs.add(null);
hs.add(null); // другий раз не додаситься
System.out.println("3)"+hs);
System.out.println("4) Чи містить множина Німеччину? "+hs.contains("Німеччина"));
System.out.println("5) Множина пуста? "+hs.isEmpty());
//можемо також отримати ітератор, або ж перебрати множину у for earch
for (String str:hs){
System.out.println(str);
}
hs.clear(); // очистити
System.out.println("6) Розмір після очищення="+hs.size());
}
}
</syntaxhighlight>
Результат виконання:
<pre>
1) Три країни: [Австралія, Україна, США] розмір=3
2) Після спроби додати Австралію ще раз: [Австралія, Україна, США]
3)[null, Австралія, Німеччина, Україна, Англія]
4) Чи містить множина Німеччину? true
5) Множина пуста? false
null
Австралія
Німеччина
Україна
Англія
6) Розмір після очищення=0
</pre>
Зробити копію хеш множини можна так:
<pre>
HashSet<String> hsc=(HashSet)hs.clone();
</pre>
Слід зауважити, що метод clone() здійснює поверхневе (shadow) копіювання, тобто копіюються лише адреси об’єктів, які містяться у екземплярі класу HashSet, а не самі об’єкти.
При використанні ітератор може викидати виняток ConcurrentModificationException, якщо HashSet було змінено. Щоб уникнути таких випадків слід використовувати методи ітератора для зміни HashSet.
Клас HashSet несинхронізоватий для багатопоточності, проте його можна синхронізувати використовуючи метод synchronizedSet класу Collections:
<pre>
Set s = Collections.synchronizedSet (new HashSet (...))
</pre>
У класу String перевизначені такі методи як equal та hashcode, що дає можливість коректного порівняння їхніх хеш-кодів та значень і уникати випадків, коли будуть додаватися ідентичні рядки, незалежно від того, чи вони зберігаються в різних комірках пам’яті. Проте при використанні власних класів, на практиці для правильного функціонування HashSet (без повторення об'єктів з однаковим станом, наприклад, ідентичними полями) у класах необхідно замістити методи equals() та hashcode() самому. Так, якщо ми створимо класи оболонки, що міститимуть String поле countryName із однаковим значенням, наприклад, “Австрія”, то у нас два об'єкти вважатимуться різні, оскільки у них буде різний Хеш-код, тож вони будуть додані до HashSet. В таких випадках необхідно продумати методи equals() та hashcode().
===Клас LinkedHashSet===
Клас <code>LinkedHashSet</code> розширює клас HashSet не додаючи ніяких нових методів. Працює він дещо довше за HashSet проте зберігає порядок в якому елементи додаються до нього. Відповідно це дозволяє організувати послідовну ітерацію вставлення та витягнення елементів. Всі конструктори та методи роботи з LinkedHashSet аналогічні методам класу HashSet.
===Клас TreeSet===
Клас TreeSet дозволяє створювати відсортовану множину. Тобто елементи не повторюються та зберігаються у відсортованому порядку. Для зберігання елементів застосовується бінарна деревоподібна структура. Об'єкти зберігаються в відсортованому порядку по зростанню. Час доступу та одержання елементів доволі малий, тому клас TreeSet підходить для зберігання великих об’ємів відсортованих даних, які повинні бути швидко знайдені.
Клас TreeSet розширює клас AbstractSet та реалізує інтерфейс NavigableSet. NavigableSet реалізується на базі TreeMap.
В класі доступні чотири конструктори:
<syntaxhighlight lang="java">
TreeSet ()
TreeSet(Collection с)
TreeSet(Comparator компаратор)
TreeSet(SortedSet ss)
</syntaxhighlight>
Третій конструктор дозволяє задавати власний компаратор, відповідно до якого буде відбуватися сортування об’єктів. Так об’єкти класу String не потребують реалізації власного компаратора, проте якщо ви хочете зберігати в класі TreeSet розроблені вами об’єкти, то потрібно задавати компаратор для цих об’єктів. Такий компаратор може реалізовувати сортування об’єктів по певному полю, наприклад по Прізвищу, якщо ваш клас зберігаю інформацію про осіб. Можна реалізувати ланцюжок компараторів з використанням методу thenComparing() класу Comparator.
TreeSet не може містити значення null. Також TreeSet не синхронізований клас, як і інші класи колекцій при потребі його потрібно синхронізувати з використанням методу Collections.synchronizedSet().
Розглянемо приклад роботи TreeSet з компаратором. Використаємо клас Car, який був попередньо використаний при роботі з LinkedList додавши лише гетер та сетер методи.
<syntaxhighlight lang="java">
public class Car {
private String name;
private double price;
private int year;
public Car(String name, double price, int year) {
this.name = name;
this.price = price;
this.year=year;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
@Override
public String toString() {
return "\n Car [name=" + name + ", price=" + price + ", year=" + year+ "]";
}
}
</syntaxhighlight>
Клас компаратора CarsComparator виглядає так:
<syntaxhighlight lang="java">
import java.util.Comparator;
public class CarsComparator implements Comparator {
@Override
public int compare(Car car1, Car car2) {
if(car1.getYear() > car2.getYear())
return 1;
else if (car1.getYear() < car2.getYear())
return -1;
else return 0;
}
}
</syntaxhighlight>
Наша програма з TreeSet:
<syntaxhighlight lang="java">
import java.util.Comparator;
import java.util.TreeSet;
public class TestTreeSet{
CarsComparator comp=new CarsComparator();
TreeSet<Car> ts1=new TreeSet<>(comp);
public static void main(String[] args) {
TestTreeSet t=new TestTreeSet();
t.test();
}
void test(){
Car car1=new Car("Ferrary", 12000, 1988);
Car car2=new Car("Ford", 13000, 1955);
Car car3=new Car("Toyota", 13500, 2003);
Car car4=new Car("Citroen", 12000, 2014);
Car car5=new Car("Mercedes-Benz", 15000, 2011);
ts1.add(car1);
ts1.add(car2);
ts1.add(car3);
ts1.add(car4);
ts1.add(car5);
System.out.println("Сортування по роках: "+ts1);
//Зворотній компаратор для TreeSet(Java8)
TreeSet<Car> ts2=new TreeSet<>(comp.reversed());
ts2.addAll(ts1); //додати вміст попереднього TreeSet у новий
System.out.println("Зворотнє сортування:"+ts2);
}
}
</syntaxhighlight>
Результат виконання:
<pre>
Сортування по роках: [
Car [name=Ford, price=13000.0, year=1955],
Car [name=Ferrary, price=12000.0, year=1988],
Car [name=Toyota, price=13500.0, year=2003],
Car [name=Mercedes-Benz, price=15000.0, year=2011],
Car [name=Citroen, price=12000.0, year=2014]]
Зворотнє сортування:[
Car [name=Citroen, price=12000.0, year=2014],
Car [name=Mercedes-Benz, price=15000.0, year=2011],
Car [name=Toyota, price=13500.0, year=2003],
Car [name=Ferrary, price=12000.0, year=1988],
Car [name=Ford, price=13000.0, year=1955]]
</pre>
Реалізація інтерфейсу NavigableSet забезпечила клас TreeSet доволі корисними методами як то ceiling(), floor(), headset(), higher(), pollFirst(), pollLast(), subset(), tailSet(), iterator(), descendingIterator(), descendingSet(). Використовуючи їх можна організувати доволі зручний вибір елементів з TreeSet. Див. детальніше документацію по TreeSet.
===Клас PriorityQueue===
PriorityQueue дозволяє реалізувати чергу на основі пріоритету. Така черга може бути корисна, наприклад, у разі необхідності обслуговування клієнтів згідно пріоритету. При зберіганні чисел в пріоритетній черзі, така черга гарантує, що першим елементом завжди буде найменший елемент. При цьому не гарантується ніякий стабільний послідовний порядок збереження елементів. Після додавання або видалення елементу з пріоритетної черги, порядок зберігання елементів в цій черзі змінюється таким чином, що в голові черги опиняється найменший елемент згідно його природнього порядку або згідно заданого компаратора.
<syntaxhighlight lang="java">
PriorityQueue має наступні конструктори:
PriorityQueue() //початковий об’єм становить 11
PriorityQueue(int початковий_об’єм)
PriorityQueue(Comparator comparator)
PriorityQueue(int початковий_об'єм, Comparator компаратор)
PriorityQueue(Collection с)
PriorityQueue(PriorityQueue с)
PriorityQueue(SortedSet с)
</syntaxhighlight>
Таким чином в разі потреби можна задати власний компаратор для видачі елементів у потрібному нам порядку.
PriorityQueue не може містити null. PriorityQueue розширює AbstractQueue та реалізує інтерфейси Serializable, Iterable, Collection, Queue.
Реалізація інтерфейсу Queue говорить нам, що в PriorityQueue доступні такі методи роботи з чергою:
*add(E e) – додати вказаний елемент у чергу
*element() – отримати, але не видаляти, елемент з голови черги
*offer(E e)- додати визначений елемент у чергу
*peek() – отримати елемент з голови черги, але не видаляти його. Повертає null, якщо черга порожня
*poll() – отримати та видалити елемент з голови черги
*remove() - отримати та видалити елемент з голови черги
Крім того в PriorityQueue достуні методи, що наявні і в інших колекціях як то: clear(), comparator(), contains(), iterator(), spliterator(), size(), toArray() тощо.
Приклад:
<syntaxhighlight lang="java">
import java.util.PriorityQueue;
public class TestPriorityQueue {
public static void main(String[] args) {
PriorityQueue<Integer> pq= new PriorityQueue<>(11);
pq.add(750);
pq.add(50);
pq.offer(1);
pq.add(300);
pq.add(25);
pq.add(2);
pq.offer(20);
pq.add(5);
pq.add(40);
System.out.println("Порядок зберігання елементів"+pq);
// Отримуємо і видаляємо елемент з голови черги
while (!pq.isEmpty()) {
System.out.println("Отримали: "+pq.poll());
System.out.println("Новий порядок:"+pq);
}
}
}
</syntaxhighlight>
Результат:
<pre>
Порядок зберігання елементів[1, 5, 2, 25, 300, 50, 20, 750, 40]
Отримали: 1
Новий порядок:[2, 5, 20, 25, 300, 50, 40, 750]
Отримали: 2
Новий порядок:[5, 25, 20, 750, 300, 50, 40]
Отримали: 5
Новий порядок:[20, 25, 40, 750, 300, 50]
Отримали: 20
Новий порядок:[25, 50, 40, 750, 300]
Отримали: 25
Новий порядок:[40, 50, 300, 750]
Отримали: 40
Новий порядок:[50, 750, 300]
Отримали: 50
Новий порядок:[300, 750]
Отримали: 300
Новий порядок:[750]
Отримали: 750
Новий порядок:[]
</pre>
Таким чином за допомогою методу poll() (його можна також замінити методом remove()), ми можемо отримувати елементи масиву у відсортованому порядку, незважаючи на те, що в самій пріоритетній черзі елементи зберігаються у іншому порядку.
===Клас ArrayDeque===
ArrayDeque (читається як аррейдек) – це клас який забезпечує двосторонню чергу. Іншими словами - це автоматично зростаючий масив, що дозволяє нам додавати або видаляти елементи з обох боків черги. ArrayDeque може бути використано як стек (LIFO, останній ввійшов - перший вийшов) або ж як черга (FIFO, перший ввійшов - перший вийшов).
ArrayDeque не може містити в якості елемента null.
Клас ArrayDeque швидший за клас Stack, якщо використовувати його в якості стеку і швидший за LinkedList, якщо використовувати в якості черги.
ArrayDeque розширює клас AbstractCollection та реалізує інтерфейси Deque, Cloneable, Serializable. Таким чином ми можемо використовувати для роботи з даним класом, як методи інтерфейсу Deque (який розширює інтерфейс Queue) так і методи інтерфейсу Collection.
Якщо використовується ітератор, то він буде викидати виняток ConcurrentModificationException, якщо вміст ArrayDeque був модифікований після створення ітератора. Таким чином ітератор необхідно з обережністю використовувати з ArrayDeque.
В ArrayDeque доступні наступні конструктори:
<syntaxhighlight lang="java">
ArrayDeque() // пустий ArrayDeque з початковим об’ємом 16 елентів
ArrayDeque(Collection c) // міститиме елементи колекції в порядку, що повертає ітератор даної колекції
ArrayDeque(int numElements) // дозволяє задати початковий об’єм
</syntaxhighlight>
При потребі збільшення об'єму, то він автоматично збільшується вдвічі.
Наступний приклад демонструє роботу із ArrayDeque у вигляді стека та у в вигляді черги:
<syntaxhighlight lang="java">
import java.util.ArrayDeque;
public class TestArrayDeque {
public static void main(String[] args) {
ArrayDeque<String> ad=new ArrayDeque<>();
System.out.println("Використання в якості стеку");
ad.push("Перший"); // метод інтерфуйсу Deque
ad.push("Другий");
ad.push("Третій");
System.out.println("Перший елемент ArrayDeque: "+ad.getFirst());//Отримуємо перший елемент, але не видаляємо
System.out.println("Вміст ArrayDeque: "+ad);
System.out.println(ad.pop()); //Отримуємо і видаляємо з вершини стеку
System.out.println(ad.pop()); //еквівалентно до removeFirst()
System.out.println(ad.pop());
//System.out.println(ad.pop()); //ArrayDeque порожній видасть NoSuchElementException
System.out.println();
System.out.println("Використання в якості черги");
ad.offer("Перший");
ad.offer("Другий");
ad.offer("Третій");
System.out.println("Перший елемент ArrayDeque: "+ad.getFirst());//Отримуємо перший елемент, але не видаляємо
System.out.println("Вміст ArrayDeque: "+ad);
System.out.println(ad.poll()); //витягнути і видалити з голови
System.out.println(ad.poll());
System.out.println(ad.poll());
System.out.println(ad.poll());
}
}
</syntaxhighlight>
Результат роботи:
<pre>
Використання в якості стеку
Перший елемент ArrayDeque: Третій
Вміст ArrayDeque: [Третій, Другий, Перший]
Третій
Другий
Перший
Використання в якості черги
Перший елемент ArrayDeque: Перший
Вміст ArrayDeque: [Перший, Другий, Третій]
Перший
Другий
Третій
null
</pre>
Дивіться також офіційну документацію по: [https://docs.oracle.com/javase/8/docs/api/java/util/Deque.html Інтерфейсу Deque] та
[https://docs.oracle.com/javase/8/docs/api/java/util/Collection.html Інтерфейсу Collection]
===Клас EnumSet===
Клас EnumSet — це одна з спеціалізованих реалізацій інтерфейсу Set для використання з перелічуваним типом даних (enum). EnumSet розширює AbstractSet та реалізує Cloneable та Serializable інтерфейси Java. EnumSet заміщує більшість методів інтерфейсів Set та Collection. EnumSet доволі швидка реалізація Set, швидша за HashSet, тому що всередині використовуються побітові операції, а не хеш-коди об’єктів.
EnumSet не синхронізований і повинен бути синхронізований ззовні, наприклад з використанням методу Collections.synchronizedSet(java.util.Set).
Всі елементи enum множини мають походити від єдиного перелічуваного типу, що вказується, коли множина створюється явно або неявно. EnumSet не дозволяє додавати значення null. Елементи зберігаються в порядку в якому їх подано в переліченні (enum).
EnumSet використовує безвідмовний (fail-safe) ітератор, що працює з копією EnumSet, тобто ітератор не буде викидати виняток ConcurrentModificationException, в разі зміни даних множини поза ітератором.
EnumSet – це відкритий абстрактний клас, який не має відкритого конструктора, для створення об’єкту EnumSet використовуються відповідні статичні факторні методи. В даних методах для створення EnumSet використовуються дві реалізації даного класу RegularEnumSet(для зберігання невеликих перелічень, до 64) та JumboEnumSet (для зберігання великих перелічень). Наступний приклад демонструє роботу з EnumSet:
<syntaxhighlight lang="java">
import java.util.EnumSet;
enum Colors
{
RED, GREEN, YELLOW, BLUE, BLACK
};
public class TestEnumSet
{
public static void main(String[] args)
{
// Створюємо множину
EnumSet<Colors> set1, set2, set3, set4, set5;
// Додаємо окремі елементи, порядок зберігання буде згідно порядку перелічення
set1 = EnumSet.of(Colors.RED, Colors.GREEN,
Colors.BLACK, Colors.BLUE);
// Заповнити тими елемнтами, яких нема у вказаній множині
set2 = EnumSet.complementOf(set1);
// Всі із даного перелічення
set3 = EnumSet.allOf(Colors.class);
// Додати усі елементи перелічення в діапазоні від GREEN до BLACK
set4 = EnumSet.range(Colors.GREEN, Colors.BLACK);
// створити пусту множину перелічень відповідного типу
set5= EnumSet.noneOf(Colors.class);
System.out.println("Set 1: " + set1);
System.out.println("Set 2: " + set2);
System.out.println("Set 3: " + set3);
System.out.println("Set 4: " + set4);
System.out.println("Set 5: " + set5);
}
}
</syntaxhighlight>
Результат роботи:
<pre>
Set 1: [RED, GREEN, BLUE, BLACK]
Set 2: [YELLOW]
Set 3: [RED, GREEN, YELLOW, BLUE, BLACK]
Set 4: [GREEN, YELLOW, BLUE, BLACK]
Set 5: []
</pre>
==Інтерфейс Map та класи, що його реалізують==
'''''Зіставлення''''' (англ. ''map'', також перекладають як ''відображення'')– це об’єкт який зіставляє ключ із відповідним значенням (key/value). Маючи ключ ви можете знайти його значення. І ключ, і значення є об’єктами. Ключ може бути унікальним, а значення може повторюватися. Деякі зіставлення можуть приймати null ключ і null значення, інші не можуть.
Зіставлення не підтримують Iterable інтерфейс. Тому ви не зможете використати ітератор для перебору вмісту зіставлення. Також ви не можете використовувати цикл for each. Проте можна перетворити зіставлення у інший тип колекції і вже на ньому можна отримати ітератор.
Основу зіставлень складає інтерфейс '''Map'''.
Map є узагальненим (див. розділ [[Освоюємо Java/Узагальнення|Узагальнення]]) і оголошений так:
<code>
interface Map<K, V>
</code>
де K – визначає тип ключа, а V визначає тип значення.
Інтерфейс '''SortedMap''' розширює інтерфейс Map і забезпечує, що вміст зберігається в порядку зростання, базуючись на значенні ключа.
Інтерфейс '''NavigableMap''' розширює SortedMap і забезпечує повернення вмісту базуючись на схожості ключа або ключів.
Інтерфейс '''Map.Entry''' – вкладений в Map інтерфейс і забезпечує роботу із вмістом зіставлення.
Класи, що реалізують інтерфейс Map наведені в таблиці.
{| class="wikitable" style="text-align: left; width: 800px;"
!Клас||Опис
|-
|AbstractMap ||Реалізує більшість інтерфейсу Map
|-
|EnumMap ||Розширює AbstractMap для використання з перелічуваними ключами.
|-
|HashMap ||HashMap розширює AbstractMap, щоб використовувати хеш таблиці.
|-
|TreeMap ||TreeMap розширює AbstractMap для використання дерев.
|-
|WeakHashMap ||WeakHashMap розширює AbstractMap для використання слабких ключів, що забезпечує утилізацію невикористовуваних ключів збирачем мусору
|-
|LinkedHashMap ||LinkedHashMap розширює HashMap дозволяючи ітерацію з вводом елементів в певному порядку
|-
|IdentityHashMap ||IdentityHashMap розширює AbstractMap і використовує рівність посилань при порівнянні документів
|}
===Клас HashMap===
HashMap розширює AbstractMap та реалізує інтерфейс Map. Клас не додає власних методів. Клас використовує хеш таблиці для зберігання зіставлення. HashMap не гарантує порядок елементів.
<code>
HashMap має наступні конструктори:
HashMap( )
HashMap(Map<? extends K, ? extends V> m)
HashMap(int capacity)
HashMap(int capacity, float fillRatio)
</code>
Перший створює HashMap по замовчуванню. Другий створює хеш зіставлення використовуючи елементи m. Третій задає ємність хеш зіставлення. Четвертий задає ємність(по замовчуванню 16) та коефіцієнт заповнення (по замовчуванню 0.75).
<syntaxhighlight lang="java">
package Map;
import java.util.HashMap;
import java.util.*;
import java.util.Set;
public class TestHashMap {
public static void main(String[] args) {
// створюємо об'єкт HashMap з назвою capitalCities
HashMap<String, String> capitalCities = new HashMap<String, String>();
// додаємо ключі і значення (Країна, Столиця)
capitalCities.put("Англія", "Лондон");
capitalCities.put("Німеччина", "Берлін");
capitalCities.put("Норвегія", "Осло");
capitalCities.put("США", "Вашингтон");
//вивести значення об'єкту capitalCities
System.out.println(capitalCities);
//звернутися до HashMap використовуючи ключ
System.out.println(" Отримати столицю США");
System.out.println(capitalCities.get("США"));
//Видалити Англію
System.out.println(" Видаляємо Англію");
capitalCities.remove("Англія");
System.out.println(capitalCities);
//видалити все можна так
//capitalCities.clear();
// друкуємо ключі
System.out.println(" Ключі:");
for (String i : capitalCities.keySet()) {
System.out.println(i);
}
// друкуємо значення
System.out.println(" Значення:");
for (String i : capitalCities.values()) {
System.out.println(i);
}
// Друкувати ключі і значення
System.out.println(" Ключі і значення:");
for (String i : capitalCities.keySet()) {
System.out.println("key: " + i + " value: " + capitalCities.get(i));
}
System.out.println("Використовуємо Map.Entry");
//одержати множину входжень
Set<Map.Entry<String,String>> set=capitalCities.entrySet();
//вивести множину входжень
for(Map.Entry<String, String> me: set) {
System.out.print(me.getKey()+": ");
System.out.println(me.getValue());
}
}
}
</syntaxhighlight>
Результат:
<pre>
{США=Вашингтон, Англія=Лондон, Норвегія=Осло, Німеччина=Берлін}
Отримати столицю США
Вашингтон
Видаляємо Англію
{США=Вашингтон, Норвегія=Осло, Німеччина=Берлін}
Ключі:
США
Норвегія
Німеччина
Значення:
Вашингтон
Осло
Берлін
Ключі і значення:
key: США value: Вашингтон
key: Норвегія value: Осло
key: Німеччина value: Берлін
Використовуємо Map.Entry
США: Вашингтон
Норвегія: Осло
Німеччина: Берлін
</pre>
Ключі і значення в HashMap є об’єктами. Якщо ми хочемо використати, наприклад, числа цілого типу (іnt) то використовуватиметься клас обгортка Integer. Так само і для інших примітивних типів.
===Клас TreeMap===
Клас '''TreeMap''' розширює '''AbstractMap''' та реалізує інтерфейс '''NavigableMap'''. TreeMap не містить методів крім тих, що визначені у NavigableMap та класі AbstractMap. Що забезпечує зберігання зіставлень за допомогою деревовидної структури. TreeMap забезпечує зберігання пар ключ/значення у відсортованому порядку (в порядку зростання), що забезпечує швидкий доступ до елементів. TreeMap по замовчуванню сортується за ключами. Для задання іншого сортування використовують компаратор.
TreeMap узагальнений клас і оголошується так:
<code>
class TreeMap<K,V>
</code>
де K – задає тип ключа, а V – задає тип значення.
TreeMap визначає наступні конструктори:
<pre>
TreeMap( )
TreeMap(Comparator<? super K> comp)
TreeMap(Map<? extends K, ? extends V> m)
TreeMap(SortedMap<K, ? extends V> sm)
</pre>
Перший створює пусте деревовидне зіставлення, що буде відсортоване використовуючи природній порядок ключів. Другий створює пусте зіставлення, що буде відсортоване використовуючи компаратор. Третій створює деревовидне зіставлення із входжень зіставлення m, що буде відсортоване в природньому порядку. Третій ініціалізує деревовидне зіставлення входженнями із sm з порядком сортуванням того ж sm.
<syntaxhighlight lang="java">
package Map;
import java.util.TreeMap;
import java.util.*;
public class TestTreeMap {
public static void main(String[] args) {
TreeMap<String, Integer> countries = new TreeMap<String, Integer>();
countries.put("Гваделупа",1);
countries.put("США",2);
countries.put("Гаваї",3);
countries.put("Бельгія", 4);
//вивести вміст
System.out.println(countries);
//вивести останній ключ
System.out.println("Останній ключ:"+countries.lastKey());
countries.put("Албанія", 5);
System.out.println(" Вміст зіставлення:");
// взяти множину входжень
Set<Map.Entry<String, Integer>> set = countries.entrySet();
// Вивести елементи
for(Map.Entry<String, Integer> me : set) {
System.out.print(me.getKey() + ": ");
System.out.println(me.getValue());
}
System.out.println();
}
}
</syntaxhighlight>
Результат:
<pre>
{Бельгія=4, Гаваї=3, Гваделупа=1, США=2}
Останній ключ:США
Вміст зіставлення:
Албанія: 5
Бельгія: 4
Гаваї: 3
Гваделупа: 1
США: 2
</pre>
===Клас LinkedHashMap===
Клас LinkedHashMap розширює HashMap і підтримує пов'язаний список записів у зіставлення, в порядку в якому вони додавались. При необхідності можна задати зіставлення в якому записи будуть зберігатись в порядку останнього доступу.
LinkedHashMap має наступні конструктори:
<pre>
LinkedHashMap( )
LinkedHashMap(Map<? extends K, ? extends V> m)
LinkedHashMap(int capacity)
LinkedHashMap(int capacity, float fillRatio)
LinkedHashMap(int capacity, float fillRatio, boolean Order)
</pre>
Перший конструктор створює LinkedHashMap по замовчуванню. Другий ініціалізує LinkedHashMap елементами із зіставлення m. Третій конструктор задає ємність. Четвертий задає ємність та коефіцієнт заповнення. Ємність по замовчуванню - 16, а коефіцієнт заповнення по замовчуванню становить 0,75. Останній конструктор дозволяє задати порядок заповнення зіставлення, чи записи зберігатимуться в порядку вставлення чи в порядку останнього доступу. Якщо Order є true тоді використовуються порядок зберігання по порядку доступу, якщо false тоді використовується порядок вставлення.
LinkedHashMap додає лише один власний метод - removeEldestEntry. Якщо його замістити так, щоб він повертав true, то буде видалятися найстаріший елемент при використанні методів put() та putAll(). Таким чином можна, наприклад, встановити, щоб в зіставлення було б не більше певної кількості елементів.
<syntaxhighlight lang="java">
var cache = new LinkedHashMap<K, V>(128, 0.75F, true)
{
protected boolean removeEldestEntry(Map.Entry<K, V> eldest)
{
return size() > 100; //якщо елементів більше ста, то старі записи видалятимуться
}
};
</syntaxhighlight>
(потребує доповнення)
==Алгоритми==
В структурі колекцій існує клас Collections, який надає ряд зручних статичних методів для роботи з даними. Нагадаємо, що статичні методи – це методи, які не потребують створення об'єктів і реалізують ряд додаткових алгоритмів по роботі з колекціями, як то сортування колекцій, знаходження максимального і мінімального елементу, перемішування, копіювання і т.п.
(необхідно розширити)
==Arrays==
(Ще не написано)
==Успадковані класи ==
Ранні версії Java не включали структуру Collections. Там було визначено декілька класів та інтерфейсів, що надавали методи для зберігання об'єктів. Структура Collections була додана в Java 2. (j2se 1.2). Тоді початкові класи були перероблені для підтримки інтерфейсів колекцій. Ці ранні класи також знані як успадковані класи (Legacy classes). В Java 5 успадковані класи та інтерфейси були перероблені для підтримки узагальнень. Їх підтримують, тому що до сих пір існує код, який їх використовує. Успадковані класи - синхронізовані. Класи входять в пакет java.util. Успадкованими є наступні класи:
* Dictionary
* HashTable
* Properties
* Stack
* Vector
Успадкованим є інтерфейс Enumaration, на заміну якому прийшов інтерфейс Iterator. Enumaration інтерфейс до сих пір використовується в декількох методах класів Vector та Properties.
==Додаткова література==
* [http://idndist.lp.edu.ua/moodle/library/books/0021/index06.html Плешко Д.Д. Лекція VІ. Колекції. (Об'єктно-орієнтоване програмування в Java)]
* [https://www.geeksforgeeks.org/collections-in-java-2/ Колекції в Java(англ)]
* [https://dzone.com/articles/working-with-hashcode-and-equals-in-java Робота з hashcode() та equals() (англ)]
* [https://docs.oracle.com/javase/8/docs/technotes/guides/collections/overview.html Огляд структори колекцій(англ)]
* [https://ukr-technologies.blogspot.com/search/label/Колекції Колекції Java]
{{Гортання сторінок|Графічний інтерфейс користувача|Менеджери розташування}}
[[Категорія:Освоюємо Java]]
a36dga4cdm2gwuikx7tpp7bqz10bb3z
36857
36856
2022-08-03T17:44:19Z
Володимир Груша
985
/* Клас LinkedHashMap */
wikitext
text/x-wiki
При об’єктно орієнтованому програмуванні доводиться працювати з великою кількістю об’єктів. Зручно мати засоби групування об’єктів. Для цих цілей в Java розроблено набір інтерфейсів і класів на їх основі під назвою колекції . В основі ієрархії колекцій знаходиться інтерфейс Collection.
==Структура колекцій==
Згадаймо, що інтерфейс – це клас, який не містить реалізації методів, а лише їхні оголошення. Можна реалізувати безліч реалізацій інтерфейсу. Програмісту, який використовуватиме ці реалізації, достатньо знати базовий інтерфейс для роботи з його реалізаціями, тобто знати методи, які передбачає даний інтерфейс.
Collection – базовий інтерфейс, крім нього на його основі в структурі колекцій є ще декілька інтерфейсів, які розширюють базовий інтерфейс Collection. Зокрема, List, Set та SortedSet. Окремо виділяють ще інтерфейс Map. Він не походить на пряму від інтерфейсу Collection, проте його також відносять до колекцій. На їх основі створено набір класів, які згодяться програмістам для більшості випадків роботи з набором об’єктів. Тож вам не прийдеться самим їх реалізовувати.
Якщо вам цікаво, для чого стільки різних класів в колекціях? Суть в тому, що різні класи по різному реалізовують роботу з даними. Одні класи швидше здійснюють читання даних, інші вставлення і видалення, одні перевіряють, щоб не було дублювань, інші дозволяють вставляти дані за певним ключем і т.п. Доволі важливо підібрати клас, який найкраще підходить для вашого завдання і забезпечить найбільшу швидкодію. Особливо це актуально, коли кількість об’єктів величезна.
==Реалізації інтерфейсу Collection==
===Клас ArrayList та використання ітератора===
Клас ArrayList призначений для читання об'єктів по індексу. Тож не дарма у назві є слово Array (масив). Після створення колекції на основі ArrayList, прочитати дані можна кількома способами. Наступний приклад демонструє створення ArrayList, його наповнення об'єктами типу String та їх читання за допомогою методу get (int index) та за допомогою ітератора.
<syntaxhighlight lang="java">
import java.util.ArrayList;
import java.util.ListIterator;
public class TestArrayList {
private ArrayList<String> a1;
public static void main(String[] args) {
TestArrayList test = new TestArrayList();
test.create();
test.getData();
test.iterateData();
}
void create() {
//створюємо і наповнюємо ArrayList
a1 = new ArrayList<String>();
a1.add("Привіт");
a1.add("тобі");
a1.add("божевільний");
a1.add("світе!");
}
//читаємо дані по індексу
void getData() {
for (int i = 0; i < a1.size(); i++) {
System.out.print(a1.get(i) + " ");
}
}
//Читаємо вміст ArrayList з допомогою ітератора
void iterateData() {
ListIterator<String> it = a1.listIterator();
while (it.hasNext()) {
System.out.print(it.next() + " ");
}
}
}
</syntaxhighlight>
Результат:
<PRE>Привіт тобі божевільний світе! Привіт тобі божевільний світе!</PRE>
Крім вищенаведених способів можна передати вміст ArrayList у звичайний масив за допомогою методу toArray(). Якщо ви хочете детально розібратися з ArrayList і його методами, то для цього також дивіться інформацію про інтерфейси Collection, List та Iterator.
Окремо розглянемо перегляд даних з допомогою ітератора.
<syntaxhighlight lang="java">ListIterator<String> it=a1.listIterator();</syntaxhighlight>
Таким чином створюється об’єкт ітератора, посилання на який передається об'єктній змінній it типу ListIterator. ListIterator – це інтерфейс, який розширює інтерфейс Iterator декількома новими методами. Базовими ж методами інтерфейсу Iterator є ті, що використані у нас в програмі, а саме:
* boolean hasNext() – повертає true, якщо ітерація має наступний елемент
* E next() - повертає наступний елемент ітерації (буква E вказує, що це може бути елемент будь-якого типу, детальніше див. розділ [[Освоюємо_Java/Узагальнення|Узагальнення]])
* void remove() – знищує останній елемент, що повертався ітератором
Тож у коді бачимо:
<syntaxhighlight lang="java">
while(it.hasNext()){
System.out.print(it.next()+" ");
}
</syntaxhighlight>
Цикл працює поки є елементи в ітераторі. Перевірка здійснюється за допомогою методу hasNext. А вивід елементів здійснюється за допомогою методу next. Перевірка за допомогою hasNext необхідна через те, що в разі відсутності наступного елементу при виклику методу next буде викинуто виняток NoSuchElementExeption.
Інтерфейсом ListIterator передбачено ще такі методи як add, hasPrevious, next, nextIndex, previous, previousIndex, set. Назви методів говорять самі за себе. Детальніше ви можете подивитися в документації по інтерфейсу ListIterator.
Клас Itr, який реалізовує інтерфейс ListIterator є внутрішнім класом класу AbstractList. ArrayList є нащадком класу AbstractList.
Для того, щоб ітератор міг працювати з певним об’єктом, клас даного об’єкту повинен реалізовувати інтерфейс Iterable:
<syntaxhighlight lang="java">
public interface Iterable<E>
{
Iterator<E> iterator();
}
</syntaxhighlight>
Інтерфейс Collection розширює даний інтерфейс.
Можна також перебрати елементи за допомогою перевантаженого з виходом java 5 циклу for (так званого “for each”):
<syntaxhighlight lang="java">
for (String str : a1) {
System.out.print(str+" ");
}
</syntaxhighlight>
При компіляції даний цикл перетворюється компілятором у цикл із ітератором.
ArrayList можна також перетворити у звичайний масив за допомогою методу toArray():
<syntaxhighlight lang="java">
String strArray[]= new String[a1.size()];
strArray=a1.toArray(strArray);
System.out.println(strArray[0]);
</syntaxhighlight>
Якщо ви погано розумієте вищенаведений приклад і як усе працює зверніться до розділів, що описують основні концепції об’єктно-орієнтованого програмування і, зокрема, розберіть детально теми інтерфейсів, абстрактних класів та поліморфізму.
===Клас LinkedList===
LinkedList — це структура даних, що являє собою пов’язаний список елементів (об’єктів).
Різниця між ArrayList та LinkedList полягає в тому, що ArrayList реалізований у вигляді масиву, а LinkedList у вигляді пов’язаних між собою об’єктів. ArrayList швидко виконує читання і заміну елементів (посилань на об’єкти), проте, щоб вставити новий елемнт в середину ArrayList або видалити існуючий в середині ArrayList здійснюється послідовний зсув цілого ряду елементів масиву. В LinkedList доволі швидко відбувається вставлення нового елементу або видалення існуючого. Це відбувається тому, що в середині реалізації LinkedList змінюються лише посилання на попередній і наступний об’єкти (елементи). Проте доступ до об’єктів по індексу в LinkedList відбувається повільніше ніж в ArrayList. Тож загалом, LinkedList корисний, коли необхідно часто вставляти та видаляти елементи зі списку, а в інших випадках краще використовувати ArrayList.
Існує два конструктури LinkedList:
<syntaxhighlight lang="java">
LinkedList()
LinkedList (Collection c)
</syntaxhighlight>
Перший конструктор створює пустий список, а другий – створює пов’язаний список із іншої колекції.
Клас LinkedList розширює клас AbstractSequentalList та реалізує інтерфейси List, Dequeue та Queue. Реалізація останніх двох інтерфейсів (черг) означає, що ми можемо працювати із пов’язаним списком як із стеком з використанням методів pop(), push(), poll(), pollFirst(), pollLast() і т.п. Детальніше дивіться документацію по заданим інтерфейсам.
Далі попрацюємо з LinkedList, який міститиме в якості елементів об’єктні змінні типу Car.
Спочатку реалізуємо наш клас Car:
<syntaxhighlight lang="java">
public class Car {
private String name;
private double price;
private int year;
public Car(String name, double price, int year) {
this.name = name;
this.price = price;
this.year=year;
}
@Override
public String toString() {
return "\n Car [name=" + name + ", price=" + price + ", year=" + year
+ "]";
}
}
</syntaxhighlight>
Клас Car містить лише поля, конструктор, який заповнює дані поля та заміщений метод toString(), який видаватиме нам інформацію про автомобіль у вигляді рядка.
Наступний клас демонструє роботу з LinkedList:
<syntaxhighlight lang="java">
import java.util.ArrayList;
import java.util.LinkedList;
public class TestLinkedList {
private LinkedList<Car> ll=new LinkedList<>();
public static void main(String[] args) {
TestLinkedList t=new TestLinkedList();
t.test();
}
void test(){
Car car1=new Car("Ferrary", 10800, 1995);
Car car2=new Car("Запорожець", 2600, 1989);
ll.add(car1);
ll.add(car2);
//додаємо в початок списку
ll.addFirst(new Car("Alfa Romeo 155", 11678, 2000));
ll.remove(car2); // видалити об'єкт
System.out.println("Після видалення car2: "+ll);
ll.remove(1); //видалити елемент за індексом
System.out.println("Після видалення першого елементу: "+ll);
Car myCar=ll.get(0);
System.out.println("Отриманий елемент за індексом [0]:"+myCar);
ll.set(0, car1); //замінити елемент за індексом
System.out.println("Замінений елемент за індексом [0]"+ll.get(0));
ArrayList<Car> arrList=new ArrayList<Car>();
arrList.add(car1);
arrList.add(car2);
ll.addAll(arrList); //додаємо вміст ArrayList у наш LinkedList
System.out.println("Після додавання ArrayList:"+ll);
}
}
</syntaxhighlight>
Результат виконання програми:
<PRE>
Після видалення car2: [
Car [name=Alfa Romeo 155, price=11678.0, year=2000],
Car [name=Ferrary, price=10800.0, year=1995]]
Після видалення першого елементу: [
Car [name=Alfa Romeo 155, price=11678.0, year=2000]]
Отриманий елемент за індексом [0]:
Car [name=Alfa Romeo 155, price=11678.0, year=2000]
Замінений елемент за індексом [0]
Car [name=Ferrary, price=10800.0, year=1995]
Після додавання ArrayList:[
Car [name=Ferrary, price=10800.0, year=1995],
Car [name=Ferrary, price=10800.0, year=1995],
Car [name=Запорожець, price=2600.0, year=1989]]
</PRE>
Перебирати елементи LinkedList також можна з допомогою ітератора та у циклі for earch.
Детальніше про методи класу дивіться документацію по класу [https://docs.oracle.com/javase/9/docs/api/java/util/LinkedList.html LinkedList].
===Клас HashSet===
HashSet – це клас призначений для зберігання даних у вигляді множини невпорядкованих елементів. Якщо потрібна впорядкована множина, то використовуйте TreeSet. HashSet також не гарантує стабільного порядку збереження об’єктів. Тобто при додаванні об’єктів порядок зберігання елементів змінюється. Вони можуть бути збережені як в кінці множити так і в середині. Якщо потрібен один порядок зберігання об’єктів використовуйте LinkedHashSet.
Сам термін «множина» означає, що елементи не будуть повторюватися. Для зберігання і пошуку елементів використовується хеш-код об’єкта. HashSet також може містити значення null. Власне всередині самої реалізації HashSet використовується клас HashMap, який дозволяє зберігати елементи у вигляді двох складових ключа та хеш-коду. У класі HashSet хеш-код недоступний і використовується неявно для користувача.
Клас HashSet розширює клас AbstractSet та реалізує інтерфейс Set. Також реалізовує інтерфейси Serializable та Clonable.
HashSet має такі конструктори:
<pre>
HashSet()
HashSet (Collection c)
HashSet (int об’єм)
HashSet (int об’єм, float коефіцієнт_заповнення)
</pre>
Коефіцієнт заповнення – це число в межах 0.0 до 1.0, що представляє собою частку заповнення HashSet при якій об’єм HashSet буде збільшений. По замовчуванню в конcтрукторах, що не задають коефіцієнт заповнення, використовується значення 0.75.
Наступний приклад демонструє роботу із HashSet.
<syntaxhighlight lang="java">
import java.util.HashSet;
public class TestHashSet {
HashSet<String> hs=new HashSet<String>();
public static void main(String[] args) {
TestHashSet test=new TestHashSet();
test.test();
}
void test(){
hs.add("Австралія");
hs.add("Україна");
hs.add("США");
System.out.println("1) Три країни: "+hs+" розмір="+hs.size());
hs.add("Австралія"); // помилки не буде, але в HashSet нічого не поміняється
System.out.println("2) Після спроби додати Авcтралію ще раз: "+hs);
hs.remove("США"); //видаляємо США з множини
hs.add("Німеччина");
hs.add("Англія");
hs.add(null);
hs.add(null); // другий раз не додаситься
System.out.println("3)"+hs);
System.out.println("4) Чи містить множина Німеччину? "+hs.contains("Німеччина"));
System.out.println("5) Множина пуста? "+hs.isEmpty());
//можемо також отримати ітератор, або ж перебрати множину у for earch
for (String str:hs){
System.out.println(str);
}
hs.clear(); // очистити
System.out.println("6) Розмір після очищення="+hs.size());
}
}
</syntaxhighlight>
Результат виконання:
<pre>
1) Три країни: [Австралія, Україна, США] розмір=3
2) Після спроби додати Австралію ще раз: [Австралія, Україна, США]
3)[null, Австралія, Німеччина, Україна, Англія]
4) Чи містить множина Німеччину? true
5) Множина пуста? false
null
Австралія
Німеччина
Україна
Англія
6) Розмір після очищення=0
</pre>
Зробити копію хеш множини можна так:
<pre>
HashSet<String> hsc=(HashSet)hs.clone();
</pre>
Слід зауважити, що метод clone() здійснює поверхневе (shadow) копіювання, тобто копіюються лише адреси об’єктів, які містяться у екземплярі класу HashSet, а не самі об’єкти.
При використанні ітератор може викидати виняток ConcurrentModificationException, якщо HashSet було змінено. Щоб уникнути таких випадків слід використовувати методи ітератора для зміни HashSet.
Клас HashSet несинхронізоватий для багатопоточності, проте його можна синхронізувати використовуючи метод synchronizedSet класу Collections:
<pre>
Set s = Collections.synchronizedSet (new HashSet (...))
</pre>
У класу String перевизначені такі методи як equal та hashcode, що дає можливість коректного порівняння їхніх хеш-кодів та значень і уникати випадків, коли будуть додаватися ідентичні рядки, незалежно від того, чи вони зберігаються в різних комірках пам’яті. Проте при використанні власних класів, на практиці для правильного функціонування HashSet (без повторення об'єктів з однаковим станом, наприклад, ідентичними полями) у класах необхідно замістити методи equals() та hashcode() самому. Так, якщо ми створимо класи оболонки, що міститимуть String поле countryName із однаковим значенням, наприклад, “Австрія”, то у нас два об'єкти вважатимуться різні, оскільки у них буде різний Хеш-код, тож вони будуть додані до HashSet. В таких випадках необхідно продумати методи equals() та hashcode().
===Клас LinkedHashSet===
Клас <code>LinkedHashSet</code> розширює клас HashSet не додаючи ніяких нових методів. Працює він дещо довше за HashSet проте зберігає порядок в якому елементи додаються до нього. Відповідно це дозволяє організувати послідовну ітерацію вставлення та витягнення елементів. Всі конструктори та методи роботи з LinkedHashSet аналогічні методам класу HashSet.
===Клас TreeSet===
Клас TreeSet дозволяє створювати відсортовану множину. Тобто елементи не повторюються та зберігаються у відсортованому порядку. Для зберігання елементів застосовується бінарна деревоподібна структура. Об'єкти зберігаються в відсортованому порядку по зростанню. Час доступу та одержання елементів доволі малий, тому клас TreeSet підходить для зберігання великих об’ємів відсортованих даних, які повинні бути швидко знайдені.
Клас TreeSet розширює клас AbstractSet та реалізує інтерфейс NavigableSet. NavigableSet реалізується на базі TreeMap.
В класі доступні чотири конструктори:
<syntaxhighlight lang="java">
TreeSet ()
TreeSet(Collection с)
TreeSet(Comparator компаратор)
TreeSet(SortedSet ss)
</syntaxhighlight>
Третій конструктор дозволяє задавати власний компаратор, відповідно до якого буде відбуватися сортування об’єктів. Так об’єкти класу String не потребують реалізації власного компаратора, проте якщо ви хочете зберігати в класі TreeSet розроблені вами об’єкти, то потрібно задавати компаратор для цих об’єктів. Такий компаратор може реалізовувати сортування об’єктів по певному полю, наприклад по Прізвищу, якщо ваш клас зберігаю інформацію про осіб. Можна реалізувати ланцюжок компараторів з використанням методу thenComparing() класу Comparator.
TreeSet не може містити значення null. Також TreeSet не синхронізований клас, як і інші класи колекцій при потребі його потрібно синхронізувати з використанням методу Collections.synchronizedSet().
Розглянемо приклад роботи TreeSet з компаратором. Використаємо клас Car, який був попередньо використаний при роботі з LinkedList додавши лише гетер та сетер методи.
<syntaxhighlight lang="java">
public class Car {
private String name;
private double price;
private int year;
public Car(String name, double price, int year) {
this.name = name;
this.price = price;
this.year=year;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
@Override
public String toString() {
return "\n Car [name=" + name + ", price=" + price + ", year=" + year+ "]";
}
}
</syntaxhighlight>
Клас компаратора CarsComparator виглядає так:
<syntaxhighlight lang="java">
import java.util.Comparator;
public class CarsComparator implements Comparator {
@Override
public int compare(Car car1, Car car2) {
if(car1.getYear() > car2.getYear())
return 1;
else if (car1.getYear() < car2.getYear())
return -1;
else return 0;
}
}
</syntaxhighlight>
Наша програма з TreeSet:
<syntaxhighlight lang="java">
import java.util.Comparator;
import java.util.TreeSet;
public class TestTreeSet{
CarsComparator comp=new CarsComparator();
TreeSet<Car> ts1=new TreeSet<>(comp);
public static void main(String[] args) {
TestTreeSet t=new TestTreeSet();
t.test();
}
void test(){
Car car1=new Car("Ferrary", 12000, 1988);
Car car2=new Car("Ford", 13000, 1955);
Car car3=new Car("Toyota", 13500, 2003);
Car car4=new Car("Citroen", 12000, 2014);
Car car5=new Car("Mercedes-Benz", 15000, 2011);
ts1.add(car1);
ts1.add(car2);
ts1.add(car3);
ts1.add(car4);
ts1.add(car5);
System.out.println("Сортування по роках: "+ts1);
//Зворотній компаратор для TreeSet(Java8)
TreeSet<Car> ts2=new TreeSet<>(comp.reversed());
ts2.addAll(ts1); //додати вміст попереднього TreeSet у новий
System.out.println("Зворотнє сортування:"+ts2);
}
}
</syntaxhighlight>
Результат виконання:
<pre>
Сортування по роках: [
Car [name=Ford, price=13000.0, year=1955],
Car [name=Ferrary, price=12000.0, year=1988],
Car [name=Toyota, price=13500.0, year=2003],
Car [name=Mercedes-Benz, price=15000.0, year=2011],
Car [name=Citroen, price=12000.0, year=2014]]
Зворотнє сортування:[
Car [name=Citroen, price=12000.0, year=2014],
Car [name=Mercedes-Benz, price=15000.0, year=2011],
Car [name=Toyota, price=13500.0, year=2003],
Car [name=Ferrary, price=12000.0, year=1988],
Car [name=Ford, price=13000.0, year=1955]]
</pre>
Реалізація інтерфейсу NavigableSet забезпечила клас TreeSet доволі корисними методами як то ceiling(), floor(), headset(), higher(), pollFirst(), pollLast(), subset(), tailSet(), iterator(), descendingIterator(), descendingSet(). Використовуючи їх можна організувати доволі зручний вибір елементів з TreeSet. Див. детальніше документацію по TreeSet.
===Клас PriorityQueue===
PriorityQueue дозволяє реалізувати чергу на основі пріоритету. Така черга може бути корисна, наприклад, у разі необхідності обслуговування клієнтів згідно пріоритету. При зберіганні чисел в пріоритетній черзі, така черга гарантує, що першим елементом завжди буде найменший елемент. При цьому не гарантується ніякий стабільний послідовний порядок збереження елементів. Після додавання або видалення елементу з пріоритетної черги, порядок зберігання елементів в цій черзі змінюється таким чином, що в голові черги опиняється найменший елемент згідно його природнього порядку або згідно заданого компаратора.
<syntaxhighlight lang="java">
PriorityQueue має наступні конструктори:
PriorityQueue() //початковий об’єм становить 11
PriorityQueue(int початковий_об’єм)
PriorityQueue(Comparator comparator)
PriorityQueue(int початковий_об'єм, Comparator компаратор)
PriorityQueue(Collection с)
PriorityQueue(PriorityQueue с)
PriorityQueue(SortedSet с)
</syntaxhighlight>
Таким чином в разі потреби можна задати власний компаратор для видачі елементів у потрібному нам порядку.
PriorityQueue не може містити null. PriorityQueue розширює AbstractQueue та реалізує інтерфейси Serializable, Iterable, Collection, Queue.
Реалізація інтерфейсу Queue говорить нам, що в PriorityQueue доступні такі методи роботи з чергою:
*add(E e) – додати вказаний елемент у чергу
*element() – отримати, але не видаляти, елемент з голови черги
*offer(E e)- додати визначений елемент у чергу
*peek() – отримати елемент з голови черги, але не видаляти його. Повертає null, якщо черга порожня
*poll() – отримати та видалити елемент з голови черги
*remove() - отримати та видалити елемент з голови черги
Крім того в PriorityQueue достуні методи, що наявні і в інших колекціях як то: clear(), comparator(), contains(), iterator(), spliterator(), size(), toArray() тощо.
Приклад:
<syntaxhighlight lang="java">
import java.util.PriorityQueue;
public class TestPriorityQueue {
public static void main(String[] args) {
PriorityQueue<Integer> pq= new PriorityQueue<>(11);
pq.add(750);
pq.add(50);
pq.offer(1);
pq.add(300);
pq.add(25);
pq.add(2);
pq.offer(20);
pq.add(5);
pq.add(40);
System.out.println("Порядок зберігання елементів"+pq);
// Отримуємо і видаляємо елемент з голови черги
while (!pq.isEmpty()) {
System.out.println("Отримали: "+pq.poll());
System.out.println("Новий порядок:"+pq);
}
}
}
</syntaxhighlight>
Результат:
<pre>
Порядок зберігання елементів[1, 5, 2, 25, 300, 50, 20, 750, 40]
Отримали: 1
Новий порядок:[2, 5, 20, 25, 300, 50, 40, 750]
Отримали: 2
Новий порядок:[5, 25, 20, 750, 300, 50, 40]
Отримали: 5
Новий порядок:[20, 25, 40, 750, 300, 50]
Отримали: 20
Новий порядок:[25, 50, 40, 750, 300]
Отримали: 25
Новий порядок:[40, 50, 300, 750]
Отримали: 40
Новий порядок:[50, 750, 300]
Отримали: 50
Новий порядок:[300, 750]
Отримали: 300
Новий порядок:[750]
Отримали: 750
Новий порядок:[]
</pre>
Таким чином за допомогою методу poll() (його можна також замінити методом remove()), ми можемо отримувати елементи масиву у відсортованому порядку, незважаючи на те, що в самій пріоритетній черзі елементи зберігаються у іншому порядку.
===Клас ArrayDeque===
ArrayDeque (читається як аррейдек) – це клас який забезпечує двосторонню чергу. Іншими словами - це автоматично зростаючий масив, що дозволяє нам додавати або видаляти елементи з обох боків черги. ArrayDeque може бути використано як стек (LIFO, останній ввійшов - перший вийшов) або ж як черга (FIFO, перший ввійшов - перший вийшов).
ArrayDeque не може містити в якості елемента null.
Клас ArrayDeque швидший за клас Stack, якщо використовувати його в якості стеку і швидший за LinkedList, якщо використовувати в якості черги.
ArrayDeque розширює клас AbstractCollection та реалізує інтерфейси Deque, Cloneable, Serializable. Таким чином ми можемо використовувати для роботи з даним класом, як методи інтерфейсу Deque (який розширює інтерфейс Queue) так і методи інтерфейсу Collection.
Якщо використовується ітератор, то він буде викидати виняток ConcurrentModificationException, якщо вміст ArrayDeque був модифікований після створення ітератора. Таким чином ітератор необхідно з обережністю використовувати з ArrayDeque.
В ArrayDeque доступні наступні конструктори:
<syntaxhighlight lang="java">
ArrayDeque() // пустий ArrayDeque з початковим об’ємом 16 елентів
ArrayDeque(Collection c) // міститиме елементи колекції в порядку, що повертає ітератор даної колекції
ArrayDeque(int numElements) // дозволяє задати початковий об’єм
</syntaxhighlight>
При потребі збільшення об'єму, то він автоматично збільшується вдвічі.
Наступний приклад демонструє роботу із ArrayDeque у вигляді стека та у в вигляді черги:
<syntaxhighlight lang="java">
import java.util.ArrayDeque;
public class TestArrayDeque {
public static void main(String[] args) {
ArrayDeque<String> ad=new ArrayDeque<>();
System.out.println("Використання в якості стеку");
ad.push("Перший"); // метод інтерфуйсу Deque
ad.push("Другий");
ad.push("Третій");
System.out.println("Перший елемент ArrayDeque: "+ad.getFirst());//Отримуємо перший елемент, але не видаляємо
System.out.println("Вміст ArrayDeque: "+ad);
System.out.println(ad.pop()); //Отримуємо і видаляємо з вершини стеку
System.out.println(ad.pop()); //еквівалентно до removeFirst()
System.out.println(ad.pop());
//System.out.println(ad.pop()); //ArrayDeque порожній видасть NoSuchElementException
System.out.println();
System.out.println("Використання в якості черги");
ad.offer("Перший");
ad.offer("Другий");
ad.offer("Третій");
System.out.println("Перший елемент ArrayDeque: "+ad.getFirst());//Отримуємо перший елемент, але не видаляємо
System.out.println("Вміст ArrayDeque: "+ad);
System.out.println(ad.poll()); //витягнути і видалити з голови
System.out.println(ad.poll());
System.out.println(ad.poll());
System.out.println(ad.poll());
}
}
</syntaxhighlight>
Результат роботи:
<pre>
Використання в якості стеку
Перший елемент ArrayDeque: Третій
Вміст ArrayDeque: [Третій, Другий, Перший]
Третій
Другий
Перший
Використання в якості черги
Перший елемент ArrayDeque: Перший
Вміст ArrayDeque: [Перший, Другий, Третій]
Перший
Другий
Третій
null
</pre>
Дивіться також офіційну документацію по: [https://docs.oracle.com/javase/8/docs/api/java/util/Deque.html Інтерфейсу Deque] та
[https://docs.oracle.com/javase/8/docs/api/java/util/Collection.html Інтерфейсу Collection]
===Клас EnumSet===
Клас EnumSet — це одна з спеціалізованих реалізацій інтерфейсу Set для використання з перелічуваним типом даних (enum). EnumSet розширює AbstractSet та реалізує Cloneable та Serializable інтерфейси Java. EnumSet заміщує більшість методів інтерфейсів Set та Collection. EnumSet доволі швидка реалізація Set, швидша за HashSet, тому що всередині використовуються побітові операції, а не хеш-коди об’єктів.
EnumSet не синхронізований і повинен бути синхронізований ззовні, наприклад з використанням методу Collections.synchronizedSet(java.util.Set).
Всі елементи enum множини мають походити від єдиного перелічуваного типу, що вказується, коли множина створюється явно або неявно. EnumSet не дозволяє додавати значення null. Елементи зберігаються в порядку в якому їх подано в переліченні (enum).
EnumSet використовує безвідмовний (fail-safe) ітератор, що працює з копією EnumSet, тобто ітератор не буде викидати виняток ConcurrentModificationException, в разі зміни даних множини поза ітератором.
EnumSet – це відкритий абстрактний клас, який не має відкритого конструктора, для створення об’єкту EnumSet використовуються відповідні статичні факторні методи. В даних методах для створення EnumSet використовуються дві реалізації даного класу RegularEnumSet(для зберігання невеликих перелічень, до 64) та JumboEnumSet (для зберігання великих перелічень). Наступний приклад демонструє роботу з EnumSet:
<syntaxhighlight lang="java">
import java.util.EnumSet;
enum Colors
{
RED, GREEN, YELLOW, BLUE, BLACK
};
public class TestEnumSet
{
public static void main(String[] args)
{
// Створюємо множину
EnumSet<Colors> set1, set2, set3, set4, set5;
// Додаємо окремі елементи, порядок зберігання буде згідно порядку перелічення
set1 = EnumSet.of(Colors.RED, Colors.GREEN,
Colors.BLACK, Colors.BLUE);
// Заповнити тими елемнтами, яких нема у вказаній множині
set2 = EnumSet.complementOf(set1);
// Всі із даного перелічення
set3 = EnumSet.allOf(Colors.class);
// Додати усі елементи перелічення в діапазоні від GREEN до BLACK
set4 = EnumSet.range(Colors.GREEN, Colors.BLACK);
// створити пусту множину перелічень відповідного типу
set5= EnumSet.noneOf(Colors.class);
System.out.println("Set 1: " + set1);
System.out.println("Set 2: " + set2);
System.out.println("Set 3: " + set3);
System.out.println("Set 4: " + set4);
System.out.println("Set 5: " + set5);
}
}
</syntaxhighlight>
Результат роботи:
<pre>
Set 1: [RED, GREEN, BLUE, BLACK]
Set 2: [YELLOW]
Set 3: [RED, GREEN, YELLOW, BLUE, BLACK]
Set 4: [GREEN, YELLOW, BLUE, BLACK]
Set 5: []
</pre>
==Інтерфейс Map та класи, що його реалізують==
'''''Зіставлення''''' (англ. ''map'', також перекладають як ''відображення'')– це об’єкт який зіставляє ключ із відповідним значенням (key/value). Маючи ключ ви можете знайти його значення. І ключ, і значення є об’єктами. Ключ може бути унікальним, а значення може повторюватися. Деякі зіставлення можуть приймати null ключ і null значення, інші не можуть.
Зіставлення не підтримують Iterable інтерфейс. Тому ви не зможете використати ітератор для перебору вмісту зіставлення. Також ви не можете використовувати цикл for each. Проте можна перетворити зіставлення у інший тип колекції і вже на ньому можна отримати ітератор.
Основу зіставлень складає інтерфейс '''Map'''.
Map є узагальненим (див. розділ [[Освоюємо Java/Узагальнення|Узагальнення]]) і оголошений так:
<code>
interface Map<K, V>
</code>
де K – визначає тип ключа, а V визначає тип значення.
Інтерфейс '''SortedMap''' розширює інтерфейс Map і забезпечує, що вміст зберігається в порядку зростання, базуючись на значенні ключа.
Інтерфейс '''NavigableMap''' розширює SortedMap і забезпечує повернення вмісту базуючись на схожості ключа або ключів.
Інтерфейс '''Map.Entry''' – вкладений в Map інтерфейс і забезпечує роботу із вмістом зіставлення.
Класи, що реалізують інтерфейс Map наведені в таблиці.
{| class="wikitable" style="text-align: left; width: 800px;"
!Клас||Опис
|-
|AbstractMap ||Реалізує більшість інтерфейсу Map
|-
|EnumMap ||Розширює AbstractMap для використання з перелічуваними ключами.
|-
|HashMap ||HashMap розширює AbstractMap, щоб використовувати хеш таблиці.
|-
|TreeMap ||TreeMap розширює AbstractMap для використання дерев.
|-
|WeakHashMap ||WeakHashMap розширює AbstractMap для використання слабких ключів, що забезпечує утилізацію невикористовуваних ключів збирачем мусору
|-
|LinkedHashMap ||LinkedHashMap розширює HashMap дозволяючи ітерацію з вводом елементів в певному порядку
|-
|IdentityHashMap ||IdentityHashMap розширює AbstractMap і використовує рівність посилань при порівнянні документів
|}
===Клас HashMap===
HashMap розширює AbstractMap та реалізує інтерфейс Map. Клас не додає власних методів. Клас використовує хеш таблиці для зберігання зіставлення. HashMap не гарантує порядок елементів.
<code>
HashMap має наступні конструктори:
HashMap( )
HashMap(Map<? extends K, ? extends V> m)
HashMap(int capacity)
HashMap(int capacity, float fillRatio)
</code>
Перший створює HashMap по замовчуванню. Другий створює хеш зіставлення використовуючи елементи m. Третій задає ємність хеш зіставлення. Четвертий задає ємність(по замовчуванню 16) та коефіцієнт заповнення (по замовчуванню 0.75).
<syntaxhighlight lang="java">
package Map;
import java.util.HashMap;
import java.util.*;
import java.util.Set;
public class TestHashMap {
public static void main(String[] args) {
// створюємо об'єкт HashMap з назвою capitalCities
HashMap<String, String> capitalCities = new HashMap<String, String>();
// додаємо ключі і значення (Країна, Столиця)
capitalCities.put("Англія", "Лондон");
capitalCities.put("Німеччина", "Берлін");
capitalCities.put("Норвегія", "Осло");
capitalCities.put("США", "Вашингтон");
//вивести значення об'єкту capitalCities
System.out.println(capitalCities);
//звернутися до HashMap використовуючи ключ
System.out.println(" Отримати столицю США");
System.out.println(capitalCities.get("США"));
//Видалити Англію
System.out.println(" Видаляємо Англію");
capitalCities.remove("Англія");
System.out.println(capitalCities);
//видалити все можна так
//capitalCities.clear();
// друкуємо ключі
System.out.println(" Ключі:");
for (String i : capitalCities.keySet()) {
System.out.println(i);
}
// друкуємо значення
System.out.println(" Значення:");
for (String i : capitalCities.values()) {
System.out.println(i);
}
// Друкувати ключі і значення
System.out.println(" Ключі і значення:");
for (String i : capitalCities.keySet()) {
System.out.println("key: " + i + " value: " + capitalCities.get(i));
}
System.out.println("Використовуємо Map.Entry");
//одержати множину входжень
Set<Map.Entry<String,String>> set=capitalCities.entrySet();
//вивести множину входжень
for(Map.Entry<String, String> me: set) {
System.out.print(me.getKey()+": ");
System.out.println(me.getValue());
}
}
}
</syntaxhighlight>
Результат:
<pre>
{США=Вашингтон, Англія=Лондон, Норвегія=Осло, Німеччина=Берлін}
Отримати столицю США
Вашингтон
Видаляємо Англію
{США=Вашингтон, Норвегія=Осло, Німеччина=Берлін}
Ключі:
США
Норвегія
Німеччина
Значення:
Вашингтон
Осло
Берлін
Ключі і значення:
key: США value: Вашингтон
key: Норвегія value: Осло
key: Німеччина value: Берлін
Використовуємо Map.Entry
США: Вашингтон
Норвегія: Осло
Німеччина: Берлін
</pre>
Ключі і значення в HashMap є об’єктами. Якщо ми хочемо використати, наприклад, числа цілого типу (іnt) то використовуватиметься клас обгортка Integer. Так само і для інших примітивних типів.
===Клас TreeMap===
Клас '''TreeMap''' розширює '''AbstractMap''' та реалізує інтерфейс '''NavigableMap'''. TreeMap не містить методів крім тих, що визначені у NavigableMap та класі AbstractMap. Що забезпечує зберігання зіставлень за допомогою деревовидної структури. TreeMap забезпечує зберігання пар ключ/значення у відсортованому порядку (в порядку зростання), що забезпечує швидкий доступ до елементів. TreeMap по замовчуванню сортується за ключами. Для задання іншого сортування використовують компаратор.
TreeMap узагальнений клас і оголошується так:
<code>
class TreeMap<K,V>
</code>
де K – задає тип ключа, а V – задає тип значення.
TreeMap визначає наступні конструктори:
<pre>
TreeMap( )
TreeMap(Comparator<? super K> comp)
TreeMap(Map<? extends K, ? extends V> m)
TreeMap(SortedMap<K, ? extends V> sm)
</pre>
Перший створює пусте деревовидне зіставлення, що буде відсортоване використовуючи природній порядок ключів. Другий створює пусте зіставлення, що буде відсортоване використовуючи компаратор. Третій створює деревовидне зіставлення із входжень зіставлення m, що буде відсортоване в природньому порядку. Третій ініціалізує деревовидне зіставлення входженнями із sm з порядком сортуванням того ж sm.
<syntaxhighlight lang="java">
package Map;
import java.util.TreeMap;
import java.util.*;
public class TestTreeMap {
public static void main(String[] args) {
TreeMap<String, Integer> countries = new TreeMap<String, Integer>();
countries.put("Гваделупа",1);
countries.put("США",2);
countries.put("Гаваї",3);
countries.put("Бельгія", 4);
//вивести вміст
System.out.println(countries);
//вивести останній ключ
System.out.println("Останній ключ:"+countries.lastKey());
countries.put("Албанія", 5);
System.out.println(" Вміст зіставлення:");
// взяти множину входжень
Set<Map.Entry<String, Integer>> set = countries.entrySet();
// Вивести елементи
for(Map.Entry<String, Integer> me : set) {
System.out.print(me.getKey() + ": ");
System.out.println(me.getValue());
}
System.out.println();
}
}
</syntaxhighlight>
Результат:
<pre>
{Бельгія=4, Гаваї=3, Гваделупа=1, США=2}
Останній ключ:США
Вміст зіставлення:
Албанія: 5
Бельгія: 4
Гаваї: 3
Гваделупа: 1
США: 2
</pre>
===Клас LinkedHashMap===
Клас '''LinkedHashMap''' розширює '''HashMap''' і підтримує пов'язаний список записів у зіставлення, в порядку в якому вони додавались. При необхідності можна задати зіставлення в якому записи будуть зберігатись в порядку останнього доступу.
LinkedHashMap має наступні конструктори:
<pre>
LinkedHashMap( )
LinkedHashMap(Map<? extends K, ? extends V> m)
LinkedHashMap(int capacity)
LinkedHashMap(int capacity, float fillRatio)
LinkedHashMap(int capacity, float fillRatio, boolean Order)
</pre>
Перший конструктор створює LinkedHashMap по замовчуванню. Другий ініціалізує LinkedHashMap елементами із зіставлення m. Третій конструктор задає ємність. Четвертий задає ємність та коефіцієнт заповнення. Ємність по замовчуванню - 16, а коефіцієнт заповнення по замовчуванню становить 0,75. Останній конструктор дозволяє задати порядок заповнення зіставлення, чи записи зберігатимуться в порядку вставлення чи в порядку останнього доступу. Якщо Order є true тоді використовуються порядок зберігання по порядку доступу, якщо false тоді використовується порядок вставлення.
LinkedHashMap додає лише один власний метод - removeEldestEntry. Якщо його замістити так, щоб він повертав true, то буде видалятися найстаріший елемент при використанні методів put() та putAll(). Таким чином можна, наприклад, встановити, щоб в зіставлення було б не більше певної кількості елементів.
<syntaxhighlight lang="java">
var cache = new LinkedHashMap<K, V>(128, 0.75F, true)
{
protected boolean removeEldestEntry(Map.Entry<K, V> eldest)
{
return size() > 100; //якщо елементів більше ста, то старі записи видалятимуться
}
};
</syntaxhighlight>
(потребує доповнення)
==Алгоритми==
В структурі колекцій існує клас Collections, який надає ряд зручних статичних методів для роботи з даними. Нагадаємо, що статичні методи – це методи, які не потребують створення об'єктів і реалізують ряд додаткових алгоритмів по роботі з колекціями, як то сортування колекцій, знаходження максимального і мінімального елементу, перемішування, копіювання і т.п.
(необхідно розширити)
==Arrays==
(Ще не написано)
==Успадковані класи ==
Ранні версії Java не включали структуру Collections. Там було визначено декілька класів та інтерфейсів, що надавали методи для зберігання об'єктів. Структура Collections була додана в Java 2. (j2se 1.2). Тоді початкові класи були перероблені для підтримки інтерфейсів колекцій. Ці ранні класи також знані як успадковані класи (Legacy classes). В Java 5 успадковані класи та інтерфейси були перероблені для підтримки узагальнень. Їх підтримують, тому що до сих пір існує код, який їх використовує. Успадковані класи - синхронізовані. Класи входять в пакет java.util. Успадкованими є наступні класи:
* Dictionary
* HashTable
* Properties
* Stack
* Vector
Успадкованим є інтерфейс Enumaration, на заміну якому прийшов інтерфейс Iterator. Enumaration інтерфейс до сих пір використовується в декількох методах класів Vector та Properties.
==Додаткова література==
* [http://idndist.lp.edu.ua/moodle/library/books/0021/index06.html Плешко Д.Д. Лекція VІ. Колекції. (Об'єктно-орієнтоване програмування в Java)]
* [https://www.geeksforgeeks.org/collections-in-java-2/ Колекції в Java(англ)]
* [https://dzone.com/articles/working-with-hashcode-and-equals-in-java Робота з hashcode() та equals() (англ)]
* [https://docs.oracle.com/javase/8/docs/technotes/guides/collections/overview.html Огляд структори колекцій(англ)]
* [https://ukr-technologies.blogspot.com/search/label/Колекції Колекції Java]
{{Гортання сторінок|Графічний інтерфейс користувача|Менеджери розташування}}
[[Категорія:Освоюємо Java]]
93n3j7vof3ijrfak6lckedx1h3og7e0
36859
36857
2022-08-03T17:51:01Z
Володимир Груша
985
/* Інтерфейс Map та класи, що його реалізують */
wikitext
text/x-wiki
При об’єктно орієнтованому програмуванні доводиться працювати з великою кількістю об’єктів. Зручно мати засоби групування об’єктів. Для цих цілей в Java розроблено набір інтерфейсів і класів на їх основі під назвою колекції . В основі ієрархії колекцій знаходиться інтерфейс Collection.
==Структура колекцій==
Згадаймо, що інтерфейс – це клас, який не містить реалізації методів, а лише їхні оголошення. Можна реалізувати безліч реалізацій інтерфейсу. Програмісту, який використовуватиме ці реалізації, достатньо знати базовий інтерфейс для роботи з його реалізаціями, тобто знати методи, які передбачає даний інтерфейс.
Collection – базовий інтерфейс, крім нього на його основі в структурі колекцій є ще декілька інтерфейсів, які розширюють базовий інтерфейс Collection. Зокрема, List, Set та SortedSet. Окремо виділяють ще інтерфейс Map. Він не походить на пряму від інтерфейсу Collection, проте його також відносять до колекцій. На їх основі створено набір класів, які згодяться програмістам для більшості випадків роботи з набором об’єктів. Тож вам не прийдеться самим їх реалізовувати.
Якщо вам цікаво, для чого стільки різних класів в колекціях? Суть в тому, що різні класи по різному реалізовують роботу з даними. Одні класи швидше здійснюють читання даних, інші вставлення і видалення, одні перевіряють, щоб не було дублювань, інші дозволяють вставляти дані за певним ключем і т.п. Доволі важливо підібрати клас, який найкраще підходить для вашого завдання і забезпечить найбільшу швидкодію. Особливо це актуально, коли кількість об’єктів величезна.
==Реалізації інтерфейсу Collection==
===Клас ArrayList та використання ітератора===
Клас ArrayList призначений для читання об'єктів по індексу. Тож не дарма у назві є слово Array (масив). Після створення колекції на основі ArrayList, прочитати дані можна кількома способами. Наступний приклад демонструє створення ArrayList, його наповнення об'єктами типу String та їх читання за допомогою методу get (int index) та за допомогою ітератора.
<syntaxhighlight lang="java">
import java.util.ArrayList;
import java.util.ListIterator;
public class TestArrayList {
private ArrayList<String> a1;
public static void main(String[] args) {
TestArrayList test = new TestArrayList();
test.create();
test.getData();
test.iterateData();
}
void create() {
//створюємо і наповнюємо ArrayList
a1 = new ArrayList<String>();
a1.add("Привіт");
a1.add("тобі");
a1.add("божевільний");
a1.add("світе!");
}
//читаємо дані по індексу
void getData() {
for (int i = 0; i < a1.size(); i++) {
System.out.print(a1.get(i) + " ");
}
}
//Читаємо вміст ArrayList з допомогою ітератора
void iterateData() {
ListIterator<String> it = a1.listIterator();
while (it.hasNext()) {
System.out.print(it.next() + " ");
}
}
}
</syntaxhighlight>
Результат:
<PRE>Привіт тобі божевільний світе! Привіт тобі божевільний світе!</PRE>
Крім вищенаведених способів можна передати вміст ArrayList у звичайний масив за допомогою методу toArray(). Якщо ви хочете детально розібратися з ArrayList і його методами, то для цього також дивіться інформацію про інтерфейси Collection, List та Iterator.
Окремо розглянемо перегляд даних з допомогою ітератора.
<syntaxhighlight lang="java">ListIterator<String> it=a1.listIterator();</syntaxhighlight>
Таким чином створюється об’єкт ітератора, посилання на який передається об'єктній змінній it типу ListIterator. ListIterator – це інтерфейс, який розширює інтерфейс Iterator декількома новими методами. Базовими ж методами інтерфейсу Iterator є ті, що використані у нас в програмі, а саме:
* boolean hasNext() – повертає true, якщо ітерація має наступний елемент
* E next() - повертає наступний елемент ітерації (буква E вказує, що це може бути елемент будь-якого типу, детальніше див. розділ [[Освоюємо_Java/Узагальнення|Узагальнення]])
* void remove() – знищує останній елемент, що повертався ітератором
Тож у коді бачимо:
<syntaxhighlight lang="java">
while(it.hasNext()){
System.out.print(it.next()+" ");
}
</syntaxhighlight>
Цикл працює поки є елементи в ітераторі. Перевірка здійснюється за допомогою методу hasNext. А вивід елементів здійснюється за допомогою методу next. Перевірка за допомогою hasNext необхідна через те, що в разі відсутності наступного елементу при виклику методу next буде викинуто виняток NoSuchElementExeption.
Інтерфейсом ListIterator передбачено ще такі методи як add, hasPrevious, next, nextIndex, previous, previousIndex, set. Назви методів говорять самі за себе. Детальніше ви можете подивитися в документації по інтерфейсу ListIterator.
Клас Itr, який реалізовує інтерфейс ListIterator є внутрішнім класом класу AbstractList. ArrayList є нащадком класу AbstractList.
Для того, щоб ітератор міг працювати з певним об’єктом, клас даного об’єкту повинен реалізовувати інтерфейс Iterable:
<syntaxhighlight lang="java">
public interface Iterable<E>
{
Iterator<E> iterator();
}
</syntaxhighlight>
Інтерфейс Collection розширює даний інтерфейс.
Можна також перебрати елементи за допомогою перевантаженого з виходом java 5 циклу for (так званого “for each”):
<syntaxhighlight lang="java">
for (String str : a1) {
System.out.print(str+" ");
}
</syntaxhighlight>
При компіляції даний цикл перетворюється компілятором у цикл із ітератором.
ArrayList можна також перетворити у звичайний масив за допомогою методу toArray():
<syntaxhighlight lang="java">
String strArray[]= new String[a1.size()];
strArray=a1.toArray(strArray);
System.out.println(strArray[0]);
</syntaxhighlight>
Якщо ви погано розумієте вищенаведений приклад і як усе працює зверніться до розділів, що описують основні концепції об’єктно-орієнтованого програмування і, зокрема, розберіть детально теми інтерфейсів, абстрактних класів та поліморфізму.
===Клас LinkedList===
LinkedList — це структура даних, що являє собою пов’язаний список елементів (об’єктів).
Різниця між ArrayList та LinkedList полягає в тому, що ArrayList реалізований у вигляді масиву, а LinkedList у вигляді пов’язаних між собою об’єктів. ArrayList швидко виконує читання і заміну елементів (посилань на об’єкти), проте, щоб вставити новий елемнт в середину ArrayList або видалити існуючий в середині ArrayList здійснюється послідовний зсув цілого ряду елементів масиву. В LinkedList доволі швидко відбувається вставлення нового елементу або видалення існуючого. Це відбувається тому, що в середині реалізації LinkedList змінюються лише посилання на попередній і наступний об’єкти (елементи). Проте доступ до об’єктів по індексу в LinkedList відбувається повільніше ніж в ArrayList. Тож загалом, LinkedList корисний, коли необхідно часто вставляти та видаляти елементи зі списку, а в інших випадках краще використовувати ArrayList.
Існує два конструктури LinkedList:
<syntaxhighlight lang="java">
LinkedList()
LinkedList (Collection c)
</syntaxhighlight>
Перший конструктор створює пустий список, а другий – створює пов’язаний список із іншої колекції.
Клас LinkedList розширює клас AbstractSequentalList та реалізує інтерфейси List, Dequeue та Queue. Реалізація останніх двох інтерфейсів (черг) означає, що ми можемо працювати із пов’язаним списком як із стеком з використанням методів pop(), push(), poll(), pollFirst(), pollLast() і т.п. Детальніше дивіться документацію по заданим інтерфейсам.
Далі попрацюємо з LinkedList, який міститиме в якості елементів об’єктні змінні типу Car.
Спочатку реалізуємо наш клас Car:
<syntaxhighlight lang="java">
public class Car {
private String name;
private double price;
private int year;
public Car(String name, double price, int year) {
this.name = name;
this.price = price;
this.year=year;
}
@Override
public String toString() {
return "\n Car [name=" + name + ", price=" + price + ", year=" + year
+ "]";
}
}
</syntaxhighlight>
Клас Car містить лише поля, конструктор, який заповнює дані поля та заміщений метод toString(), який видаватиме нам інформацію про автомобіль у вигляді рядка.
Наступний клас демонструє роботу з LinkedList:
<syntaxhighlight lang="java">
import java.util.ArrayList;
import java.util.LinkedList;
public class TestLinkedList {
private LinkedList<Car> ll=new LinkedList<>();
public static void main(String[] args) {
TestLinkedList t=new TestLinkedList();
t.test();
}
void test(){
Car car1=new Car("Ferrary", 10800, 1995);
Car car2=new Car("Запорожець", 2600, 1989);
ll.add(car1);
ll.add(car2);
//додаємо в початок списку
ll.addFirst(new Car("Alfa Romeo 155", 11678, 2000));
ll.remove(car2); // видалити об'єкт
System.out.println("Після видалення car2: "+ll);
ll.remove(1); //видалити елемент за індексом
System.out.println("Після видалення першого елементу: "+ll);
Car myCar=ll.get(0);
System.out.println("Отриманий елемент за індексом [0]:"+myCar);
ll.set(0, car1); //замінити елемент за індексом
System.out.println("Замінений елемент за індексом [0]"+ll.get(0));
ArrayList<Car> arrList=new ArrayList<Car>();
arrList.add(car1);
arrList.add(car2);
ll.addAll(arrList); //додаємо вміст ArrayList у наш LinkedList
System.out.println("Після додавання ArrayList:"+ll);
}
}
</syntaxhighlight>
Результат виконання програми:
<PRE>
Після видалення car2: [
Car [name=Alfa Romeo 155, price=11678.0, year=2000],
Car [name=Ferrary, price=10800.0, year=1995]]
Після видалення першого елементу: [
Car [name=Alfa Romeo 155, price=11678.0, year=2000]]
Отриманий елемент за індексом [0]:
Car [name=Alfa Romeo 155, price=11678.0, year=2000]
Замінений елемент за індексом [0]
Car [name=Ferrary, price=10800.0, year=1995]
Після додавання ArrayList:[
Car [name=Ferrary, price=10800.0, year=1995],
Car [name=Ferrary, price=10800.0, year=1995],
Car [name=Запорожець, price=2600.0, year=1989]]
</PRE>
Перебирати елементи LinkedList також можна з допомогою ітератора та у циклі for earch.
Детальніше про методи класу дивіться документацію по класу [https://docs.oracle.com/javase/9/docs/api/java/util/LinkedList.html LinkedList].
===Клас HashSet===
HashSet – це клас призначений для зберігання даних у вигляді множини невпорядкованих елементів. Якщо потрібна впорядкована множина, то використовуйте TreeSet. HashSet також не гарантує стабільного порядку збереження об’єктів. Тобто при додаванні об’єктів порядок зберігання елементів змінюється. Вони можуть бути збережені як в кінці множити так і в середині. Якщо потрібен один порядок зберігання об’єктів використовуйте LinkedHashSet.
Сам термін «множина» означає, що елементи не будуть повторюватися. Для зберігання і пошуку елементів використовується хеш-код об’єкта. HashSet також може містити значення null. Власне всередині самої реалізації HashSet використовується клас HashMap, який дозволяє зберігати елементи у вигляді двох складових ключа та хеш-коду. У класі HashSet хеш-код недоступний і використовується неявно для користувача.
Клас HashSet розширює клас AbstractSet та реалізує інтерфейс Set. Також реалізовує інтерфейси Serializable та Clonable.
HashSet має такі конструктори:
<pre>
HashSet()
HashSet (Collection c)
HashSet (int об’єм)
HashSet (int об’єм, float коефіцієнт_заповнення)
</pre>
Коефіцієнт заповнення – це число в межах 0.0 до 1.0, що представляє собою частку заповнення HashSet при якій об’єм HashSet буде збільшений. По замовчуванню в конcтрукторах, що не задають коефіцієнт заповнення, використовується значення 0.75.
Наступний приклад демонструє роботу із HashSet.
<syntaxhighlight lang="java">
import java.util.HashSet;
public class TestHashSet {
HashSet<String> hs=new HashSet<String>();
public static void main(String[] args) {
TestHashSet test=new TestHashSet();
test.test();
}
void test(){
hs.add("Австралія");
hs.add("Україна");
hs.add("США");
System.out.println("1) Три країни: "+hs+" розмір="+hs.size());
hs.add("Австралія"); // помилки не буде, але в HashSet нічого не поміняється
System.out.println("2) Після спроби додати Авcтралію ще раз: "+hs);
hs.remove("США"); //видаляємо США з множини
hs.add("Німеччина");
hs.add("Англія");
hs.add(null);
hs.add(null); // другий раз не додаситься
System.out.println("3)"+hs);
System.out.println("4) Чи містить множина Німеччину? "+hs.contains("Німеччина"));
System.out.println("5) Множина пуста? "+hs.isEmpty());
//можемо також отримати ітератор, або ж перебрати множину у for earch
for (String str:hs){
System.out.println(str);
}
hs.clear(); // очистити
System.out.println("6) Розмір після очищення="+hs.size());
}
}
</syntaxhighlight>
Результат виконання:
<pre>
1) Три країни: [Австралія, Україна, США] розмір=3
2) Після спроби додати Австралію ще раз: [Австралія, Україна, США]
3)[null, Австралія, Німеччина, Україна, Англія]
4) Чи містить множина Німеччину? true
5) Множина пуста? false
null
Австралія
Німеччина
Україна
Англія
6) Розмір після очищення=0
</pre>
Зробити копію хеш множини можна так:
<pre>
HashSet<String> hsc=(HashSet)hs.clone();
</pre>
Слід зауважити, що метод clone() здійснює поверхневе (shadow) копіювання, тобто копіюються лише адреси об’єктів, які містяться у екземплярі класу HashSet, а не самі об’єкти.
При використанні ітератор може викидати виняток ConcurrentModificationException, якщо HashSet було змінено. Щоб уникнути таких випадків слід використовувати методи ітератора для зміни HashSet.
Клас HashSet несинхронізоватий для багатопоточності, проте його можна синхронізувати використовуючи метод synchronizedSet класу Collections:
<pre>
Set s = Collections.synchronizedSet (new HashSet (...))
</pre>
У класу String перевизначені такі методи як equal та hashcode, що дає можливість коректного порівняння їхніх хеш-кодів та значень і уникати випадків, коли будуть додаватися ідентичні рядки, незалежно від того, чи вони зберігаються в різних комірках пам’яті. Проте при використанні власних класів, на практиці для правильного функціонування HashSet (без повторення об'єктів з однаковим станом, наприклад, ідентичними полями) у класах необхідно замістити методи equals() та hashcode() самому. Так, якщо ми створимо класи оболонки, що міститимуть String поле countryName із однаковим значенням, наприклад, “Австрія”, то у нас два об'єкти вважатимуться різні, оскільки у них буде різний Хеш-код, тож вони будуть додані до HashSet. В таких випадках необхідно продумати методи equals() та hashcode().
===Клас LinkedHashSet===
Клас <code>LinkedHashSet</code> розширює клас HashSet не додаючи ніяких нових методів. Працює він дещо довше за HashSet проте зберігає порядок в якому елементи додаються до нього. Відповідно це дозволяє організувати послідовну ітерацію вставлення та витягнення елементів. Всі конструктори та методи роботи з LinkedHashSet аналогічні методам класу HashSet.
===Клас TreeSet===
Клас TreeSet дозволяє створювати відсортовану множину. Тобто елементи не повторюються та зберігаються у відсортованому порядку. Для зберігання елементів застосовується бінарна деревоподібна структура. Об'єкти зберігаються в відсортованому порядку по зростанню. Час доступу та одержання елементів доволі малий, тому клас TreeSet підходить для зберігання великих об’ємів відсортованих даних, які повинні бути швидко знайдені.
Клас TreeSet розширює клас AbstractSet та реалізує інтерфейс NavigableSet. NavigableSet реалізується на базі TreeMap.
В класі доступні чотири конструктори:
<syntaxhighlight lang="java">
TreeSet ()
TreeSet(Collection с)
TreeSet(Comparator компаратор)
TreeSet(SortedSet ss)
</syntaxhighlight>
Третій конструктор дозволяє задавати власний компаратор, відповідно до якого буде відбуватися сортування об’єктів. Так об’єкти класу String не потребують реалізації власного компаратора, проте якщо ви хочете зберігати в класі TreeSet розроблені вами об’єкти, то потрібно задавати компаратор для цих об’єктів. Такий компаратор може реалізовувати сортування об’єктів по певному полю, наприклад по Прізвищу, якщо ваш клас зберігаю інформацію про осіб. Можна реалізувати ланцюжок компараторів з використанням методу thenComparing() класу Comparator.
TreeSet не може містити значення null. Також TreeSet не синхронізований клас, як і інші класи колекцій при потребі його потрібно синхронізувати з використанням методу Collections.synchronizedSet().
Розглянемо приклад роботи TreeSet з компаратором. Використаємо клас Car, який був попередньо використаний при роботі з LinkedList додавши лише гетер та сетер методи.
<syntaxhighlight lang="java">
public class Car {
private String name;
private double price;
private int year;
public Car(String name, double price, int year) {
this.name = name;
this.price = price;
this.year=year;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
@Override
public String toString() {
return "\n Car [name=" + name + ", price=" + price + ", year=" + year+ "]";
}
}
</syntaxhighlight>
Клас компаратора CarsComparator виглядає так:
<syntaxhighlight lang="java">
import java.util.Comparator;
public class CarsComparator implements Comparator {
@Override
public int compare(Car car1, Car car2) {
if(car1.getYear() > car2.getYear())
return 1;
else if (car1.getYear() < car2.getYear())
return -1;
else return 0;
}
}
</syntaxhighlight>
Наша програма з TreeSet:
<syntaxhighlight lang="java">
import java.util.Comparator;
import java.util.TreeSet;
public class TestTreeSet{
CarsComparator comp=new CarsComparator();
TreeSet<Car> ts1=new TreeSet<>(comp);
public static void main(String[] args) {
TestTreeSet t=new TestTreeSet();
t.test();
}
void test(){
Car car1=new Car("Ferrary", 12000, 1988);
Car car2=new Car("Ford", 13000, 1955);
Car car3=new Car("Toyota", 13500, 2003);
Car car4=new Car("Citroen", 12000, 2014);
Car car5=new Car("Mercedes-Benz", 15000, 2011);
ts1.add(car1);
ts1.add(car2);
ts1.add(car3);
ts1.add(car4);
ts1.add(car5);
System.out.println("Сортування по роках: "+ts1);
//Зворотній компаратор для TreeSet(Java8)
TreeSet<Car> ts2=new TreeSet<>(comp.reversed());
ts2.addAll(ts1); //додати вміст попереднього TreeSet у новий
System.out.println("Зворотнє сортування:"+ts2);
}
}
</syntaxhighlight>
Результат виконання:
<pre>
Сортування по роках: [
Car [name=Ford, price=13000.0, year=1955],
Car [name=Ferrary, price=12000.0, year=1988],
Car [name=Toyota, price=13500.0, year=2003],
Car [name=Mercedes-Benz, price=15000.0, year=2011],
Car [name=Citroen, price=12000.0, year=2014]]
Зворотнє сортування:[
Car [name=Citroen, price=12000.0, year=2014],
Car [name=Mercedes-Benz, price=15000.0, year=2011],
Car [name=Toyota, price=13500.0, year=2003],
Car [name=Ferrary, price=12000.0, year=1988],
Car [name=Ford, price=13000.0, year=1955]]
</pre>
Реалізація інтерфейсу NavigableSet забезпечила клас TreeSet доволі корисними методами як то ceiling(), floor(), headset(), higher(), pollFirst(), pollLast(), subset(), tailSet(), iterator(), descendingIterator(), descendingSet(). Використовуючи їх можна організувати доволі зручний вибір елементів з TreeSet. Див. детальніше документацію по TreeSet.
===Клас PriorityQueue===
PriorityQueue дозволяє реалізувати чергу на основі пріоритету. Така черга може бути корисна, наприклад, у разі необхідності обслуговування клієнтів згідно пріоритету. При зберіганні чисел в пріоритетній черзі, така черга гарантує, що першим елементом завжди буде найменший елемент. При цьому не гарантується ніякий стабільний послідовний порядок збереження елементів. Після додавання або видалення елементу з пріоритетної черги, порядок зберігання елементів в цій черзі змінюється таким чином, що в голові черги опиняється найменший елемент згідно його природнього порядку або згідно заданого компаратора.
<syntaxhighlight lang="java">
PriorityQueue має наступні конструктори:
PriorityQueue() //початковий об’єм становить 11
PriorityQueue(int початковий_об’єм)
PriorityQueue(Comparator comparator)
PriorityQueue(int початковий_об'єм, Comparator компаратор)
PriorityQueue(Collection с)
PriorityQueue(PriorityQueue с)
PriorityQueue(SortedSet с)
</syntaxhighlight>
Таким чином в разі потреби можна задати власний компаратор для видачі елементів у потрібному нам порядку.
PriorityQueue не може містити null. PriorityQueue розширює AbstractQueue та реалізує інтерфейси Serializable, Iterable, Collection, Queue.
Реалізація інтерфейсу Queue говорить нам, що в PriorityQueue доступні такі методи роботи з чергою:
*add(E e) – додати вказаний елемент у чергу
*element() – отримати, але не видаляти, елемент з голови черги
*offer(E e)- додати визначений елемент у чергу
*peek() – отримати елемент з голови черги, але не видаляти його. Повертає null, якщо черга порожня
*poll() – отримати та видалити елемент з голови черги
*remove() - отримати та видалити елемент з голови черги
Крім того в PriorityQueue достуні методи, що наявні і в інших колекціях як то: clear(), comparator(), contains(), iterator(), spliterator(), size(), toArray() тощо.
Приклад:
<syntaxhighlight lang="java">
import java.util.PriorityQueue;
public class TestPriorityQueue {
public static void main(String[] args) {
PriorityQueue<Integer> pq= new PriorityQueue<>(11);
pq.add(750);
pq.add(50);
pq.offer(1);
pq.add(300);
pq.add(25);
pq.add(2);
pq.offer(20);
pq.add(5);
pq.add(40);
System.out.println("Порядок зберігання елементів"+pq);
// Отримуємо і видаляємо елемент з голови черги
while (!pq.isEmpty()) {
System.out.println("Отримали: "+pq.poll());
System.out.println("Новий порядок:"+pq);
}
}
}
</syntaxhighlight>
Результат:
<pre>
Порядок зберігання елементів[1, 5, 2, 25, 300, 50, 20, 750, 40]
Отримали: 1
Новий порядок:[2, 5, 20, 25, 300, 50, 40, 750]
Отримали: 2
Новий порядок:[5, 25, 20, 750, 300, 50, 40]
Отримали: 5
Новий порядок:[20, 25, 40, 750, 300, 50]
Отримали: 20
Новий порядок:[25, 50, 40, 750, 300]
Отримали: 25
Новий порядок:[40, 50, 300, 750]
Отримали: 40
Новий порядок:[50, 750, 300]
Отримали: 50
Новий порядок:[300, 750]
Отримали: 300
Новий порядок:[750]
Отримали: 750
Новий порядок:[]
</pre>
Таким чином за допомогою методу poll() (його можна також замінити методом remove()), ми можемо отримувати елементи масиву у відсортованому порядку, незважаючи на те, що в самій пріоритетній черзі елементи зберігаються у іншому порядку.
===Клас ArrayDeque===
ArrayDeque (читається як аррейдек) – це клас який забезпечує двосторонню чергу. Іншими словами - це автоматично зростаючий масив, що дозволяє нам додавати або видаляти елементи з обох боків черги. ArrayDeque може бути використано як стек (LIFO, останній ввійшов - перший вийшов) або ж як черга (FIFO, перший ввійшов - перший вийшов).
ArrayDeque не може містити в якості елемента null.
Клас ArrayDeque швидший за клас Stack, якщо використовувати його в якості стеку і швидший за LinkedList, якщо використовувати в якості черги.
ArrayDeque розширює клас AbstractCollection та реалізує інтерфейси Deque, Cloneable, Serializable. Таким чином ми можемо використовувати для роботи з даним класом, як методи інтерфейсу Deque (який розширює інтерфейс Queue) так і методи інтерфейсу Collection.
Якщо використовується ітератор, то він буде викидати виняток ConcurrentModificationException, якщо вміст ArrayDeque був модифікований після створення ітератора. Таким чином ітератор необхідно з обережністю використовувати з ArrayDeque.
В ArrayDeque доступні наступні конструктори:
<syntaxhighlight lang="java">
ArrayDeque() // пустий ArrayDeque з початковим об’ємом 16 елентів
ArrayDeque(Collection c) // міститиме елементи колекції в порядку, що повертає ітератор даної колекції
ArrayDeque(int numElements) // дозволяє задати початковий об’єм
</syntaxhighlight>
При потребі збільшення об'єму, то він автоматично збільшується вдвічі.
Наступний приклад демонструє роботу із ArrayDeque у вигляді стека та у в вигляді черги:
<syntaxhighlight lang="java">
import java.util.ArrayDeque;
public class TestArrayDeque {
public static void main(String[] args) {
ArrayDeque<String> ad=new ArrayDeque<>();
System.out.println("Використання в якості стеку");
ad.push("Перший"); // метод інтерфуйсу Deque
ad.push("Другий");
ad.push("Третій");
System.out.println("Перший елемент ArrayDeque: "+ad.getFirst());//Отримуємо перший елемент, але не видаляємо
System.out.println("Вміст ArrayDeque: "+ad);
System.out.println(ad.pop()); //Отримуємо і видаляємо з вершини стеку
System.out.println(ad.pop()); //еквівалентно до removeFirst()
System.out.println(ad.pop());
//System.out.println(ad.pop()); //ArrayDeque порожній видасть NoSuchElementException
System.out.println();
System.out.println("Використання в якості черги");
ad.offer("Перший");
ad.offer("Другий");
ad.offer("Третій");
System.out.println("Перший елемент ArrayDeque: "+ad.getFirst());//Отримуємо перший елемент, але не видаляємо
System.out.println("Вміст ArrayDeque: "+ad);
System.out.println(ad.poll()); //витягнути і видалити з голови
System.out.println(ad.poll());
System.out.println(ad.poll());
System.out.println(ad.poll());
}
}
</syntaxhighlight>
Результат роботи:
<pre>
Використання в якості стеку
Перший елемент ArrayDeque: Третій
Вміст ArrayDeque: [Третій, Другий, Перший]
Третій
Другий
Перший
Використання в якості черги
Перший елемент ArrayDeque: Перший
Вміст ArrayDeque: [Перший, Другий, Третій]
Перший
Другий
Третій
null
</pre>
Дивіться також офіційну документацію по: [https://docs.oracle.com/javase/8/docs/api/java/util/Deque.html Інтерфейсу Deque] та
[https://docs.oracle.com/javase/8/docs/api/java/util/Collection.html Інтерфейсу Collection]
===Клас EnumSet===
Клас EnumSet — це одна з спеціалізованих реалізацій інтерфейсу Set для використання з перелічуваним типом даних (enum). EnumSet розширює AbstractSet та реалізує Cloneable та Serializable інтерфейси Java. EnumSet заміщує більшість методів інтерфейсів Set та Collection. EnumSet доволі швидка реалізація Set, швидша за HashSet, тому що всередині використовуються побітові операції, а не хеш-коди об’єктів.
EnumSet не синхронізований і повинен бути синхронізований ззовні, наприклад з використанням методу Collections.synchronizedSet(java.util.Set).
Всі елементи enum множини мають походити від єдиного перелічуваного типу, що вказується, коли множина створюється явно або неявно. EnumSet не дозволяє додавати значення null. Елементи зберігаються в порядку в якому їх подано в переліченні (enum).
EnumSet використовує безвідмовний (fail-safe) ітератор, що працює з копією EnumSet, тобто ітератор не буде викидати виняток ConcurrentModificationException, в разі зміни даних множини поза ітератором.
EnumSet – це відкритий абстрактний клас, який не має відкритого конструктора, для створення об’єкту EnumSet використовуються відповідні статичні факторні методи. В даних методах для створення EnumSet використовуються дві реалізації даного класу RegularEnumSet(для зберігання невеликих перелічень, до 64) та JumboEnumSet (для зберігання великих перелічень). Наступний приклад демонструє роботу з EnumSet:
<syntaxhighlight lang="java">
import java.util.EnumSet;
enum Colors
{
RED, GREEN, YELLOW, BLUE, BLACK
};
public class TestEnumSet
{
public static void main(String[] args)
{
// Створюємо множину
EnumSet<Colors> set1, set2, set3, set4, set5;
// Додаємо окремі елементи, порядок зберігання буде згідно порядку перелічення
set1 = EnumSet.of(Colors.RED, Colors.GREEN,
Colors.BLACK, Colors.BLUE);
// Заповнити тими елемнтами, яких нема у вказаній множині
set2 = EnumSet.complementOf(set1);
// Всі із даного перелічення
set3 = EnumSet.allOf(Colors.class);
// Додати усі елементи перелічення в діапазоні від GREEN до BLACK
set4 = EnumSet.range(Colors.GREEN, Colors.BLACK);
// створити пусту множину перелічень відповідного типу
set5= EnumSet.noneOf(Colors.class);
System.out.println("Set 1: " + set1);
System.out.println("Set 2: " + set2);
System.out.println("Set 3: " + set3);
System.out.println("Set 4: " + set4);
System.out.println("Set 5: " + set5);
}
}
</syntaxhighlight>
Результат роботи:
<pre>
Set 1: [RED, GREEN, BLUE, BLACK]
Set 2: [YELLOW]
Set 3: [RED, GREEN, YELLOW, BLUE, BLACK]
Set 4: [GREEN, YELLOW, BLUE, BLACK]
Set 5: []
</pre>
==Інтерфейс Map та класи, що його реалізують==
'''''Зіставлення''''' (англ. ''map'', також перекладають як ''відображення'')– це об’єкт який зіставляє ключ із відповідним значенням (key/value). Маючи ключ ви можете знайти його значення. І ключ, і значення є об’єктами. Ключ може бути унікальним, а значення може повторюватися. Деякі зіставлення можуть приймати null ключ і null значення, інші не можуть.
Зіставлення не підтримують Iterable інтерфейс. Тому ви не зможете використати ітератор для перебору вмісту зіставлення. Також ви не можете використовувати цикл for each. Проте можна перетворити зіставлення у інший тип колекції і вже на ньому можна отримати ітератор.
Основу зіставлень складає інтерфейс '''Map'''.
Map є узагальненим (див. розділ [[Освоюємо Java/Узагальнення|Узагальнення]]) і оголошений так:
<code>
interface Map<K, V>
</code>
де K – визначає тип ключа, а V визначає тип значення.
Інтерфейс '''SortedMap''' розширює інтерфейс Map і забезпечує, що вміст зберігається в порядку зростання, базуючись на значенні ключа.
Інтерфейс '''NavigableMap''' розширює SortedMap і забезпечує повернення вмісту базуючись на схожості ключа або ключів.
Інтерфейс '''Map.Entry''' – вкладений в Map інтерфейс і забезпечує роботу із вмістом зіставлення.
Класи, що реалізують інтерфейс Map наведені в таблиці.
{| class="wikitable" style="text-align: left; width: 800px;"
!Клас||Опис
|-
|AbstractMap ||Реалізує більшість інтерфейсу Map
|-
|EnumMap ||Розширює AbstractMap для використання з перелічуваними ключами.
|-
|HashMap ||HashMap розширює AbstractMap, щоб використовувати хеш таблиці.
|-
|TreeMap ||TreeMap розширює AbstractMap для використання дерев.
|-
|WeakHashMap ||WeakHashMap розширює AbstractMap для використання слабких ключів, що забезпечує утилізацію невикористовуваних ключів збирачем мусору
|-
|LinkedHashMap ||LinkedHashMap розширює HashMap дозволяючи ітерацію з вводом елементів в певному порядку
|-
|IdentityHashMap ||IdentityHashMap розширює AbstractMap і використовує рівність посилань при порівнянні документів (для специфічних задач)
|}
===Клас HashMap===
HashMap розширює AbstractMap та реалізує інтерфейс Map. Клас не додає власних методів. Клас використовує хеш таблиці для зберігання зіставлення. HashMap не гарантує порядок елементів.
<code>
HashMap має наступні конструктори:
HashMap( )
HashMap(Map<? extends K, ? extends V> m)
HashMap(int capacity)
HashMap(int capacity, float fillRatio)
</code>
Перший створює HashMap по замовчуванню. Другий створює хеш зіставлення використовуючи елементи m. Третій задає ємність хеш зіставлення. Четвертий задає ємність(по замовчуванню 16) та коефіцієнт заповнення (по замовчуванню 0.75).
<syntaxhighlight lang="java">
package Map;
import java.util.HashMap;
import java.util.*;
import java.util.Set;
public class TestHashMap {
public static void main(String[] args) {
// створюємо об'єкт HashMap з назвою capitalCities
HashMap<String, String> capitalCities = new HashMap<String, String>();
// додаємо ключі і значення (Країна, Столиця)
capitalCities.put("Англія", "Лондон");
capitalCities.put("Німеччина", "Берлін");
capitalCities.put("Норвегія", "Осло");
capitalCities.put("США", "Вашингтон");
//вивести значення об'єкту capitalCities
System.out.println(capitalCities);
//звернутися до HashMap використовуючи ключ
System.out.println(" Отримати столицю США");
System.out.println(capitalCities.get("США"));
//Видалити Англію
System.out.println(" Видаляємо Англію");
capitalCities.remove("Англія");
System.out.println(capitalCities);
//видалити все можна так
//capitalCities.clear();
// друкуємо ключі
System.out.println(" Ключі:");
for (String i : capitalCities.keySet()) {
System.out.println(i);
}
// друкуємо значення
System.out.println(" Значення:");
for (String i : capitalCities.values()) {
System.out.println(i);
}
// Друкувати ключі і значення
System.out.println(" Ключі і значення:");
for (String i : capitalCities.keySet()) {
System.out.println("key: " + i + " value: " + capitalCities.get(i));
}
System.out.println("Використовуємо Map.Entry");
//одержати множину входжень
Set<Map.Entry<String,String>> set=capitalCities.entrySet();
//вивести множину входжень
for(Map.Entry<String, String> me: set) {
System.out.print(me.getKey()+": ");
System.out.println(me.getValue());
}
}
}
</syntaxhighlight>
Результат:
<pre>
{США=Вашингтон, Англія=Лондон, Норвегія=Осло, Німеччина=Берлін}
Отримати столицю США
Вашингтон
Видаляємо Англію
{США=Вашингтон, Норвегія=Осло, Німеччина=Берлін}
Ключі:
США
Норвегія
Німеччина
Значення:
Вашингтон
Осло
Берлін
Ключі і значення:
key: США value: Вашингтон
key: Норвегія value: Осло
key: Німеччина value: Берлін
Використовуємо Map.Entry
США: Вашингтон
Норвегія: Осло
Німеччина: Берлін
</pre>
Ключі і значення в HashMap є об’єктами. Якщо ми хочемо використати, наприклад, числа цілого типу (іnt) то використовуватиметься клас обгортка Integer. Так само і для інших примітивних типів.
===Клас TreeMap===
Клас '''TreeMap''' розширює '''AbstractMap''' та реалізує інтерфейс '''NavigableMap'''. TreeMap не містить методів крім тих, що визначені у NavigableMap та класі AbstractMap. Що забезпечує зберігання зіставлень за допомогою деревовидної структури. TreeMap забезпечує зберігання пар ключ/значення у відсортованому порядку (в порядку зростання), що забезпечує швидкий доступ до елементів. TreeMap по замовчуванню сортується за ключами. Для задання іншого сортування використовують компаратор.
TreeMap узагальнений клас і оголошується так:
<code>
class TreeMap<K,V>
</code>
де K – задає тип ключа, а V – задає тип значення.
TreeMap визначає наступні конструктори:
<pre>
TreeMap( )
TreeMap(Comparator<? super K> comp)
TreeMap(Map<? extends K, ? extends V> m)
TreeMap(SortedMap<K, ? extends V> sm)
</pre>
Перший створює пусте деревовидне зіставлення, що буде відсортоване використовуючи природній порядок ключів. Другий створює пусте зіставлення, що буде відсортоване використовуючи компаратор. Третій створює деревовидне зіставлення із входжень зіставлення m, що буде відсортоване в природньому порядку. Третій ініціалізує деревовидне зіставлення входженнями із sm з порядком сортуванням того ж sm.
<syntaxhighlight lang="java">
package Map;
import java.util.TreeMap;
import java.util.*;
public class TestTreeMap {
public static void main(String[] args) {
TreeMap<String, Integer> countries = new TreeMap<String, Integer>();
countries.put("Гваделупа",1);
countries.put("США",2);
countries.put("Гаваї",3);
countries.put("Бельгія", 4);
//вивести вміст
System.out.println(countries);
//вивести останній ключ
System.out.println("Останній ключ:"+countries.lastKey());
countries.put("Албанія", 5);
System.out.println(" Вміст зіставлення:");
// взяти множину входжень
Set<Map.Entry<String, Integer>> set = countries.entrySet();
// Вивести елементи
for(Map.Entry<String, Integer> me : set) {
System.out.print(me.getKey() + ": ");
System.out.println(me.getValue());
}
System.out.println();
}
}
</syntaxhighlight>
Результат:
<pre>
{Бельгія=4, Гаваї=3, Гваделупа=1, США=2}
Останній ключ:США
Вміст зіставлення:
Албанія: 5
Бельгія: 4
Гаваї: 3
Гваделупа: 1
США: 2
</pre>
===Клас LinkedHashMap===
Клас '''LinkedHashMap''' розширює '''HashMap''' і підтримує пов'язаний список записів у зіставлення, в порядку в якому вони додавались. При необхідності можна задати зіставлення в якому записи будуть зберігатись в порядку останнього доступу.
LinkedHashMap має наступні конструктори:
<pre>
LinkedHashMap( )
LinkedHashMap(Map<? extends K, ? extends V> m)
LinkedHashMap(int capacity)
LinkedHashMap(int capacity, float fillRatio)
LinkedHashMap(int capacity, float fillRatio, boolean Order)
</pre>
Перший конструктор створює LinkedHashMap по замовчуванню. Другий ініціалізує LinkedHashMap елементами із зіставлення m. Третій конструктор задає ємність. Четвертий задає ємність та коефіцієнт заповнення. Ємність по замовчуванню - 16, а коефіцієнт заповнення по замовчуванню становить 0,75. Останній конструктор дозволяє задати порядок заповнення зіставлення, чи записи зберігатимуться в порядку вставлення чи в порядку останнього доступу. Якщо Order є true тоді використовуються порядок зберігання по порядку доступу, якщо false тоді використовується порядок вставлення.
LinkedHashMap додає лише один власний метод - removeEldestEntry. Якщо його замістити так, щоб він повертав true, то буде видалятися найстаріший елемент при використанні методів put() та putAll(). Таким чином можна, наприклад, встановити, щоб в зіставлення було б не більше певної кількості елементів.
<syntaxhighlight lang="java">
var cache = new LinkedHashMap<K, V>(128, 0.75F, true)
{
protected boolean removeEldestEntry(Map.Entry<K, V> eldest)
{
return size() > 100; //якщо елементів більше ста, то старі записи видалятимуться
}
};
</syntaxhighlight>
(потребує доповнення)
==Алгоритми==
В структурі колекцій існує клас Collections, який надає ряд зручних статичних методів для роботи з даними. Нагадаємо, що статичні методи – це методи, які не потребують створення об'єктів і реалізують ряд додаткових алгоритмів по роботі з колекціями, як то сортування колекцій, знаходження максимального і мінімального елементу, перемішування, копіювання і т.п.
(необхідно розширити)
==Arrays==
(Ще не написано)
==Успадковані класи ==
Ранні версії Java не включали структуру Collections. Там було визначено декілька класів та інтерфейсів, що надавали методи для зберігання об'єктів. Структура Collections була додана в Java 2. (j2se 1.2). Тоді початкові класи були перероблені для підтримки інтерфейсів колекцій. Ці ранні класи також знані як успадковані класи (Legacy classes). В Java 5 успадковані класи та інтерфейси були перероблені для підтримки узагальнень. Їх підтримують, тому що до сих пір існує код, який їх використовує. Успадковані класи - синхронізовані. Класи входять в пакет java.util. Успадкованими є наступні класи:
* Dictionary
* HashTable
* Properties
* Stack
* Vector
Успадкованим є інтерфейс Enumaration, на заміну якому прийшов інтерфейс Iterator. Enumaration інтерфейс до сих пір використовується в декількох методах класів Vector та Properties.
==Додаткова література==
* [http://idndist.lp.edu.ua/moodle/library/books/0021/index06.html Плешко Д.Д. Лекція VІ. Колекції. (Об'єктно-орієнтоване програмування в Java)]
* [https://www.geeksforgeeks.org/collections-in-java-2/ Колекції в Java(англ)]
* [https://dzone.com/articles/working-with-hashcode-and-equals-in-java Робота з hashcode() та equals() (англ)]
* [https://docs.oracle.com/javase/8/docs/technotes/guides/collections/overview.html Огляд структори колекцій(англ)]
* [https://ukr-technologies.blogspot.com/search/label/Колекції Колекції Java]
{{Гортання сторінок|Графічний інтерфейс користувача|Менеджери розташування}}
[[Категорія:Освоюємо Java]]
9yuuhwanlh0ey0061g8l6z2nza8k7uu
36860
36859
2022-08-03T17:54:19Z
Володимир Груша
985
/* Клас LinkedHashMap */
wikitext
text/x-wiki
При об’єктно орієнтованому програмуванні доводиться працювати з великою кількістю об’єктів. Зручно мати засоби групування об’єктів. Для цих цілей в Java розроблено набір інтерфейсів і класів на їх основі під назвою колекції . В основі ієрархії колекцій знаходиться інтерфейс Collection.
==Структура колекцій==
Згадаймо, що інтерфейс – це клас, який не містить реалізації методів, а лише їхні оголошення. Можна реалізувати безліч реалізацій інтерфейсу. Програмісту, який використовуватиме ці реалізації, достатньо знати базовий інтерфейс для роботи з його реалізаціями, тобто знати методи, які передбачає даний інтерфейс.
Collection – базовий інтерфейс, крім нього на його основі в структурі колекцій є ще декілька інтерфейсів, які розширюють базовий інтерфейс Collection. Зокрема, List, Set та SortedSet. Окремо виділяють ще інтерфейс Map. Він не походить на пряму від інтерфейсу Collection, проте його також відносять до колекцій. На їх основі створено набір класів, які згодяться програмістам для більшості випадків роботи з набором об’єктів. Тож вам не прийдеться самим їх реалізовувати.
Якщо вам цікаво, для чого стільки різних класів в колекціях? Суть в тому, що різні класи по різному реалізовують роботу з даними. Одні класи швидше здійснюють читання даних, інші вставлення і видалення, одні перевіряють, щоб не було дублювань, інші дозволяють вставляти дані за певним ключем і т.п. Доволі важливо підібрати клас, який найкраще підходить для вашого завдання і забезпечить найбільшу швидкодію. Особливо це актуально, коли кількість об’єктів величезна.
==Реалізації інтерфейсу Collection==
===Клас ArrayList та використання ітератора===
Клас ArrayList призначений для читання об'єктів по індексу. Тож не дарма у назві є слово Array (масив). Після створення колекції на основі ArrayList, прочитати дані можна кількома способами. Наступний приклад демонструє створення ArrayList, його наповнення об'єктами типу String та їх читання за допомогою методу get (int index) та за допомогою ітератора.
<syntaxhighlight lang="java">
import java.util.ArrayList;
import java.util.ListIterator;
public class TestArrayList {
private ArrayList<String> a1;
public static void main(String[] args) {
TestArrayList test = new TestArrayList();
test.create();
test.getData();
test.iterateData();
}
void create() {
//створюємо і наповнюємо ArrayList
a1 = new ArrayList<String>();
a1.add("Привіт");
a1.add("тобі");
a1.add("божевільний");
a1.add("світе!");
}
//читаємо дані по індексу
void getData() {
for (int i = 0; i < a1.size(); i++) {
System.out.print(a1.get(i) + " ");
}
}
//Читаємо вміст ArrayList з допомогою ітератора
void iterateData() {
ListIterator<String> it = a1.listIterator();
while (it.hasNext()) {
System.out.print(it.next() + " ");
}
}
}
</syntaxhighlight>
Результат:
<PRE>Привіт тобі божевільний світе! Привіт тобі божевільний світе!</PRE>
Крім вищенаведених способів можна передати вміст ArrayList у звичайний масив за допомогою методу toArray(). Якщо ви хочете детально розібратися з ArrayList і його методами, то для цього також дивіться інформацію про інтерфейси Collection, List та Iterator.
Окремо розглянемо перегляд даних з допомогою ітератора.
<syntaxhighlight lang="java">ListIterator<String> it=a1.listIterator();</syntaxhighlight>
Таким чином створюється об’єкт ітератора, посилання на який передається об'єктній змінній it типу ListIterator. ListIterator – це інтерфейс, який розширює інтерфейс Iterator декількома новими методами. Базовими ж методами інтерфейсу Iterator є ті, що використані у нас в програмі, а саме:
* boolean hasNext() – повертає true, якщо ітерація має наступний елемент
* E next() - повертає наступний елемент ітерації (буква E вказує, що це може бути елемент будь-якого типу, детальніше див. розділ [[Освоюємо_Java/Узагальнення|Узагальнення]])
* void remove() – знищує останній елемент, що повертався ітератором
Тож у коді бачимо:
<syntaxhighlight lang="java">
while(it.hasNext()){
System.out.print(it.next()+" ");
}
</syntaxhighlight>
Цикл працює поки є елементи в ітераторі. Перевірка здійснюється за допомогою методу hasNext. А вивід елементів здійснюється за допомогою методу next. Перевірка за допомогою hasNext необхідна через те, що в разі відсутності наступного елементу при виклику методу next буде викинуто виняток NoSuchElementExeption.
Інтерфейсом ListIterator передбачено ще такі методи як add, hasPrevious, next, nextIndex, previous, previousIndex, set. Назви методів говорять самі за себе. Детальніше ви можете подивитися в документації по інтерфейсу ListIterator.
Клас Itr, який реалізовує інтерфейс ListIterator є внутрішнім класом класу AbstractList. ArrayList є нащадком класу AbstractList.
Для того, щоб ітератор міг працювати з певним об’єктом, клас даного об’єкту повинен реалізовувати інтерфейс Iterable:
<syntaxhighlight lang="java">
public interface Iterable<E>
{
Iterator<E> iterator();
}
</syntaxhighlight>
Інтерфейс Collection розширює даний інтерфейс.
Можна також перебрати елементи за допомогою перевантаженого з виходом java 5 циклу for (так званого “for each”):
<syntaxhighlight lang="java">
for (String str : a1) {
System.out.print(str+" ");
}
</syntaxhighlight>
При компіляції даний цикл перетворюється компілятором у цикл із ітератором.
ArrayList можна також перетворити у звичайний масив за допомогою методу toArray():
<syntaxhighlight lang="java">
String strArray[]= new String[a1.size()];
strArray=a1.toArray(strArray);
System.out.println(strArray[0]);
</syntaxhighlight>
Якщо ви погано розумієте вищенаведений приклад і як усе працює зверніться до розділів, що описують основні концепції об’єктно-орієнтованого програмування і, зокрема, розберіть детально теми інтерфейсів, абстрактних класів та поліморфізму.
===Клас LinkedList===
LinkedList — це структура даних, що являє собою пов’язаний список елементів (об’єктів).
Різниця між ArrayList та LinkedList полягає в тому, що ArrayList реалізований у вигляді масиву, а LinkedList у вигляді пов’язаних між собою об’єктів. ArrayList швидко виконує читання і заміну елементів (посилань на об’єкти), проте, щоб вставити новий елемнт в середину ArrayList або видалити існуючий в середині ArrayList здійснюється послідовний зсув цілого ряду елементів масиву. В LinkedList доволі швидко відбувається вставлення нового елементу або видалення існуючого. Це відбувається тому, що в середині реалізації LinkedList змінюються лише посилання на попередній і наступний об’єкти (елементи). Проте доступ до об’єктів по індексу в LinkedList відбувається повільніше ніж в ArrayList. Тож загалом, LinkedList корисний, коли необхідно часто вставляти та видаляти елементи зі списку, а в інших випадках краще використовувати ArrayList.
Існує два конструктури LinkedList:
<syntaxhighlight lang="java">
LinkedList()
LinkedList (Collection c)
</syntaxhighlight>
Перший конструктор створює пустий список, а другий – створює пов’язаний список із іншої колекції.
Клас LinkedList розширює клас AbstractSequentalList та реалізує інтерфейси List, Dequeue та Queue. Реалізація останніх двох інтерфейсів (черг) означає, що ми можемо працювати із пов’язаним списком як із стеком з використанням методів pop(), push(), poll(), pollFirst(), pollLast() і т.п. Детальніше дивіться документацію по заданим інтерфейсам.
Далі попрацюємо з LinkedList, який міститиме в якості елементів об’єктні змінні типу Car.
Спочатку реалізуємо наш клас Car:
<syntaxhighlight lang="java">
public class Car {
private String name;
private double price;
private int year;
public Car(String name, double price, int year) {
this.name = name;
this.price = price;
this.year=year;
}
@Override
public String toString() {
return "\n Car [name=" + name + ", price=" + price + ", year=" + year
+ "]";
}
}
</syntaxhighlight>
Клас Car містить лише поля, конструктор, який заповнює дані поля та заміщений метод toString(), який видаватиме нам інформацію про автомобіль у вигляді рядка.
Наступний клас демонструє роботу з LinkedList:
<syntaxhighlight lang="java">
import java.util.ArrayList;
import java.util.LinkedList;
public class TestLinkedList {
private LinkedList<Car> ll=new LinkedList<>();
public static void main(String[] args) {
TestLinkedList t=new TestLinkedList();
t.test();
}
void test(){
Car car1=new Car("Ferrary", 10800, 1995);
Car car2=new Car("Запорожець", 2600, 1989);
ll.add(car1);
ll.add(car2);
//додаємо в початок списку
ll.addFirst(new Car("Alfa Romeo 155", 11678, 2000));
ll.remove(car2); // видалити об'єкт
System.out.println("Після видалення car2: "+ll);
ll.remove(1); //видалити елемент за індексом
System.out.println("Після видалення першого елементу: "+ll);
Car myCar=ll.get(0);
System.out.println("Отриманий елемент за індексом [0]:"+myCar);
ll.set(0, car1); //замінити елемент за індексом
System.out.println("Замінений елемент за індексом [0]"+ll.get(0));
ArrayList<Car> arrList=new ArrayList<Car>();
arrList.add(car1);
arrList.add(car2);
ll.addAll(arrList); //додаємо вміст ArrayList у наш LinkedList
System.out.println("Після додавання ArrayList:"+ll);
}
}
</syntaxhighlight>
Результат виконання програми:
<PRE>
Після видалення car2: [
Car [name=Alfa Romeo 155, price=11678.0, year=2000],
Car [name=Ferrary, price=10800.0, year=1995]]
Після видалення першого елементу: [
Car [name=Alfa Romeo 155, price=11678.0, year=2000]]
Отриманий елемент за індексом [0]:
Car [name=Alfa Romeo 155, price=11678.0, year=2000]
Замінений елемент за індексом [0]
Car [name=Ferrary, price=10800.0, year=1995]
Після додавання ArrayList:[
Car [name=Ferrary, price=10800.0, year=1995],
Car [name=Ferrary, price=10800.0, year=1995],
Car [name=Запорожець, price=2600.0, year=1989]]
</PRE>
Перебирати елементи LinkedList також можна з допомогою ітератора та у циклі for earch.
Детальніше про методи класу дивіться документацію по класу [https://docs.oracle.com/javase/9/docs/api/java/util/LinkedList.html LinkedList].
===Клас HashSet===
HashSet – це клас призначений для зберігання даних у вигляді множини невпорядкованих елементів. Якщо потрібна впорядкована множина, то використовуйте TreeSet. HashSet також не гарантує стабільного порядку збереження об’єктів. Тобто при додаванні об’єктів порядок зберігання елементів змінюється. Вони можуть бути збережені як в кінці множити так і в середині. Якщо потрібен один порядок зберігання об’єктів використовуйте LinkedHashSet.
Сам термін «множина» означає, що елементи не будуть повторюватися. Для зберігання і пошуку елементів використовується хеш-код об’єкта. HashSet також може містити значення null. Власне всередині самої реалізації HashSet використовується клас HashMap, який дозволяє зберігати елементи у вигляді двох складових ключа та хеш-коду. У класі HashSet хеш-код недоступний і використовується неявно для користувача.
Клас HashSet розширює клас AbstractSet та реалізує інтерфейс Set. Також реалізовує інтерфейси Serializable та Clonable.
HashSet має такі конструктори:
<pre>
HashSet()
HashSet (Collection c)
HashSet (int об’єм)
HashSet (int об’єм, float коефіцієнт_заповнення)
</pre>
Коефіцієнт заповнення – це число в межах 0.0 до 1.0, що представляє собою частку заповнення HashSet при якій об’єм HashSet буде збільшений. По замовчуванню в конcтрукторах, що не задають коефіцієнт заповнення, використовується значення 0.75.
Наступний приклад демонструє роботу із HashSet.
<syntaxhighlight lang="java">
import java.util.HashSet;
public class TestHashSet {
HashSet<String> hs=new HashSet<String>();
public static void main(String[] args) {
TestHashSet test=new TestHashSet();
test.test();
}
void test(){
hs.add("Австралія");
hs.add("Україна");
hs.add("США");
System.out.println("1) Три країни: "+hs+" розмір="+hs.size());
hs.add("Австралія"); // помилки не буде, але в HashSet нічого не поміняється
System.out.println("2) Після спроби додати Авcтралію ще раз: "+hs);
hs.remove("США"); //видаляємо США з множини
hs.add("Німеччина");
hs.add("Англія");
hs.add(null);
hs.add(null); // другий раз не додаситься
System.out.println("3)"+hs);
System.out.println("4) Чи містить множина Німеччину? "+hs.contains("Німеччина"));
System.out.println("5) Множина пуста? "+hs.isEmpty());
//можемо також отримати ітератор, або ж перебрати множину у for earch
for (String str:hs){
System.out.println(str);
}
hs.clear(); // очистити
System.out.println("6) Розмір після очищення="+hs.size());
}
}
</syntaxhighlight>
Результат виконання:
<pre>
1) Три країни: [Австралія, Україна, США] розмір=3
2) Після спроби додати Австралію ще раз: [Австралія, Україна, США]
3)[null, Австралія, Німеччина, Україна, Англія]
4) Чи містить множина Німеччину? true
5) Множина пуста? false
null
Австралія
Німеччина
Україна
Англія
6) Розмір після очищення=0
</pre>
Зробити копію хеш множини можна так:
<pre>
HashSet<String> hsc=(HashSet)hs.clone();
</pre>
Слід зауважити, що метод clone() здійснює поверхневе (shadow) копіювання, тобто копіюються лише адреси об’єктів, які містяться у екземплярі класу HashSet, а не самі об’єкти.
При використанні ітератор може викидати виняток ConcurrentModificationException, якщо HashSet було змінено. Щоб уникнути таких випадків слід використовувати методи ітератора для зміни HashSet.
Клас HashSet несинхронізоватий для багатопоточності, проте його можна синхронізувати використовуючи метод synchronizedSet класу Collections:
<pre>
Set s = Collections.synchronizedSet (new HashSet (...))
</pre>
У класу String перевизначені такі методи як equal та hashcode, що дає можливість коректного порівняння їхніх хеш-кодів та значень і уникати випадків, коли будуть додаватися ідентичні рядки, незалежно від того, чи вони зберігаються в різних комірках пам’яті. Проте при використанні власних класів, на практиці для правильного функціонування HashSet (без повторення об'єктів з однаковим станом, наприклад, ідентичними полями) у класах необхідно замістити методи equals() та hashcode() самому. Так, якщо ми створимо класи оболонки, що міститимуть String поле countryName із однаковим значенням, наприклад, “Австрія”, то у нас два об'єкти вважатимуться різні, оскільки у них буде різний Хеш-код, тож вони будуть додані до HashSet. В таких випадках необхідно продумати методи equals() та hashcode().
===Клас LinkedHashSet===
Клас <code>LinkedHashSet</code> розширює клас HashSet не додаючи ніяких нових методів. Працює він дещо довше за HashSet проте зберігає порядок в якому елементи додаються до нього. Відповідно це дозволяє організувати послідовну ітерацію вставлення та витягнення елементів. Всі конструктори та методи роботи з LinkedHashSet аналогічні методам класу HashSet.
===Клас TreeSet===
Клас TreeSet дозволяє створювати відсортовану множину. Тобто елементи не повторюються та зберігаються у відсортованому порядку. Для зберігання елементів застосовується бінарна деревоподібна структура. Об'єкти зберігаються в відсортованому порядку по зростанню. Час доступу та одержання елементів доволі малий, тому клас TreeSet підходить для зберігання великих об’ємів відсортованих даних, які повинні бути швидко знайдені.
Клас TreeSet розширює клас AbstractSet та реалізує інтерфейс NavigableSet. NavigableSet реалізується на базі TreeMap.
В класі доступні чотири конструктори:
<syntaxhighlight lang="java">
TreeSet ()
TreeSet(Collection с)
TreeSet(Comparator компаратор)
TreeSet(SortedSet ss)
</syntaxhighlight>
Третій конструктор дозволяє задавати власний компаратор, відповідно до якого буде відбуватися сортування об’єктів. Так об’єкти класу String не потребують реалізації власного компаратора, проте якщо ви хочете зберігати в класі TreeSet розроблені вами об’єкти, то потрібно задавати компаратор для цих об’єктів. Такий компаратор може реалізовувати сортування об’єктів по певному полю, наприклад по Прізвищу, якщо ваш клас зберігаю інформацію про осіб. Можна реалізувати ланцюжок компараторів з використанням методу thenComparing() класу Comparator.
TreeSet не може містити значення null. Також TreeSet не синхронізований клас, як і інші класи колекцій при потребі його потрібно синхронізувати з використанням методу Collections.synchronizedSet().
Розглянемо приклад роботи TreeSet з компаратором. Використаємо клас Car, який був попередньо використаний при роботі з LinkedList додавши лише гетер та сетер методи.
<syntaxhighlight lang="java">
public class Car {
private String name;
private double price;
private int year;
public Car(String name, double price, int year) {
this.name = name;
this.price = price;
this.year=year;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
@Override
public String toString() {
return "\n Car [name=" + name + ", price=" + price + ", year=" + year+ "]";
}
}
</syntaxhighlight>
Клас компаратора CarsComparator виглядає так:
<syntaxhighlight lang="java">
import java.util.Comparator;
public class CarsComparator implements Comparator {
@Override
public int compare(Car car1, Car car2) {
if(car1.getYear() > car2.getYear())
return 1;
else if (car1.getYear() < car2.getYear())
return -1;
else return 0;
}
}
</syntaxhighlight>
Наша програма з TreeSet:
<syntaxhighlight lang="java">
import java.util.Comparator;
import java.util.TreeSet;
public class TestTreeSet{
CarsComparator comp=new CarsComparator();
TreeSet<Car> ts1=new TreeSet<>(comp);
public static void main(String[] args) {
TestTreeSet t=new TestTreeSet();
t.test();
}
void test(){
Car car1=new Car("Ferrary", 12000, 1988);
Car car2=new Car("Ford", 13000, 1955);
Car car3=new Car("Toyota", 13500, 2003);
Car car4=new Car("Citroen", 12000, 2014);
Car car5=new Car("Mercedes-Benz", 15000, 2011);
ts1.add(car1);
ts1.add(car2);
ts1.add(car3);
ts1.add(car4);
ts1.add(car5);
System.out.println("Сортування по роках: "+ts1);
//Зворотній компаратор для TreeSet(Java8)
TreeSet<Car> ts2=new TreeSet<>(comp.reversed());
ts2.addAll(ts1); //додати вміст попереднього TreeSet у новий
System.out.println("Зворотнє сортування:"+ts2);
}
}
</syntaxhighlight>
Результат виконання:
<pre>
Сортування по роках: [
Car [name=Ford, price=13000.0, year=1955],
Car [name=Ferrary, price=12000.0, year=1988],
Car [name=Toyota, price=13500.0, year=2003],
Car [name=Mercedes-Benz, price=15000.0, year=2011],
Car [name=Citroen, price=12000.0, year=2014]]
Зворотнє сортування:[
Car [name=Citroen, price=12000.0, year=2014],
Car [name=Mercedes-Benz, price=15000.0, year=2011],
Car [name=Toyota, price=13500.0, year=2003],
Car [name=Ferrary, price=12000.0, year=1988],
Car [name=Ford, price=13000.0, year=1955]]
</pre>
Реалізація інтерфейсу NavigableSet забезпечила клас TreeSet доволі корисними методами як то ceiling(), floor(), headset(), higher(), pollFirst(), pollLast(), subset(), tailSet(), iterator(), descendingIterator(), descendingSet(). Використовуючи їх можна організувати доволі зручний вибір елементів з TreeSet. Див. детальніше документацію по TreeSet.
===Клас PriorityQueue===
PriorityQueue дозволяє реалізувати чергу на основі пріоритету. Така черга може бути корисна, наприклад, у разі необхідності обслуговування клієнтів згідно пріоритету. При зберіганні чисел в пріоритетній черзі, така черга гарантує, що першим елементом завжди буде найменший елемент. При цьому не гарантується ніякий стабільний послідовний порядок збереження елементів. Після додавання або видалення елементу з пріоритетної черги, порядок зберігання елементів в цій черзі змінюється таким чином, що в голові черги опиняється найменший елемент згідно його природнього порядку або згідно заданого компаратора.
<syntaxhighlight lang="java">
PriorityQueue має наступні конструктори:
PriorityQueue() //початковий об’єм становить 11
PriorityQueue(int початковий_об’єм)
PriorityQueue(Comparator comparator)
PriorityQueue(int початковий_об'єм, Comparator компаратор)
PriorityQueue(Collection с)
PriorityQueue(PriorityQueue с)
PriorityQueue(SortedSet с)
</syntaxhighlight>
Таким чином в разі потреби можна задати власний компаратор для видачі елементів у потрібному нам порядку.
PriorityQueue не може містити null. PriorityQueue розширює AbstractQueue та реалізує інтерфейси Serializable, Iterable, Collection, Queue.
Реалізація інтерфейсу Queue говорить нам, що в PriorityQueue доступні такі методи роботи з чергою:
*add(E e) – додати вказаний елемент у чергу
*element() – отримати, але не видаляти, елемент з голови черги
*offer(E e)- додати визначений елемент у чергу
*peek() – отримати елемент з голови черги, але не видаляти його. Повертає null, якщо черга порожня
*poll() – отримати та видалити елемент з голови черги
*remove() - отримати та видалити елемент з голови черги
Крім того в PriorityQueue достуні методи, що наявні і в інших колекціях як то: clear(), comparator(), contains(), iterator(), spliterator(), size(), toArray() тощо.
Приклад:
<syntaxhighlight lang="java">
import java.util.PriorityQueue;
public class TestPriorityQueue {
public static void main(String[] args) {
PriorityQueue<Integer> pq= new PriorityQueue<>(11);
pq.add(750);
pq.add(50);
pq.offer(1);
pq.add(300);
pq.add(25);
pq.add(2);
pq.offer(20);
pq.add(5);
pq.add(40);
System.out.println("Порядок зберігання елементів"+pq);
// Отримуємо і видаляємо елемент з голови черги
while (!pq.isEmpty()) {
System.out.println("Отримали: "+pq.poll());
System.out.println("Новий порядок:"+pq);
}
}
}
</syntaxhighlight>
Результат:
<pre>
Порядок зберігання елементів[1, 5, 2, 25, 300, 50, 20, 750, 40]
Отримали: 1
Новий порядок:[2, 5, 20, 25, 300, 50, 40, 750]
Отримали: 2
Новий порядок:[5, 25, 20, 750, 300, 50, 40]
Отримали: 5
Новий порядок:[20, 25, 40, 750, 300, 50]
Отримали: 20
Новий порядок:[25, 50, 40, 750, 300]
Отримали: 25
Новий порядок:[40, 50, 300, 750]
Отримали: 40
Новий порядок:[50, 750, 300]
Отримали: 50
Новий порядок:[300, 750]
Отримали: 300
Новий порядок:[750]
Отримали: 750
Новий порядок:[]
</pre>
Таким чином за допомогою методу poll() (його можна також замінити методом remove()), ми можемо отримувати елементи масиву у відсортованому порядку, незважаючи на те, що в самій пріоритетній черзі елементи зберігаються у іншому порядку.
===Клас ArrayDeque===
ArrayDeque (читається як аррейдек) – це клас який забезпечує двосторонню чергу. Іншими словами - це автоматично зростаючий масив, що дозволяє нам додавати або видаляти елементи з обох боків черги. ArrayDeque може бути використано як стек (LIFO, останній ввійшов - перший вийшов) або ж як черга (FIFO, перший ввійшов - перший вийшов).
ArrayDeque не може містити в якості елемента null.
Клас ArrayDeque швидший за клас Stack, якщо використовувати його в якості стеку і швидший за LinkedList, якщо використовувати в якості черги.
ArrayDeque розширює клас AbstractCollection та реалізує інтерфейси Deque, Cloneable, Serializable. Таким чином ми можемо використовувати для роботи з даним класом, як методи інтерфейсу Deque (який розширює інтерфейс Queue) так і методи інтерфейсу Collection.
Якщо використовується ітератор, то він буде викидати виняток ConcurrentModificationException, якщо вміст ArrayDeque був модифікований після створення ітератора. Таким чином ітератор необхідно з обережністю використовувати з ArrayDeque.
В ArrayDeque доступні наступні конструктори:
<syntaxhighlight lang="java">
ArrayDeque() // пустий ArrayDeque з початковим об’ємом 16 елентів
ArrayDeque(Collection c) // міститиме елементи колекції в порядку, що повертає ітератор даної колекції
ArrayDeque(int numElements) // дозволяє задати початковий об’єм
</syntaxhighlight>
При потребі збільшення об'єму, то він автоматично збільшується вдвічі.
Наступний приклад демонструє роботу із ArrayDeque у вигляді стека та у в вигляді черги:
<syntaxhighlight lang="java">
import java.util.ArrayDeque;
public class TestArrayDeque {
public static void main(String[] args) {
ArrayDeque<String> ad=new ArrayDeque<>();
System.out.println("Використання в якості стеку");
ad.push("Перший"); // метод інтерфуйсу Deque
ad.push("Другий");
ad.push("Третій");
System.out.println("Перший елемент ArrayDeque: "+ad.getFirst());//Отримуємо перший елемент, але не видаляємо
System.out.println("Вміст ArrayDeque: "+ad);
System.out.println(ad.pop()); //Отримуємо і видаляємо з вершини стеку
System.out.println(ad.pop()); //еквівалентно до removeFirst()
System.out.println(ad.pop());
//System.out.println(ad.pop()); //ArrayDeque порожній видасть NoSuchElementException
System.out.println();
System.out.println("Використання в якості черги");
ad.offer("Перший");
ad.offer("Другий");
ad.offer("Третій");
System.out.println("Перший елемент ArrayDeque: "+ad.getFirst());//Отримуємо перший елемент, але не видаляємо
System.out.println("Вміст ArrayDeque: "+ad);
System.out.println(ad.poll()); //витягнути і видалити з голови
System.out.println(ad.poll());
System.out.println(ad.poll());
System.out.println(ad.poll());
}
}
</syntaxhighlight>
Результат роботи:
<pre>
Використання в якості стеку
Перший елемент ArrayDeque: Третій
Вміст ArrayDeque: [Третій, Другий, Перший]
Третій
Другий
Перший
Використання в якості черги
Перший елемент ArrayDeque: Перший
Вміст ArrayDeque: [Перший, Другий, Третій]
Перший
Другий
Третій
null
</pre>
Дивіться також офіційну документацію по: [https://docs.oracle.com/javase/8/docs/api/java/util/Deque.html Інтерфейсу Deque] та
[https://docs.oracle.com/javase/8/docs/api/java/util/Collection.html Інтерфейсу Collection]
===Клас EnumSet===
Клас EnumSet — це одна з спеціалізованих реалізацій інтерфейсу Set для використання з перелічуваним типом даних (enum). EnumSet розширює AbstractSet та реалізує Cloneable та Serializable інтерфейси Java. EnumSet заміщує більшість методів інтерфейсів Set та Collection. EnumSet доволі швидка реалізація Set, швидша за HashSet, тому що всередині використовуються побітові операції, а не хеш-коди об’єктів.
EnumSet не синхронізований і повинен бути синхронізований ззовні, наприклад з використанням методу Collections.synchronizedSet(java.util.Set).
Всі елементи enum множини мають походити від єдиного перелічуваного типу, що вказується, коли множина створюється явно або неявно. EnumSet не дозволяє додавати значення null. Елементи зберігаються в порядку в якому їх подано в переліченні (enum).
EnumSet використовує безвідмовний (fail-safe) ітератор, що працює з копією EnumSet, тобто ітератор не буде викидати виняток ConcurrentModificationException, в разі зміни даних множини поза ітератором.
EnumSet – це відкритий абстрактний клас, який не має відкритого конструктора, для створення об’єкту EnumSet використовуються відповідні статичні факторні методи. В даних методах для створення EnumSet використовуються дві реалізації даного класу RegularEnumSet(для зберігання невеликих перелічень, до 64) та JumboEnumSet (для зберігання великих перелічень). Наступний приклад демонструє роботу з EnumSet:
<syntaxhighlight lang="java">
import java.util.EnumSet;
enum Colors
{
RED, GREEN, YELLOW, BLUE, BLACK
};
public class TestEnumSet
{
public static void main(String[] args)
{
// Створюємо множину
EnumSet<Colors> set1, set2, set3, set4, set5;
// Додаємо окремі елементи, порядок зберігання буде згідно порядку перелічення
set1 = EnumSet.of(Colors.RED, Colors.GREEN,
Colors.BLACK, Colors.BLUE);
// Заповнити тими елемнтами, яких нема у вказаній множині
set2 = EnumSet.complementOf(set1);
// Всі із даного перелічення
set3 = EnumSet.allOf(Colors.class);
// Додати усі елементи перелічення в діапазоні від GREEN до BLACK
set4 = EnumSet.range(Colors.GREEN, Colors.BLACK);
// створити пусту множину перелічень відповідного типу
set5= EnumSet.noneOf(Colors.class);
System.out.println("Set 1: " + set1);
System.out.println("Set 2: " + set2);
System.out.println("Set 3: " + set3);
System.out.println("Set 4: " + set4);
System.out.println("Set 5: " + set5);
}
}
</syntaxhighlight>
Результат роботи:
<pre>
Set 1: [RED, GREEN, BLUE, BLACK]
Set 2: [YELLOW]
Set 3: [RED, GREEN, YELLOW, BLUE, BLACK]
Set 4: [GREEN, YELLOW, BLUE, BLACK]
Set 5: []
</pre>
==Інтерфейс Map та класи, що його реалізують==
'''''Зіставлення''''' (англ. ''map'', також перекладають як ''відображення'')– це об’єкт який зіставляє ключ із відповідним значенням (key/value). Маючи ключ ви можете знайти його значення. І ключ, і значення є об’єктами. Ключ може бути унікальним, а значення може повторюватися. Деякі зіставлення можуть приймати null ключ і null значення, інші не можуть.
Зіставлення не підтримують Iterable інтерфейс. Тому ви не зможете використати ітератор для перебору вмісту зіставлення. Також ви не можете використовувати цикл for each. Проте можна перетворити зіставлення у інший тип колекції і вже на ньому можна отримати ітератор.
Основу зіставлень складає інтерфейс '''Map'''.
Map є узагальненим (див. розділ [[Освоюємо Java/Узагальнення|Узагальнення]]) і оголошений так:
<code>
interface Map<K, V>
</code>
де K – визначає тип ключа, а V визначає тип значення.
Інтерфейс '''SortedMap''' розширює інтерфейс Map і забезпечує, що вміст зберігається в порядку зростання, базуючись на значенні ключа.
Інтерфейс '''NavigableMap''' розширює SortedMap і забезпечує повернення вмісту базуючись на схожості ключа або ключів.
Інтерфейс '''Map.Entry''' – вкладений в Map інтерфейс і забезпечує роботу із вмістом зіставлення.
Класи, що реалізують інтерфейс Map наведені в таблиці.
{| class="wikitable" style="text-align: left; width: 800px;"
!Клас||Опис
|-
|AbstractMap ||Реалізує більшість інтерфейсу Map
|-
|EnumMap ||Розширює AbstractMap для використання з перелічуваними ключами.
|-
|HashMap ||HashMap розширює AbstractMap, щоб використовувати хеш таблиці.
|-
|TreeMap ||TreeMap розширює AbstractMap для використання дерев.
|-
|WeakHashMap ||WeakHashMap розширює AbstractMap для використання слабких ключів, що забезпечує утилізацію невикористовуваних ключів збирачем мусору
|-
|LinkedHashMap ||LinkedHashMap розширює HashMap дозволяючи ітерацію з вводом елементів в певному порядку
|-
|IdentityHashMap ||IdentityHashMap розширює AbstractMap і використовує рівність посилань при порівнянні документів (для специфічних задач)
|}
===Клас HashMap===
HashMap розширює AbstractMap та реалізує інтерфейс Map. Клас не додає власних методів. Клас використовує хеш таблиці для зберігання зіставлення. HashMap не гарантує порядок елементів.
<code>
HashMap має наступні конструктори:
HashMap( )
HashMap(Map<? extends K, ? extends V> m)
HashMap(int capacity)
HashMap(int capacity, float fillRatio)
</code>
Перший створює HashMap по замовчуванню. Другий створює хеш зіставлення використовуючи елементи m. Третій задає ємність хеш зіставлення. Четвертий задає ємність(по замовчуванню 16) та коефіцієнт заповнення (по замовчуванню 0.75).
<syntaxhighlight lang="java">
package Map;
import java.util.HashMap;
import java.util.*;
import java.util.Set;
public class TestHashMap {
public static void main(String[] args) {
// створюємо об'єкт HashMap з назвою capitalCities
HashMap<String, String> capitalCities = new HashMap<String, String>();
// додаємо ключі і значення (Країна, Столиця)
capitalCities.put("Англія", "Лондон");
capitalCities.put("Німеччина", "Берлін");
capitalCities.put("Норвегія", "Осло");
capitalCities.put("США", "Вашингтон");
//вивести значення об'єкту capitalCities
System.out.println(capitalCities);
//звернутися до HashMap використовуючи ключ
System.out.println(" Отримати столицю США");
System.out.println(capitalCities.get("США"));
//Видалити Англію
System.out.println(" Видаляємо Англію");
capitalCities.remove("Англія");
System.out.println(capitalCities);
//видалити все можна так
//capitalCities.clear();
// друкуємо ключі
System.out.println(" Ключі:");
for (String i : capitalCities.keySet()) {
System.out.println(i);
}
// друкуємо значення
System.out.println(" Значення:");
for (String i : capitalCities.values()) {
System.out.println(i);
}
// Друкувати ключі і значення
System.out.println(" Ключі і значення:");
for (String i : capitalCities.keySet()) {
System.out.println("key: " + i + " value: " + capitalCities.get(i));
}
System.out.println("Використовуємо Map.Entry");
//одержати множину входжень
Set<Map.Entry<String,String>> set=capitalCities.entrySet();
//вивести множину входжень
for(Map.Entry<String, String> me: set) {
System.out.print(me.getKey()+": ");
System.out.println(me.getValue());
}
}
}
</syntaxhighlight>
Результат:
<pre>
{США=Вашингтон, Англія=Лондон, Норвегія=Осло, Німеччина=Берлін}
Отримати столицю США
Вашингтон
Видаляємо Англію
{США=Вашингтон, Норвегія=Осло, Німеччина=Берлін}
Ключі:
США
Норвегія
Німеччина
Значення:
Вашингтон
Осло
Берлін
Ключі і значення:
key: США value: Вашингтон
key: Норвегія value: Осло
key: Німеччина value: Берлін
Використовуємо Map.Entry
США: Вашингтон
Норвегія: Осло
Німеччина: Берлін
</pre>
Ключі і значення в HashMap є об’єктами. Якщо ми хочемо використати, наприклад, числа цілого типу (іnt) то використовуватиметься клас обгортка Integer. Так само і для інших примітивних типів.
===Клас TreeMap===
Клас '''TreeMap''' розширює '''AbstractMap''' та реалізує інтерфейс '''NavigableMap'''. TreeMap не містить методів крім тих, що визначені у NavigableMap та класі AbstractMap. Що забезпечує зберігання зіставлень за допомогою деревовидної структури. TreeMap забезпечує зберігання пар ключ/значення у відсортованому порядку (в порядку зростання), що забезпечує швидкий доступ до елементів. TreeMap по замовчуванню сортується за ключами. Для задання іншого сортування використовують компаратор.
TreeMap узагальнений клас і оголошується так:
<code>
class TreeMap<K,V>
</code>
де K – задає тип ключа, а V – задає тип значення.
TreeMap визначає наступні конструктори:
<pre>
TreeMap( )
TreeMap(Comparator<? super K> comp)
TreeMap(Map<? extends K, ? extends V> m)
TreeMap(SortedMap<K, ? extends V> sm)
</pre>
Перший створює пусте деревовидне зіставлення, що буде відсортоване використовуючи природній порядок ключів. Другий створює пусте зіставлення, що буде відсортоване використовуючи компаратор. Третій створює деревовидне зіставлення із входжень зіставлення m, що буде відсортоване в природньому порядку. Третій ініціалізує деревовидне зіставлення входженнями із sm з порядком сортуванням того ж sm.
<syntaxhighlight lang="java">
package Map;
import java.util.TreeMap;
import java.util.*;
public class TestTreeMap {
public static void main(String[] args) {
TreeMap<String, Integer> countries = new TreeMap<String, Integer>();
countries.put("Гваделупа",1);
countries.put("США",2);
countries.put("Гаваї",3);
countries.put("Бельгія", 4);
//вивести вміст
System.out.println(countries);
//вивести останній ключ
System.out.println("Останній ключ:"+countries.lastKey());
countries.put("Албанія", 5);
System.out.println(" Вміст зіставлення:");
// взяти множину входжень
Set<Map.Entry<String, Integer>> set = countries.entrySet();
// Вивести елементи
for(Map.Entry<String, Integer> me : set) {
System.out.print(me.getKey() + ": ");
System.out.println(me.getValue());
}
System.out.println();
}
}
</syntaxhighlight>
Результат:
<pre>
{Бельгія=4, Гаваї=3, Гваделупа=1, США=2}
Останній ключ:США
Вміст зіставлення:
Албанія: 5
Бельгія: 4
Гаваї: 3
Гваделупа: 1
США: 2
</pre>
===Клас LinkedHashMap===
Клас '''LinkedHashMap''' розширює '''HashMap''' і підтримує пов'язаний список записів у зіставленні, в порядку в якому вони додавались. При необхідності можна задати зіставлення в якому записи будуть зберігатись в порядку останнього доступу.
LinkedHashMap має наступні конструктори:
<pre>
LinkedHashMap( )
LinkedHashMap(Map<? extends K, ? extends V> m)
LinkedHashMap(int capacity)
LinkedHashMap(int capacity, float fillRatio)
LinkedHashMap(int capacity, float fillRatio, boolean Order)
</pre>
Перший конструктор створює LinkedHashMap по замовчуванню. Другий ініціалізує LinkedHashMap елементами із зіставлення m. Третій конструктор задає ємність. Четвертий задає ємність та коефіцієнт заповнення. Ємність по замовчуванню - 16, а коефіцієнт заповнення по замовчуванню становить 0,75. Останній конструктор дозволяє задати порядок заповнення зіставлення, чи записи зберігатимуться в порядку вставлення чи в порядку останнього доступу. Якщо Order є true тоді використовуються порядок зберігання по порядку доступу, якщо false тоді використовується порядок вставлення.
LinkedHashMap додає лише один власний метод - removeEldestEntry. Якщо його замістити так, щоб він повертав true, то буде видалятися найстаріший елемент при використанні методів put() та putAll(). Таким чином можна, наприклад, встановити, щоб в зіставлення було б не більше певної кількості елементів.
<syntaxhighlight lang="java">
var cache = new LinkedHashMap<K, V>(128, 0.75F, true)
{
protected boolean removeEldestEntry(Map.Entry<K, V> eldest)
{
return size() > 100; //якщо елементів більше ста, то старі записи видалятимуться
}
};
</syntaxhighlight>
(необхідно описати ще EnumMap та IdentityHashMap)
==Алгоритми==
В структурі колекцій існує клас Collections, який надає ряд зручних статичних методів для роботи з даними. Нагадаємо, що статичні методи – це методи, які не потребують створення об'єктів і реалізують ряд додаткових алгоритмів по роботі з колекціями, як то сортування колекцій, знаходження максимального і мінімального елементу, перемішування, копіювання і т.п.
(необхідно розширити)
==Arrays==
(Ще не написано)
==Успадковані класи ==
Ранні версії Java не включали структуру Collections. Там було визначено декілька класів та інтерфейсів, що надавали методи для зберігання об'єктів. Структура Collections була додана в Java 2. (j2se 1.2). Тоді початкові класи були перероблені для підтримки інтерфейсів колекцій. Ці ранні класи також знані як успадковані класи (Legacy classes). В Java 5 успадковані класи та інтерфейси були перероблені для підтримки узагальнень. Їх підтримують, тому що до сих пір існує код, який їх використовує. Успадковані класи - синхронізовані. Класи входять в пакет java.util. Успадкованими є наступні класи:
* Dictionary
* HashTable
* Properties
* Stack
* Vector
Успадкованим є інтерфейс Enumaration, на заміну якому прийшов інтерфейс Iterator. Enumaration інтерфейс до сих пір використовується в декількох методах класів Vector та Properties.
==Додаткова література==
* [http://idndist.lp.edu.ua/moodle/library/books/0021/index06.html Плешко Д.Д. Лекція VІ. Колекції. (Об'єктно-орієнтоване програмування в Java)]
* [https://www.geeksforgeeks.org/collections-in-java-2/ Колекції в Java(англ)]
* [https://dzone.com/articles/working-with-hashcode-and-equals-in-java Робота з hashcode() та equals() (англ)]
* [https://docs.oracle.com/javase/8/docs/technotes/guides/collections/overview.html Огляд структори колекцій(англ)]
* [https://ukr-technologies.blogspot.com/search/label/Колекції Колекції Java]
{{Гортання сторінок|Графічний інтерфейс користувача|Менеджери розташування}}
[[Категорія:Освоюємо Java]]
se4lkkbqdpaza90lvwoyrc4bz49j36k
36861
36860
2022-08-03T17:58:41Z
Володимир Груша
985
/* Arrays */
wikitext
text/x-wiki
При об’єктно орієнтованому програмуванні доводиться працювати з великою кількістю об’єктів. Зручно мати засоби групування об’єктів. Для цих цілей в Java розроблено набір інтерфейсів і класів на їх основі під назвою колекції . В основі ієрархії колекцій знаходиться інтерфейс Collection.
==Структура колекцій==
Згадаймо, що інтерфейс – це клас, який не містить реалізації методів, а лише їхні оголошення. Можна реалізувати безліч реалізацій інтерфейсу. Програмісту, який використовуватиме ці реалізації, достатньо знати базовий інтерфейс для роботи з його реалізаціями, тобто знати методи, які передбачає даний інтерфейс.
Collection – базовий інтерфейс, крім нього на його основі в структурі колекцій є ще декілька інтерфейсів, які розширюють базовий інтерфейс Collection. Зокрема, List, Set та SortedSet. Окремо виділяють ще інтерфейс Map. Він не походить на пряму від інтерфейсу Collection, проте його також відносять до колекцій. На їх основі створено набір класів, які згодяться програмістам для більшості випадків роботи з набором об’єктів. Тож вам не прийдеться самим їх реалізовувати.
Якщо вам цікаво, для чого стільки різних класів в колекціях? Суть в тому, що різні класи по різному реалізовують роботу з даними. Одні класи швидше здійснюють читання даних, інші вставлення і видалення, одні перевіряють, щоб не було дублювань, інші дозволяють вставляти дані за певним ключем і т.п. Доволі важливо підібрати клас, який найкраще підходить для вашого завдання і забезпечить найбільшу швидкодію. Особливо це актуально, коли кількість об’єктів величезна.
==Реалізації інтерфейсу Collection==
===Клас ArrayList та використання ітератора===
Клас ArrayList призначений для читання об'єктів по індексу. Тож не дарма у назві є слово Array (масив). Після створення колекції на основі ArrayList, прочитати дані можна кількома способами. Наступний приклад демонструє створення ArrayList, його наповнення об'єктами типу String та їх читання за допомогою методу get (int index) та за допомогою ітератора.
<syntaxhighlight lang="java">
import java.util.ArrayList;
import java.util.ListIterator;
public class TestArrayList {
private ArrayList<String> a1;
public static void main(String[] args) {
TestArrayList test = new TestArrayList();
test.create();
test.getData();
test.iterateData();
}
void create() {
//створюємо і наповнюємо ArrayList
a1 = new ArrayList<String>();
a1.add("Привіт");
a1.add("тобі");
a1.add("божевільний");
a1.add("світе!");
}
//читаємо дані по індексу
void getData() {
for (int i = 0; i < a1.size(); i++) {
System.out.print(a1.get(i) + " ");
}
}
//Читаємо вміст ArrayList з допомогою ітератора
void iterateData() {
ListIterator<String> it = a1.listIterator();
while (it.hasNext()) {
System.out.print(it.next() + " ");
}
}
}
</syntaxhighlight>
Результат:
<PRE>Привіт тобі божевільний світе! Привіт тобі божевільний світе!</PRE>
Крім вищенаведених способів можна передати вміст ArrayList у звичайний масив за допомогою методу toArray(). Якщо ви хочете детально розібратися з ArrayList і його методами, то для цього також дивіться інформацію про інтерфейси Collection, List та Iterator.
Окремо розглянемо перегляд даних з допомогою ітератора.
<syntaxhighlight lang="java">ListIterator<String> it=a1.listIterator();</syntaxhighlight>
Таким чином створюється об’єкт ітератора, посилання на який передається об'єктній змінній it типу ListIterator. ListIterator – це інтерфейс, який розширює інтерфейс Iterator декількома новими методами. Базовими ж методами інтерфейсу Iterator є ті, що використані у нас в програмі, а саме:
* boolean hasNext() – повертає true, якщо ітерація має наступний елемент
* E next() - повертає наступний елемент ітерації (буква E вказує, що це може бути елемент будь-якого типу, детальніше див. розділ [[Освоюємо_Java/Узагальнення|Узагальнення]])
* void remove() – знищує останній елемент, що повертався ітератором
Тож у коді бачимо:
<syntaxhighlight lang="java">
while(it.hasNext()){
System.out.print(it.next()+" ");
}
</syntaxhighlight>
Цикл працює поки є елементи в ітераторі. Перевірка здійснюється за допомогою методу hasNext. А вивід елементів здійснюється за допомогою методу next. Перевірка за допомогою hasNext необхідна через те, що в разі відсутності наступного елементу при виклику методу next буде викинуто виняток NoSuchElementExeption.
Інтерфейсом ListIterator передбачено ще такі методи як add, hasPrevious, next, nextIndex, previous, previousIndex, set. Назви методів говорять самі за себе. Детальніше ви можете подивитися в документації по інтерфейсу ListIterator.
Клас Itr, який реалізовує інтерфейс ListIterator є внутрішнім класом класу AbstractList. ArrayList є нащадком класу AbstractList.
Для того, щоб ітератор міг працювати з певним об’єктом, клас даного об’єкту повинен реалізовувати інтерфейс Iterable:
<syntaxhighlight lang="java">
public interface Iterable<E>
{
Iterator<E> iterator();
}
</syntaxhighlight>
Інтерфейс Collection розширює даний інтерфейс.
Можна також перебрати елементи за допомогою перевантаженого з виходом java 5 циклу for (так званого “for each”):
<syntaxhighlight lang="java">
for (String str : a1) {
System.out.print(str+" ");
}
</syntaxhighlight>
При компіляції даний цикл перетворюється компілятором у цикл із ітератором.
ArrayList можна також перетворити у звичайний масив за допомогою методу toArray():
<syntaxhighlight lang="java">
String strArray[]= new String[a1.size()];
strArray=a1.toArray(strArray);
System.out.println(strArray[0]);
</syntaxhighlight>
Якщо ви погано розумієте вищенаведений приклад і як усе працює зверніться до розділів, що описують основні концепції об’єктно-орієнтованого програмування і, зокрема, розберіть детально теми інтерфейсів, абстрактних класів та поліморфізму.
===Клас LinkedList===
LinkedList — це структура даних, що являє собою пов’язаний список елементів (об’єктів).
Різниця між ArrayList та LinkedList полягає в тому, що ArrayList реалізований у вигляді масиву, а LinkedList у вигляді пов’язаних між собою об’єктів. ArrayList швидко виконує читання і заміну елементів (посилань на об’єкти), проте, щоб вставити новий елемнт в середину ArrayList або видалити існуючий в середині ArrayList здійснюється послідовний зсув цілого ряду елементів масиву. В LinkedList доволі швидко відбувається вставлення нового елементу або видалення існуючого. Це відбувається тому, що в середині реалізації LinkedList змінюються лише посилання на попередній і наступний об’єкти (елементи). Проте доступ до об’єктів по індексу в LinkedList відбувається повільніше ніж в ArrayList. Тож загалом, LinkedList корисний, коли необхідно часто вставляти та видаляти елементи зі списку, а в інших випадках краще використовувати ArrayList.
Існує два конструктури LinkedList:
<syntaxhighlight lang="java">
LinkedList()
LinkedList (Collection c)
</syntaxhighlight>
Перший конструктор створює пустий список, а другий – створює пов’язаний список із іншої колекції.
Клас LinkedList розширює клас AbstractSequentalList та реалізує інтерфейси List, Dequeue та Queue. Реалізація останніх двох інтерфейсів (черг) означає, що ми можемо працювати із пов’язаним списком як із стеком з використанням методів pop(), push(), poll(), pollFirst(), pollLast() і т.п. Детальніше дивіться документацію по заданим інтерфейсам.
Далі попрацюємо з LinkedList, який міститиме в якості елементів об’єктні змінні типу Car.
Спочатку реалізуємо наш клас Car:
<syntaxhighlight lang="java">
public class Car {
private String name;
private double price;
private int year;
public Car(String name, double price, int year) {
this.name = name;
this.price = price;
this.year=year;
}
@Override
public String toString() {
return "\n Car [name=" + name + ", price=" + price + ", year=" + year
+ "]";
}
}
</syntaxhighlight>
Клас Car містить лише поля, конструктор, який заповнює дані поля та заміщений метод toString(), який видаватиме нам інформацію про автомобіль у вигляді рядка.
Наступний клас демонструє роботу з LinkedList:
<syntaxhighlight lang="java">
import java.util.ArrayList;
import java.util.LinkedList;
public class TestLinkedList {
private LinkedList<Car> ll=new LinkedList<>();
public static void main(String[] args) {
TestLinkedList t=new TestLinkedList();
t.test();
}
void test(){
Car car1=new Car("Ferrary", 10800, 1995);
Car car2=new Car("Запорожець", 2600, 1989);
ll.add(car1);
ll.add(car2);
//додаємо в початок списку
ll.addFirst(new Car("Alfa Romeo 155", 11678, 2000));
ll.remove(car2); // видалити об'єкт
System.out.println("Після видалення car2: "+ll);
ll.remove(1); //видалити елемент за індексом
System.out.println("Після видалення першого елементу: "+ll);
Car myCar=ll.get(0);
System.out.println("Отриманий елемент за індексом [0]:"+myCar);
ll.set(0, car1); //замінити елемент за індексом
System.out.println("Замінений елемент за індексом [0]"+ll.get(0));
ArrayList<Car> arrList=new ArrayList<Car>();
arrList.add(car1);
arrList.add(car2);
ll.addAll(arrList); //додаємо вміст ArrayList у наш LinkedList
System.out.println("Після додавання ArrayList:"+ll);
}
}
</syntaxhighlight>
Результат виконання програми:
<PRE>
Після видалення car2: [
Car [name=Alfa Romeo 155, price=11678.0, year=2000],
Car [name=Ferrary, price=10800.0, year=1995]]
Після видалення першого елементу: [
Car [name=Alfa Romeo 155, price=11678.0, year=2000]]
Отриманий елемент за індексом [0]:
Car [name=Alfa Romeo 155, price=11678.0, year=2000]
Замінений елемент за індексом [0]
Car [name=Ferrary, price=10800.0, year=1995]
Після додавання ArrayList:[
Car [name=Ferrary, price=10800.0, year=1995],
Car [name=Ferrary, price=10800.0, year=1995],
Car [name=Запорожець, price=2600.0, year=1989]]
</PRE>
Перебирати елементи LinkedList також можна з допомогою ітератора та у циклі for earch.
Детальніше про методи класу дивіться документацію по класу [https://docs.oracle.com/javase/9/docs/api/java/util/LinkedList.html LinkedList].
===Клас HashSet===
HashSet – це клас призначений для зберігання даних у вигляді множини невпорядкованих елементів. Якщо потрібна впорядкована множина, то використовуйте TreeSet. HashSet також не гарантує стабільного порядку збереження об’єктів. Тобто при додаванні об’єктів порядок зберігання елементів змінюється. Вони можуть бути збережені як в кінці множити так і в середині. Якщо потрібен один порядок зберігання об’єктів використовуйте LinkedHashSet.
Сам термін «множина» означає, що елементи не будуть повторюватися. Для зберігання і пошуку елементів використовується хеш-код об’єкта. HashSet також може містити значення null. Власне всередині самої реалізації HashSet використовується клас HashMap, який дозволяє зберігати елементи у вигляді двох складових ключа та хеш-коду. У класі HashSet хеш-код недоступний і використовується неявно для користувача.
Клас HashSet розширює клас AbstractSet та реалізує інтерфейс Set. Також реалізовує інтерфейси Serializable та Clonable.
HashSet має такі конструктори:
<pre>
HashSet()
HashSet (Collection c)
HashSet (int об’єм)
HashSet (int об’єм, float коефіцієнт_заповнення)
</pre>
Коефіцієнт заповнення – це число в межах 0.0 до 1.0, що представляє собою частку заповнення HashSet при якій об’єм HashSet буде збільшений. По замовчуванню в конcтрукторах, що не задають коефіцієнт заповнення, використовується значення 0.75.
Наступний приклад демонструє роботу із HashSet.
<syntaxhighlight lang="java">
import java.util.HashSet;
public class TestHashSet {
HashSet<String> hs=new HashSet<String>();
public static void main(String[] args) {
TestHashSet test=new TestHashSet();
test.test();
}
void test(){
hs.add("Австралія");
hs.add("Україна");
hs.add("США");
System.out.println("1) Три країни: "+hs+" розмір="+hs.size());
hs.add("Австралія"); // помилки не буде, але в HashSet нічого не поміняється
System.out.println("2) Після спроби додати Авcтралію ще раз: "+hs);
hs.remove("США"); //видаляємо США з множини
hs.add("Німеччина");
hs.add("Англія");
hs.add(null);
hs.add(null); // другий раз не додаситься
System.out.println("3)"+hs);
System.out.println("4) Чи містить множина Німеччину? "+hs.contains("Німеччина"));
System.out.println("5) Множина пуста? "+hs.isEmpty());
//можемо також отримати ітератор, або ж перебрати множину у for earch
for (String str:hs){
System.out.println(str);
}
hs.clear(); // очистити
System.out.println("6) Розмір після очищення="+hs.size());
}
}
</syntaxhighlight>
Результат виконання:
<pre>
1) Три країни: [Австралія, Україна, США] розмір=3
2) Після спроби додати Австралію ще раз: [Австралія, Україна, США]
3)[null, Австралія, Німеччина, Україна, Англія]
4) Чи містить множина Німеччину? true
5) Множина пуста? false
null
Австралія
Німеччина
Україна
Англія
6) Розмір після очищення=0
</pre>
Зробити копію хеш множини можна так:
<pre>
HashSet<String> hsc=(HashSet)hs.clone();
</pre>
Слід зауважити, що метод clone() здійснює поверхневе (shadow) копіювання, тобто копіюються лише адреси об’єктів, які містяться у екземплярі класу HashSet, а не самі об’єкти.
При використанні ітератор може викидати виняток ConcurrentModificationException, якщо HashSet було змінено. Щоб уникнути таких випадків слід використовувати методи ітератора для зміни HashSet.
Клас HashSet несинхронізоватий для багатопоточності, проте його можна синхронізувати використовуючи метод synchronizedSet класу Collections:
<pre>
Set s = Collections.synchronizedSet (new HashSet (...))
</pre>
У класу String перевизначені такі методи як equal та hashcode, що дає можливість коректного порівняння їхніх хеш-кодів та значень і уникати випадків, коли будуть додаватися ідентичні рядки, незалежно від того, чи вони зберігаються в різних комірках пам’яті. Проте при використанні власних класів, на практиці для правильного функціонування HashSet (без повторення об'єктів з однаковим станом, наприклад, ідентичними полями) у класах необхідно замістити методи equals() та hashcode() самому. Так, якщо ми створимо класи оболонки, що міститимуть String поле countryName із однаковим значенням, наприклад, “Австрія”, то у нас два об'єкти вважатимуться різні, оскільки у них буде різний Хеш-код, тож вони будуть додані до HashSet. В таких випадках необхідно продумати методи equals() та hashcode().
===Клас LinkedHashSet===
Клас <code>LinkedHashSet</code> розширює клас HashSet не додаючи ніяких нових методів. Працює він дещо довше за HashSet проте зберігає порядок в якому елементи додаються до нього. Відповідно це дозволяє організувати послідовну ітерацію вставлення та витягнення елементів. Всі конструктори та методи роботи з LinkedHashSet аналогічні методам класу HashSet.
===Клас TreeSet===
Клас TreeSet дозволяє створювати відсортовану множину. Тобто елементи не повторюються та зберігаються у відсортованому порядку. Для зберігання елементів застосовується бінарна деревоподібна структура. Об'єкти зберігаються в відсортованому порядку по зростанню. Час доступу та одержання елементів доволі малий, тому клас TreeSet підходить для зберігання великих об’ємів відсортованих даних, які повинні бути швидко знайдені.
Клас TreeSet розширює клас AbstractSet та реалізує інтерфейс NavigableSet. NavigableSet реалізується на базі TreeMap.
В класі доступні чотири конструктори:
<syntaxhighlight lang="java">
TreeSet ()
TreeSet(Collection с)
TreeSet(Comparator компаратор)
TreeSet(SortedSet ss)
</syntaxhighlight>
Третій конструктор дозволяє задавати власний компаратор, відповідно до якого буде відбуватися сортування об’єктів. Так об’єкти класу String не потребують реалізації власного компаратора, проте якщо ви хочете зберігати в класі TreeSet розроблені вами об’єкти, то потрібно задавати компаратор для цих об’єктів. Такий компаратор може реалізовувати сортування об’єктів по певному полю, наприклад по Прізвищу, якщо ваш клас зберігаю інформацію про осіб. Можна реалізувати ланцюжок компараторів з використанням методу thenComparing() класу Comparator.
TreeSet не може містити значення null. Також TreeSet не синхронізований клас, як і інші класи колекцій при потребі його потрібно синхронізувати з використанням методу Collections.synchronizedSet().
Розглянемо приклад роботи TreeSet з компаратором. Використаємо клас Car, який був попередньо використаний при роботі з LinkedList додавши лише гетер та сетер методи.
<syntaxhighlight lang="java">
public class Car {
private String name;
private double price;
private int year;
public Car(String name, double price, int year) {
this.name = name;
this.price = price;
this.year=year;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
@Override
public String toString() {
return "\n Car [name=" + name + ", price=" + price + ", year=" + year+ "]";
}
}
</syntaxhighlight>
Клас компаратора CarsComparator виглядає так:
<syntaxhighlight lang="java">
import java.util.Comparator;
public class CarsComparator implements Comparator {
@Override
public int compare(Car car1, Car car2) {
if(car1.getYear() > car2.getYear())
return 1;
else if (car1.getYear() < car2.getYear())
return -1;
else return 0;
}
}
</syntaxhighlight>
Наша програма з TreeSet:
<syntaxhighlight lang="java">
import java.util.Comparator;
import java.util.TreeSet;
public class TestTreeSet{
CarsComparator comp=new CarsComparator();
TreeSet<Car> ts1=new TreeSet<>(comp);
public static void main(String[] args) {
TestTreeSet t=new TestTreeSet();
t.test();
}
void test(){
Car car1=new Car("Ferrary", 12000, 1988);
Car car2=new Car("Ford", 13000, 1955);
Car car3=new Car("Toyota", 13500, 2003);
Car car4=new Car("Citroen", 12000, 2014);
Car car5=new Car("Mercedes-Benz", 15000, 2011);
ts1.add(car1);
ts1.add(car2);
ts1.add(car3);
ts1.add(car4);
ts1.add(car5);
System.out.println("Сортування по роках: "+ts1);
//Зворотній компаратор для TreeSet(Java8)
TreeSet<Car> ts2=new TreeSet<>(comp.reversed());
ts2.addAll(ts1); //додати вміст попереднього TreeSet у новий
System.out.println("Зворотнє сортування:"+ts2);
}
}
</syntaxhighlight>
Результат виконання:
<pre>
Сортування по роках: [
Car [name=Ford, price=13000.0, year=1955],
Car [name=Ferrary, price=12000.0, year=1988],
Car [name=Toyota, price=13500.0, year=2003],
Car [name=Mercedes-Benz, price=15000.0, year=2011],
Car [name=Citroen, price=12000.0, year=2014]]
Зворотнє сортування:[
Car [name=Citroen, price=12000.0, year=2014],
Car [name=Mercedes-Benz, price=15000.0, year=2011],
Car [name=Toyota, price=13500.0, year=2003],
Car [name=Ferrary, price=12000.0, year=1988],
Car [name=Ford, price=13000.0, year=1955]]
</pre>
Реалізація інтерфейсу NavigableSet забезпечила клас TreeSet доволі корисними методами як то ceiling(), floor(), headset(), higher(), pollFirst(), pollLast(), subset(), tailSet(), iterator(), descendingIterator(), descendingSet(). Використовуючи їх можна організувати доволі зручний вибір елементів з TreeSet. Див. детальніше документацію по TreeSet.
===Клас PriorityQueue===
PriorityQueue дозволяє реалізувати чергу на основі пріоритету. Така черга може бути корисна, наприклад, у разі необхідності обслуговування клієнтів згідно пріоритету. При зберіганні чисел в пріоритетній черзі, така черга гарантує, що першим елементом завжди буде найменший елемент. При цьому не гарантується ніякий стабільний послідовний порядок збереження елементів. Після додавання або видалення елементу з пріоритетної черги, порядок зберігання елементів в цій черзі змінюється таким чином, що в голові черги опиняється найменший елемент згідно його природнього порядку або згідно заданого компаратора.
<syntaxhighlight lang="java">
PriorityQueue має наступні конструктори:
PriorityQueue() //початковий об’єм становить 11
PriorityQueue(int початковий_об’єм)
PriorityQueue(Comparator comparator)
PriorityQueue(int початковий_об'єм, Comparator компаратор)
PriorityQueue(Collection с)
PriorityQueue(PriorityQueue с)
PriorityQueue(SortedSet с)
</syntaxhighlight>
Таким чином в разі потреби можна задати власний компаратор для видачі елементів у потрібному нам порядку.
PriorityQueue не може містити null. PriorityQueue розширює AbstractQueue та реалізує інтерфейси Serializable, Iterable, Collection, Queue.
Реалізація інтерфейсу Queue говорить нам, що в PriorityQueue доступні такі методи роботи з чергою:
*add(E e) – додати вказаний елемент у чергу
*element() – отримати, але не видаляти, елемент з голови черги
*offer(E e)- додати визначений елемент у чергу
*peek() – отримати елемент з голови черги, але не видаляти його. Повертає null, якщо черга порожня
*poll() – отримати та видалити елемент з голови черги
*remove() - отримати та видалити елемент з голови черги
Крім того в PriorityQueue достуні методи, що наявні і в інших колекціях як то: clear(), comparator(), contains(), iterator(), spliterator(), size(), toArray() тощо.
Приклад:
<syntaxhighlight lang="java">
import java.util.PriorityQueue;
public class TestPriorityQueue {
public static void main(String[] args) {
PriorityQueue<Integer> pq= new PriorityQueue<>(11);
pq.add(750);
pq.add(50);
pq.offer(1);
pq.add(300);
pq.add(25);
pq.add(2);
pq.offer(20);
pq.add(5);
pq.add(40);
System.out.println("Порядок зберігання елементів"+pq);
// Отримуємо і видаляємо елемент з голови черги
while (!pq.isEmpty()) {
System.out.println("Отримали: "+pq.poll());
System.out.println("Новий порядок:"+pq);
}
}
}
</syntaxhighlight>
Результат:
<pre>
Порядок зберігання елементів[1, 5, 2, 25, 300, 50, 20, 750, 40]
Отримали: 1
Новий порядок:[2, 5, 20, 25, 300, 50, 40, 750]
Отримали: 2
Новий порядок:[5, 25, 20, 750, 300, 50, 40]
Отримали: 5
Новий порядок:[20, 25, 40, 750, 300, 50]
Отримали: 20
Новий порядок:[25, 50, 40, 750, 300]
Отримали: 25
Новий порядок:[40, 50, 300, 750]
Отримали: 40
Новий порядок:[50, 750, 300]
Отримали: 50
Новий порядок:[300, 750]
Отримали: 300
Новий порядок:[750]
Отримали: 750
Новий порядок:[]
</pre>
Таким чином за допомогою методу poll() (його можна також замінити методом remove()), ми можемо отримувати елементи масиву у відсортованому порядку, незважаючи на те, що в самій пріоритетній черзі елементи зберігаються у іншому порядку.
===Клас ArrayDeque===
ArrayDeque (читається як аррейдек) – це клас який забезпечує двосторонню чергу. Іншими словами - це автоматично зростаючий масив, що дозволяє нам додавати або видаляти елементи з обох боків черги. ArrayDeque може бути використано як стек (LIFO, останній ввійшов - перший вийшов) або ж як черга (FIFO, перший ввійшов - перший вийшов).
ArrayDeque не може містити в якості елемента null.
Клас ArrayDeque швидший за клас Stack, якщо використовувати його в якості стеку і швидший за LinkedList, якщо використовувати в якості черги.
ArrayDeque розширює клас AbstractCollection та реалізує інтерфейси Deque, Cloneable, Serializable. Таким чином ми можемо використовувати для роботи з даним класом, як методи інтерфейсу Deque (який розширює інтерфейс Queue) так і методи інтерфейсу Collection.
Якщо використовується ітератор, то він буде викидати виняток ConcurrentModificationException, якщо вміст ArrayDeque був модифікований після створення ітератора. Таким чином ітератор необхідно з обережністю використовувати з ArrayDeque.
В ArrayDeque доступні наступні конструктори:
<syntaxhighlight lang="java">
ArrayDeque() // пустий ArrayDeque з початковим об’ємом 16 елентів
ArrayDeque(Collection c) // міститиме елементи колекції в порядку, що повертає ітератор даної колекції
ArrayDeque(int numElements) // дозволяє задати початковий об’єм
</syntaxhighlight>
При потребі збільшення об'єму, то він автоматично збільшується вдвічі.
Наступний приклад демонструє роботу із ArrayDeque у вигляді стека та у в вигляді черги:
<syntaxhighlight lang="java">
import java.util.ArrayDeque;
public class TestArrayDeque {
public static void main(String[] args) {
ArrayDeque<String> ad=new ArrayDeque<>();
System.out.println("Використання в якості стеку");
ad.push("Перший"); // метод інтерфуйсу Deque
ad.push("Другий");
ad.push("Третій");
System.out.println("Перший елемент ArrayDeque: "+ad.getFirst());//Отримуємо перший елемент, але не видаляємо
System.out.println("Вміст ArrayDeque: "+ad);
System.out.println(ad.pop()); //Отримуємо і видаляємо з вершини стеку
System.out.println(ad.pop()); //еквівалентно до removeFirst()
System.out.println(ad.pop());
//System.out.println(ad.pop()); //ArrayDeque порожній видасть NoSuchElementException
System.out.println();
System.out.println("Використання в якості черги");
ad.offer("Перший");
ad.offer("Другий");
ad.offer("Третій");
System.out.println("Перший елемент ArrayDeque: "+ad.getFirst());//Отримуємо перший елемент, але не видаляємо
System.out.println("Вміст ArrayDeque: "+ad);
System.out.println(ad.poll()); //витягнути і видалити з голови
System.out.println(ad.poll());
System.out.println(ad.poll());
System.out.println(ad.poll());
}
}
</syntaxhighlight>
Результат роботи:
<pre>
Використання в якості стеку
Перший елемент ArrayDeque: Третій
Вміст ArrayDeque: [Третій, Другий, Перший]
Третій
Другий
Перший
Використання в якості черги
Перший елемент ArrayDeque: Перший
Вміст ArrayDeque: [Перший, Другий, Третій]
Перший
Другий
Третій
null
</pre>
Дивіться також офіційну документацію по: [https://docs.oracle.com/javase/8/docs/api/java/util/Deque.html Інтерфейсу Deque] та
[https://docs.oracle.com/javase/8/docs/api/java/util/Collection.html Інтерфейсу Collection]
===Клас EnumSet===
Клас EnumSet — це одна з спеціалізованих реалізацій інтерфейсу Set для використання з перелічуваним типом даних (enum). EnumSet розширює AbstractSet та реалізує Cloneable та Serializable інтерфейси Java. EnumSet заміщує більшість методів інтерфейсів Set та Collection. EnumSet доволі швидка реалізація Set, швидша за HashSet, тому що всередині використовуються побітові операції, а не хеш-коди об’єктів.
EnumSet не синхронізований і повинен бути синхронізований ззовні, наприклад з використанням методу Collections.synchronizedSet(java.util.Set).
Всі елементи enum множини мають походити від єдиного перелічуваного типу, що вказується, коли множина створюється явно або неявно. EnumSet не дозволяє додавати значення null. Елементи зберігаються в порядку в якому їх подано в переліченні (enum).
EnumSet використовує безвідмовний (fail-safe) ітератор, що працює з копією EnumSet, тобто ітератор не буде викидати виняток ConcurrentModificationException, в разі зміни даних множини поза ітератором.
EnumSet – це відкритий абстрактний клас, який не має відкритого конструктора, для створення об’єкту EnumSet використовуються відповідні статичні факторні методи. В даних методах для створення EnumSet використовуються дві реалізації даного класу RegularEnumSet(для зберігання невеликих перелічень, до 64) та JumboEnumSet (для зберігання великих перелічень). Наступний приклад демонструє роботу з EnumSet:
<syntaxhighlight lang="java">
import java.util.EnumSet;
enum Colors
{
RED, GREEN, YELLOW, BLUE, BLACK
};
public class TestEnumSet
{
public static void main(String[] args)
{
// Створюємо множину
EnumSet<Colors> set1, set2, set3, set4, set5;
// Додаємо окремі елементи, порядок зберігання буде згідно порядку перелічення
set1 = EnumSet.of(Colors.RED, Colors.GREEN,
Colors.BLACK, Colors.BLUE);
// Заповнити тими елемнтами, яких нема у вказаній множині
set2 = EnumSet.complementOf(set1);
// Всі із даного перелічення
set3 = EnumSet.allOf(Colors.class);
// Додати усі елементи перелічення в діапазоні від GREEN до BLACK
set4 = EnumSet.range(Colors.GREEN, Colors.BLACK);
// створити пусту множину перелічень відповідного типу
set5= EnumSet.noneOf(Colors.class);
System.out.println("Set 1: " + set1);
System.out.println("Set 2: " + set2);
System.out.println("Set 3: " + set3);
System.out.println("Set 4: " + set4);
System.out.println("Set 5: " + set5);
}
}
</syntaxhighlight>
Результат роботи:
<pre>
Set 1: [RED, GREEN, BLUE, BLACK]
Set 2: [YELLOW]
Set 3: [RED, GREEN, YELLOW, BLUE, BLACK]
Set 4: [GREEN, YELLOW, BLUE, BLACK]
Set 5: []
</pre>
==Інтерфейс Map та класи, що його реалізують==
'''''Зіставлення''''' (англ. ''map'', також перекладають як ''відображення'')– це об’єкт який зіставляє ключ із відповідним значенням (key/value). Маючи ключ ви можете знайти його значення. І ключ, і значення є об’єктами. Ключ може бути унікальним, а значення може повторюватися. Деякі зіставлення можуть приймати null ключ і null значення, інші не можуть.
Зіставлення не підтримують Iterable інтерфейс. Тому ви не зможете використати ітератор для перебору вмісту зіставлення. Також ви не можете використовувати цикл for each. Проте можна перетворити зіставлення у інший тип колекції і вже на ньому можна отримати ітератор.
Основу зіставлень складає інтерфейс '''Map'''.
Map є узагальненим (див. розділ [[Освоюємо Java/Узагальнення|Узагальнення]]) і оголошений так:
<code>
interface Map<K, V>
</code>
де K – визначає тип ключа, а V визначає тип значення.
Інтерфейс '''SortedMap''' розширює інтерфейс Map і забезпечує, що вміст зберігається в порядку зростання, базуючись на значенні ключа.
Інтерфейс '''NavigableMap''' розширює SortedMap і забезпечує повернення вмісту базуючись на схожості ключа або ключів.
Інтерфейс '''Map.Entry''' – вкладений в Map інтерфейс і забезпечує роботу із вмістом зіставлення.
Класи, що реалізують інтерфейс Map наведені в таблиці.
{| class="wikitable" style="text-align: left; width: 800px;"
!Клас||Опис
|-
|AbstractMap ||Реалізує більшість інтерфейсу Map
|-
|EnumMap ||Розширює AbstractMap для використання з перелічуваними ключами.
|-
|HashMap ||HashMap розширює AbstractMap, щоб використовувати хеш таблиці.
|-
|TreeMap ||TreeMap розширює AbstractMap для використання дерев.
|-
|WeakHashMap ||WeakHashMap розширює AbstractMap для використання слабких ключів, що забезпечує утилізацію невикористовуваних ключів збирачем мусору
|-
|LinkedHashMap ||LinkedHashMap розширює HashMap дозволяючи ітерацію з вводом елементів в певному порядку
|-
|IdentityHashMap ||IdentityHashMap розширює AbstractMap і використовує рівність посилань при порівнянні документів (для специфічних задач)
|}
===Клас HashMap===
HashMap розширює AbstractMap та реалізує інтерфейс Map. Клас не додає власних методів. Клас використовує хеш таблиці для зберігання зіставлення. HashMap не гарантує порядок елементів.
<code>
HashMap має наступні конструктори:
HashMap( )
HashMap(Map<? extends K, ? extends V> m)
HashMap(int capacity)
HashMap(int capacity, float fillRatio)
</code>
Перший створює HashMap по замовчуванню. Другий створює хеш зіставлення використовуючи елементи m. Третій задає ємність хеш зіставлення. Четвертий задає ємність(по замовчуванню 16) та коефіцієнт заповнення (по замовчуванню 0.75).
<syntaxhighlight lang="java">
package Map;
import java.util.HashMap;
import java.util.*;
import java.util.Set;
public class TestHashMap {
public static void main(String[] args) {
// створюємо об'єкт HashMap з назвою capitalCities
HashMap<String, String> capitalCities = new HashMap<String, String>();
// додаємо ключі і значення (Країна, Столиця)
capitalCities.put("Англія", "Лондон");
capitalCities.put("Німеччина", "Берлін");
capitalCities.put("Норвегія", "Осло");
capitalCities.put("США", "Вашингтон");
//вивести значення об'єкту capitalCities
System.out.println(capitalCities);
//звернутися до HashMap використовуючи ключ
System.out.println(" Отримати столицю США");
System.out.println(capitalCities.get("США"));
//Видалити Англію
System.out.println(" Видаляємо Англію");
capitalCities.remove("Англія");
System.out.println(capitalCities);
//видалити все можна так
//capitalCities.clear();
// друкуємо ключі
System.out.println(" Ключі:");
for (String i : capitalCities.keySet()) {
System.out.println(i);
}
// друкуємо значення
System.out.println(" Значення:");
for (String i : capitalCities.values()) {
System.out.println(i);
}
// Друкувати ключі і значення
System.out.println(" Ключі і значення:");
for (String i : capitalCities.keySet()) {
System.out.println("key: " + i + " value: " + capitalCities.get(i));
}
System.out.println("Використовуємо Map.Entry");
//одержати множину входжень
Set<Map.Entry<String,String>> set=capitalCities.entrySet();
//вивести множину входжень
for(Map.Entry<String, String> me: set) {
System.out.print(me.getKey()+": ");
System.out.println(me.getValue());
}
}
}
</syntaxhighlight>
Результат:
<pre>
{США=Вашингтон, Англія=Лондон, Норвегія=Осло, Німеччина=Берлін}
Отримати столицю США
Вашингтон
Видаляємо Англію
{США=Вашингтон, Норвегія=Осло, Німеччина=Берлін}
Ключі:
США
Норвегія
Німеччина
Значення:
Вашингтон
Осло
Берлін
Ключі і значення:
key: США value: Вашингтон
key: Норвегія value: Осло
key: Німеччина value: Берлін
Використовуємо Map.Entry
США: Вашингтон
Норвегія: Осло
Німеччина: Берлін
</pre>
Ключі і значення в HashMap є об’єктами. Якщо ми хочемо використати, наприклад, числа цілого типу (іnt) то використовуватиметься клас обгортка Integer. Так само і для інших примітивних типів.
===Клас TreeMap===
Клас '''TreeMap''' розширює '''AbstractMap''' та реалізує інтерфейс '''NavigableMap'''. TreeMap не містить методів крім тих, що визначені у NavigableMap та класі AbstractMap. Що забезпечує зберігання зіставлень за допомогою деревовидної структури. TreeMap забезпечує зберігання пар ключ/значення у відсортованому порядку (в порядку зростання), що забезпечує швидкий доступ до елементів. TreeMap по замовчуванню сортується за ключами. Для задання іншого сортування використовують компаратор.
TreeMap узагальнений клас і оголошується так:
<code>
class TreeMap<K,V>
</code>
де K – задає тип ключа, а V – задає тип значення.
TreeMap визначає наступні конструктори:
<pre>
TreeMap( )
TreeMap(Comparator<? super K> comp)
TreeMap(Map<? extends K, ? extends V> m)
TreeMap(SortedMap<K, ? extends V> sm)
</pre>
Перший створює пусте деревовидне зіставлення, що буде відсортоване використовуючи природній порядок ключів. Другий створює пусте зіставлення, що буде відсортоване використовуючи компаратор. Третій створює деревовидне зіставлення із входжень зіставлення m, що буде відсортоване в природньому порядку. Третій ініціалізує деревовидне зіставлення входженнями із sm з порядком сортуванням того ж sm.
<syntaxhighlight lang="java">
package Map;
import java.util.TreeMap;
import java.util.*;
public class TestTreeMap {
public static void main(String[] args) {
TreeMap<String, Integer> countries = new TreeMap<String, Integer>();
countries.put("Гваделупа",1);
countries.put("США",2);
countries.put("Гаваї",3);
countries.put("Бельгія", 4);
//вивести вміст
System.out.println(countries);
//вивести останній ключ
System.out.println("Останній ключ:"+countries.lastKey());
countries.put("Албанія", 5);
System.out.println(" Вміст зіставлення:");
// взяти множину входжень
Set<Map.Entry<String, Integer>> set = countries.entrySet();
// Вивести елементи
for(Map.Entry<String, Integer> me : set) {
System.out.print(me.getKey() + ": ");
System.out.println(me.getValue());
}
System.out.println();
}
}
</syntaxhighlight>
Результат:
<pre>
{Бельгія=4, Гаваї=3, Гваделупа=1, США=2}
Останній ключ:США
Вміст зіставлення:
Албанія: 5
Бельгія: 4
Гаваї: 3
Гваделупа: 1
США: 2
</pre>
===Клас LinkedHashMap===
Клас '''LinkedHashMap''' розширює '''HashMap''' і підтримує пов'язаний список записів у зіставленні, в порядку в якому вони додавались. При необхідності можна задати зіставлення в якому записи будуть зберігатись в порядку останнього доступу.
LinkedHashMap має наступні конструктори:
<pre>
LinkedHashMap( )
LinkedHashMap(Map<? extends K, ? extends V> m)
LinkedHashMap(int capacity)
LinkedHashMap(int capacity, float fillRatio)
LinkedHashMap(int capacity, float fillRatio, boolean Order)
</pre>
Перший конструктор створює LinkedHashMap по замовчуванню. Другий ініціалізує LinkedHashMap елементами із зіставлення m. Третій конструктор задає ємність. Четвертий задає ємність та коефіцієнт заповнення. Ємність по замовчуванню - 16, а коефіцієнт заповнення по замовчуванню становить 0,75. Останній конструктор дозволяє задати порядок заповнення зіставлення, чи записи зберігатимуться в порядку вставлення чи в порядку останнього доступу. Якщо Order є true тоді використовуються порядок зберігання по порядку доступу, якщо false тоді використовується порядок вставлення.
LinkedHashMap додає лише один власний метод - removeEldestEntry. Якщо його замістити так, щоб він повертав true, то буде видалятися найстаріший елемент при використанні методів put() та putAll(). Таким чином можна, наприклад, встановити, щоб в зіставлення було б не більше певної кількості елементів.
<syntaxhighlight lang="java">
var cache = new LinkedHashMap<K, V>(128, 0.75F, true)
{
protected boolean removeEldestEntry(Map.Entry<K, V> eldest)
{
return size() > 100; //якщо елементів більше ста, то старі записи видалятимуться
}
};
</syntaxhighlight>
(необхідно описати ще EnumMap та IdentityHashMap)
==Алгоритми==
В структурі колекцій існує клас Collections, який надає ряд зручних статичних методів для роботи з даними. Нагадаємо, що статичні методи – це методи, які не потребують створення об'єктів і реалізують ряд додаткових алгоритмів по роботі з колекціями, як то сортування колекцій, знаходження максимального і мінімального елементу, перемішування, копіювання і т.п.
(необхідно розширити)
==Arrays==
Клас Arrays надає різноманітні статичні методи, що корисні при використанні масивів.
(Необхідно доповнити)
==Успадковані класи ==
Ранні версії Java не включали структуру Collections. Там було визначено декілька класів та інтерфейсів, що надавали методи для зберігання об'єктів. Структура Collections була додана в Java 2. (j2se 1.2). Тоді початкові класи були перероблені для підтримки інтерфейсів колекцій. Ці ранні класи також знані як успадковані класи (Legacy classes). В Java 5 успадковані класи та інтерфейси були перероблені для підтримки узагальнень. Їх підтримують, тому що до сих пір існує код, який їх використовує. Успадковані класи - синхронізовані. Класи входять в пакет java.util. Успадкованими є наступні класи:
* Dictionary
* HashTable
* Properties
* Stack
* Vector
Успадкованим є інтерфейс Enumaration, на заміну якому прийшов інтерфейс Iterator. Enumaration інтерфейс до сих пір використовується в декількох методах класів Vector та Properties.
==Додаткова література==
* [http://idndist.lp.edu.ua/moodle/library/books/0021/index06.html Плешко Д.Д. Лекція VІ. Колекції. (Об'єктно-орієнтоване програмування в Java)]
* [https://www.geeksforgeeks.org/collections-in-java-2/ Колекції в Java(англ)]
* [https://dzone.com/articles/working-with-hashcode-and-equals-in-java Робота з hashcode() та equals() (англ)]
* [https://docs.oracle.com/javase/8/docs/technotes/guides/collections/overview.html Огляд структори колекцій(англ)]
* [https://ukr-technologies.blogspot.com/search/label/Колекції Колекції Java]
{{Гортання сторінок|Графічний інтерфейс користувача|Менеджери розташування}}
[[Категорія:Освоюємо Java]]
lt8btau2msxs22bckf70fqazhrv23du
Програмування під Android
0
5172
36880
36763
2022-08-03T19:19:13Z
Володимир Груша
985
wikitext
text/x-wiki
{{Стадія|50%}}
'''Android''' - операційна система на основі ядра Linux з інтерфейсом користувача на основі прямого маніпулювання, призначена в першу чергу для сенсорних мобільних пристроїв, таких як смартфони і планшетні комп'ютери. Операційна система використовує сенсорне введення.
З 2011 року в Android має найбільшу базу встановленого обладнання з-понад усіх мобільних ОС станом на 2013 рік. Пристрої які використовують Android продають в світі більше ніж Windows, і пристроїв Mac OS, разом узятих. Станом на липень 2013 Google Play магазин мала більш 1 млн. опублікованих програм і більше 50 мільярдів завантажених додатків. Станом на квітень-травень 2013 встановлено, що 71% розробників мобільних додатків програмують для Android.
В наступних уроках йдеться про програмування під Android на [https://uk.wikibooks.org/wiki/Java Java]
==Зміст коротко==
# [[Програмування під Android/Вступ|Вступ]]
# [[Програмування під Android/Структура Android програми|Структура Android програми]]
# [[Програмування під Android/Налаштування середовища|Налаштування середовища Eclipse]]
# [[Програмування під Android/Структура Android проекту|Структура Android проекту]]
==Зміст детально==
# [[Програмування під Android/Вступ|Вступ]]
#* [[Програмування під Android/Вступ/Архітектура системи Android|Архітектура системи]]
# [[Програмування під Android/Структура Android програми|Структура Android програми]]
#* [[Програмування під Android/Структура Android програми#Компоненти програми|Компоненти програми]]
#* [[Програмування під Android/Структура Android програми#Файл маніфесту|Файл маніфесту]]
#* [[Програмування під Android/Структура Android програми#Ресурси програми|Ресурси програми]]
# [[Програмування під Android/Налаштування середовища|Налаштування середовища Eclipse]]
# [[Програмування під Android/Структура Android проекту|Структура Android проекту]]
===Література===
http://developer.android.com/guide/index.html
http://startandroid.ru/ru/
===Додаткові посилання===
[[Категорія:Java]]
[[Категорія:Програмне забезпечення]]
r6lzwt9m4yqn49hznxkte095e7zxz3c
Освоюємо R
0
6132
36865
30943
2022-08-03T18:36:03Z
Володимир Груша
985
/* Джерела */
wikitext
text/x-wiki
'''R''' — [[мова програмування]] та середовище для розробки створені для аналізу даних і, зокрема, статистичних обчислень та машинного навчання. R доступна як на Windows так і на Linux. Завдяки наявності великої кількості безкоштовних бібліотек під різноманітні задачі, останніми роками здобуває все більшу популярність серед тих хто займається аналізом даних. Є безкоштовним конкурентом [[Matlab]]. Також зіставляє конкуренцію в даній галузі мові програмування [[Python]].
==Встановлення==
Дистрибутиви R безкоштовні і їх можна звантажити з офіційних сайтів, крім того наявні безкоштовні графічні середовища розробки для R (IDE). Найбільш популярна графічна оболонка для R - RStudio, хоча є можливості використовувати і універсальні IDE як то Eclipse (встановивши плагін StatET).
==Вступ==
R — це інтерпретована мова. Для присвоєння використовується не <code>=</code>, а оператор <code><-</code>. Так, щоб присвоїти k число 10:
<syntaxhighlight lang="rsplus">
k<-10
</syntaxhighlight>
Вивести значення:
<syntaxhighlight lang="rsplus">
print(k)
</syntaxhighlight>
Якщо працюємо в командному рядку то достатньо ввести назву об’єкту, щоб вивести його вміст:
<syntaxhighlight lang="rsplus">
> k
[1] 10
</syntaxhighlight>
Для створення коментарів використовується символ <code>#</code>
Для того, щоб створити вектор з певними значеннями використовується функція <code>c()</code>:
<syntaxhighlight lang="rsplus">
> x<-c(0.5,0.6) ## вектор дійсних чисел(numeric)
</syntaxhighlight>
Щоб створити вектор з 5-ти елементів, що заповнений випадковим чином:
<syntaxhighlight lang="rsplus">
x<-rnorm(5)
</syntaxhighlight>
Щоб завершити сесію можна скористатися функцією q().
<syntaxhighlight lang="rsplus">
plot (х,y) # вивести графік по y та х
</syntaxhighlight>
==Довідка==
<syntaxhighlight lang="rsplus">
help.start() #загальна довідка
help ("дещо") #допомога по функції "дещо" (лапки не обов'язкові)
?дещо # теж саме
help.search("щось") #пошук записів, що містять "дещо"
??дещо # теж саме
example("дещо") # приклади використання
RSiteSearch("дещо") # пошук в інтернеті
apropos("дещо", mode="function") #список всіх доступних функцій, в назві яких є "дещо"
data() # список всіх демонстраційних даних, що містяться в завантажених пакетах
vignette() # список всіх доступних посібників по завантажених пакетах
vignette("дещо") # список посібників по темі "дещо"
</syntaxhighlight>
==Робочий простір==
Користувач може вибрати робочу директорію скориставшись функціями getwd() та setwd("директорія"). Для того, щоб уся зроблена робота не пропадала і можна було працювати на декількома проектами одночасно в R є можливість зберегти історію команд функцією savehistory() та весь поточний робочий простір save.image(). По замовчуванню, якщо не вказувати назви файлів, у робочій директорії будуть створені файли .Rhistory та .RData.
==Структури даних==
===Вектори===
Вектори - це числовий масив, що може містити числові, текстові або логічні значення. Причому вектори повинні бути однотипними, тобто не можна змішувати у векторі дані різних типів як то числа і текст.
<syntaxhighlight lang="rsplus">
v<-c(2,3,4,5,6) #створення вектора і заповнення його числами
v<-c(2:6) # те ж саме, створення вектора з рівномірним заповненням числами від 2 до 6
v[3] # отримати 3-й елемента вектора
v(с(2,4,5)) # виклик 2, 4 та 5-го елементів вектора
</syntaxhighlight>
Вектор з одним елементом називається скаляром
===Матриці===
Матриці - це двовимірні масиви однотипних елементів.
Матриці створюються за допомогою функції matrix виду:
<pre>
m<- matrix(вектор, nrow=кількість_рядків, ncol=кількість_стовпців,
byrow=логічне_значення, dimnames=list(
текст_вектор_назв_рядків, текст_вектор_назв_стовпців)
</pre>
byrow - вказує як заповняти матрицю по стовпцях(по замовчуванню byrow=FALSE) чи по рядках (byrow=FALSE)
текст_вектор_назв_рядків, текст_вектор_назв_стовпців - вектори, що дозволяють задати назви рядків та стовпців.
<syntaxhighlight lang="rsplus">
> inv<-c(5, 4, 6, 8) #значення, що будуть заповнювати матрицю
> rnames<-c("R1", "R2") #назви рядків
> cnames<-c("C1", "C2") #назви стовпців
> m<-matrix(inv, nrow=2, ncol=2, byrow=FALSE, dimnames=list (rnames, cnames)) #створюємо матрицю
> m #виводимо результат
C1 C2
R1 5 6
R2 4 8
</syntaxhighlight>
Звернення до елементів матриці відбувається так само як до елементів вектора:
<syntaxhighlight lang="rsplus">
m[2,3] #звернення до елементу в 2 рядку і 3 стовпчику
m[2,] #звернення до елементів 2-го рядку
m[,2] #звернення до елементів 2-го стовпчику
m[1, c(3,4)] #звернення до 3-го та 4-го елементів в першому рядку
</syntaxhighlight>
===Масиви===
Масиви в R по суті ті ж матриці тільки більшої розмірності. Створюються масиви за допомогою функції array():
<syntaxhighlight lang="rsplus">
myarray<-array(vector, dimensions, dimnames)
</syntaxhighlight>
де vector - дані для заповнення,
dimensions - розміри масив
dimnames - необов'язковий список назв вимірів.
Наступний приклад демонструє створення масиву:
<syntaxhighlight lang="rsplus">
> dim1<-c("A1", "A2")
> dim2<-c("B1","B2", "B3")
> dim3<-c("C1", "C2", "C3", "C4")
> a<-array(1:24, c(2,3,4), dimnames = list(dim1, dim2, dim3))
> a
, , C1
B1 B2 B3
A1 1 3 5
A2 2 4 6
, , C2
B1 B2 B3
A1 7 9 11
A2 8 10 12
, , C3
B1 B2 B3
A1 13 15 17
A2 14 16 18
, , C4
B1 B2 B3
A1 19 21 23
A2 20 22 24
>
</syntaxhighlight>
Звернення до елементів масиву, аналогічне до матриць:
<syntaxhighlight lang="rsplus">
> a[1,2,3]
[1] 15
> a[2,2,4]
[1] 22
</syntaxhighlight>
===Фрейми даних===
Фрейми даних (data frame, також перекладають як таблиці даних) - це найзастосовуваніша структура даних. На відміну від матриць фрейми можуть містити елементи різних типів, що зручно для роботи з реальними даними.
Створюєтья фрейм даних наступним чином:
<syntaxhighlight lang="rsplus">
mydata<-data.frame(col1, col2,col3,...)
</syntaxhighlight>
де col1, col2, col3 - це вектори будь-якого типу, що стануть стовпцями фрейму.
===Фактори===
Часто буває, що певні значення представлені не у чисельному вигляді (кількісні дані), а у вигляді певних текстових позначень (категоріальні дані, також називаються номінальними, неметричними або ж якісними). Існує можливість призначити їм додаткові чисельні значення, що в подальшому дає можливість порівнювати їх. Наприклад, якщо описується стан певного об'єкту через значення "прекрасно", "добре", "задовільно", "незадовільно", то можна призначити їм відповідні чисельні значення 4, 3, 2, 1. Для цього існує функція factor(). Функція може присвоювати значення в алфавітному порядку, або ж у заданому користувачем порядком.
<syntaxhighlight lang="rsplus">
> status<-c("незадовільно", "задовільно","добре", "прекрасно")
> numstatusAlph <- factor(status, order="true")
> numstatusOrder <- factor(status, order=TRUE, levels=c("незадовільно", "задовільно","добре", "прекрасно"))
> str(numstatusAlph) # вивести інформацію про об'єкт та порядок входження факторыв у поданому векторі
Ord.factor w/ 4 levels "добре"<"задовільно"<..: 3 2 1 4
> str(numstatusOrder)
Ord.factor w/ 4 levels "незадовільно"<..: 1 2 3 4
#порівняння факторів
> numstatusOrder[2]>numstatusOrder[1]
[1] TRUE
> unclass(numstatusOrder) # подивитись детальніше
[1] 1 2 3 4
attr(,"levels")
[1] "незадовільно" "задовільно" "добре" "прекрасно"
</syntaxhighlight>
===Списки===
Списки - це впорядкований набір об'єктів, що об'єднані під одним іменим. Причому об'єкти можуть бути різні, не зв'язані між собою. Для створення об'єктів використовується функція list.
<syntaxhighlight lang="rsplus">
mylist <- list(об'єкт 1, об'єкт2, ...)
</syntaxhighlight>
Звертатися до списків можна або ж по порядковому номеру, або ж по назві елементу всередині двійних квадратних дужок:
<syntaxhighlight lang="rsplus">
mylist[["Name_of_Object"]]
mylist[[3]]
</syntaxhighlight>
==Робота з діаграмами==
Робота з діаграмами відбувається шляхом послідовного введення команд. Наприклад, спочатку потрібно задати параметри графіка, далі будують графік і, згодом, можна ще дещо модифікувати зовнішній вигляд додавши, наприклад, заголовок і т.п.
<syntaxhighlight lang="rsplus">
investment<-c(5,10,13,18,20) # дані про інвестиції
profit<-c(100,300, 400, 450, 470) # дані про прибутки
plot(investment, profit, type="p") # будуємо діаграми заповнюючи її точками (p - points)
abline(lm(profit~investment)) # додати лінію регресії
title ("Regression of Profit from Investment") # вивести заголовк над графіком
</syntaxhighlight>
Задавати зовнішній вигляд елементів діаграми можна з використанням функції par(назва_параметру=параметр)
<syntaxhighlight lang="rsplus">
par(lty=2, pch=17) # задаємо пунктирну лінія (lty=2) та тип символу заповнення - трикутники (pch=17)
plot(investment, profit)
</syntaxhighlight>
Також можна це зробити зразу:
<syntaxhighlight lang="rsplus">
plot(investment, profit, type="b", lty=2, pch=17) # type="b" - означає виводити і символи і лінії
</syntaxhighlight>
Детальніше про управління зовнішнім виглядом дивіться у довідці по функції par.
===Кольори===
Для задання кольорів слугує параметр col.
{| class="wikitable"
! Параметр
! Опис
|-
| col || задати колір діаграми. Для lines та pie можна задавати декілька кольорів. Тоді вони будуть використовуватися по черзі col=c("yello", "blue", "red")
|-
| col.axis || колір значень осі (по замовчуванню - чорний)
|-
| col.lab || колір підписів осей
|-
| col.main || колір заголовків
|-
| col.sub|| колір підзаголовків
|-
| fg || колір графіку (foreground)
|-
| bg || колір фону (background)
|-
|}
<syntaxhighlight lang="rsplus">
par(col="blue") # графік та осі голубі
plot(investment, profit, type="b", col="red") #графік (лінія та точки) тепер червоний
</syntaxhighlight>
==Джерела==
* [https://www.cs.upc.edu/~robert/teaching/estadistica/rprogramming.pdf R Programming For Data Science]
* [https://www.coursera.org/course/rprog Курс R програмування на Coursera (''англ'')]
[[Категорія:R]]
[[Категорія:Мови програмування]]
{{Стадія|0%}}
hmaouu48oj6ph6yrh3r721f3ib7ctzo
Java для Вікіпроектів
0
6279
36882
34143
2022-08-03T19:22:47Z
Володимир Груша
985
wikitext
text/x-wiki
== Встановлення Java ==
== Maven ==
== Середовища розробки ==
== Клієнтські бібліотеки ==
[[:mw:API:Client_code#Java]]
Порівняння бібліотек
* [https://bitbucket.org/axelclk/info.bliki.wiki Bliki Engine - Java Wikipedia API] — Can convert wikicode to HTML, DocBook or PDF. Has [https://bitbucket.org/axelclk/info.bliki.wiki/wiki/MediaWikiAPISupport a helper library for API calls].
* [https://github.com/AttemptToCallNil/Deuterium Deuterium] — Java with Lua using LuaJ bot in development.
* [http://jwbf.sourceforge.net/pw/ JavaWikiBotFramework] — a Java library that makes several API functions accessible. On github: https://github.com/eldur/jwbf . ([[API:Client code/Evaluations/Java Wiki Bot Framework (JWBF)|Evaluation]])
* [https://github.com/fastily/jwiki jwiki] — A Java library emphasizing simplicity and ease-of-use.
* [https://github.com/frederikkaspar/Kaspar/ Kaspar] — supports Wikidata
* [https://github.com/WolfgangFahl/Mediawiki-Japi Mediawiki-Japi] just another Java Library
* [https://github.com/MER-C/wiki-java Wiki.java] — a simple one-class API implementation
* [[:mw:Wikidata Toolkit|Wikidata Toolkit]] — A Java library with functions to process data from Wikidata and other Wikibase sites, via XML dumps or the API. On github: https://github.com/Wikidata/Wikidata-Toolkit . JDoc: http://wikidata.github.io/Wikidata-Toolkit/ .
* [[:en:Wikipedia:WPCleaner|WPCleaner]] — a Java editing tool that includes a package for [http://sourceforge.net/p/wikicleaner/code/HEAD/tree/trunk/WikipediaCleaner/src/org/wikipediacleaner/api/ MediaWiki API].
* [https://github.com/dkpro/dkpro-jwpl Java Wikipedia Library]
[[Категорія:Java]]
[[Категорія:Мови програмування]]
{{Стадія:0%}}
an262pkgtn2rbwn59f2j7emrrqnru2e
36883
36882
2022-08-03T19:23:49Z
Володимир Груша
985
/* Клієнтські бібліотеки */
wikitext
text/x-wiki
== Встановлення Java ==
== Maven ==
== Середовища розробки ==
== Клієнтські бібліотеки ==
[[:mw:API:Client_code#Java]]
Порівняння бібліотек
* [https://bitbucket.org/axelclk/info.bliki.wiki Bliki Engine - Java Wikipedia API] — Can convert wikicode to HTML, DocBook or PDF. Has [https://bitbucket.org/axelclk/info.bliki.wiki/wiki/MediaWikiAPISupport a helper library for API calls].
* [https://github.com/AttemptToCallNil/Deuterium Deuterium] — Java with Lua using LuaJ bot in development.
* [http://jwbf.sourceforge.net/pw/ JavaWikiBotFramework] — a Java library that makes several API functions accessible. On github: https://github.com/eldur/jwbf . ([[API:Client code/Evaluations/Java Wiki Bot Framework (JWBF)|Evaluation]])
* [https://github.com/fastily/jwiki jwiki] — A Java library emphasizing simplicity and ease-of-use.
* [https://github.com/frederikkaspar/Kaspar/ Kaspar] — supports Wikidata
* [https://github.com/WolfgangFahl/Mediawiki-Japi Mediawiki-Japi] just another Java Library
* [https://github.com/MER-C/wiki-java Wiki.java] — a simple one-class API implementation
* [[:mw:Wikidata Toolkit|Wikidata Toolkit]] — A Java library with functions to process data from Wikidata and other Wikibase sites, via XML dumps or the API. On github: https://github.com/Wikidata/Wikidata-Toolkit . JDoc: http://wikidata.github.io/Wikidata-Toolkit/ .
* [[:en:Wikipedia:WPCleaner|WPCleaner]] — a Java editing tool that includes a package for [http://sourceforge.net/p/wikicleaner/code/HEAD/tree/trunk/WikipediaCleaner/src/org/wikipediacleaner/api/ MediaWiki API].
* [https://github.com/dkpro/dkpro-jwpl Java Wikipedia Library]
[[Категорія:Java]]
[[Категорія:Мови програмування]]
{{Стадія|0%}}
7qictgsn43dgmuc4xdfmf63fti7rwnx
Освоюємо Kotlin
0
7352
36864
34468
2022-08-03T18:34:16Z
Володимир Груша
985
wikitext
text/x-wiki
Kotlin - об'єктно-орієнтована мова програмування, що функціонує поверх віртуальної машина Java (JVM). З 7 травня 2019 року є рекомендованою мовою програмування для розробки Android застосунків.
==Змінні==
===Оголошення змінних===
Оголошення змінних відбувається з вказанням ключового слова var після чого йде назва змінної. Тип змінної можна не вказувати, тоді компілятор сам спробує визначити її тип за тим, що ви присвоюєте змінній. Для оголошення констант використовується ключове слово val взамін var.
<syntaxhighlight lang="kotlin">
var x=5 //оголошення цілочисельної змінної
val y=5 //оголошення константи
var num: Int // оголошення цілочисельної змінної з прямим вказанням типу
var hugeNumber = 6L //створення змінної типу Long
var hugeNumber2: Long =6 //теж саме
var isVar= true // створення змінної типу Boolean
var letter='D' //змінна типу Char
var name="Tom" // змінна типу String
var x=3.14 // змінна типу Double
</syntaxhighlight>
===Типи змінних===
Цілочисельні типи представлені типами Byte, Short, Int та Long.
{| class="wikitable" style="text-align:left"
! Тип
! Біт
! Діапазон значень
|-
| Byte
| 8 біт
| -128 до 127
|-
| Short
| 16 біт
| –32768 до 32767
|-
| Int
| 32 біт
| –2147483648 до 2147483647
|-
| Long
| 64 біт
| –huge до (huge - 1)
|}
Дробові числа представлені типами <code>Float</code> (32 біта) та типом <code>Double</code> (64 біта).
Для представлення символів використовується тип Char.
Для представлення рядків використовується тип String.
Boolean змінні застосовуються для значень true або false.
===Перетворення типів===
Для перетворення одного типу в інший використовуються відповідні функції, наприклад toLong(), що викликаються на відповідному об'єкті (змінній).
<syntaxhighlight lang="kotlin">
var k=65 // створиться змінна типу Int
var l:Long = k.toLong() //до типу Long
</syntaxhighlight>
===Масиви===
Робота з масивами здійснюється наступним чином:
<syntaxhighlight lang="kotlin">
var myArray = arrayOf(1, 2, 3) // оголошення масиву з трьома числами типу Int
println(myArray[0]) // звернення до першого (нульового) елемента масиву
println (myArray.size) // отримання розміру масива
var myArray2: Array<Byte>=arrayOf(2,3,4) // явне вказання типу масиву
</syntaxhighlight>
Якщо масив визначається не з допомогою ключового слова var, а з допомогою val, то створену змінну не можна буде перенаправити на інший масив. При цьому елементи масиву можна змінювати.
==Привіт Світе!==
Проста програма складається мінімум із одної функції main, що схоже на С/С++ чи java.
<syntaxhighlight lang="kotlin">
fun main(args: Array<String>){ // вказання аргументів функції необов'язкове
val message="Привіт, Світе!"
println (message) // якщо виводимо лише значення змінної
println ("Ми говоримо: $message") //якщо вставляємо змінну в рядок
}
</syntaxhighlight>
Результат:
<pre>
Привіт, Світе!
Ми говоримо: Привіт, Світе!
</pre>
Зверніть увагу, що для вставляння змінної в рядок використовується знак <code>$</code>
==Функції==
Оголошення функції в Kotlin із параметрами відбувається із вказанням ключового слова fun і вказанням назв параметрів і їхніх типів:
<syntaxhighlight lang="kotlin">
fun max(a: Int, b: Int){
println(if (a>b) a else b)
}
</syntaxhighlight>
Викликати функцію із функції main можна так:
<syntaxhighlight lang="kotlin">
fun main(args: Array<String>) {
max(4, 1)
}
</syntaxhighlight>
Якщо потрібно повернути певне значення із функції, то після дужок і двокрапки вказується тип значення, що повертається:
<syntaxhighlight lang="kotlin">
fun max(a: Int, b: Int):Int{
return if (a>b) a else b
}
</syntaxhighlight>
Компілятор строго контролюватеме чи ви передаєте аргументи правильного типу у функцію, тобто якщо написати <code>max("a", 3.14)</code>, то видасть помилку.
Якщо функція не повертає ніякого значення, то можна вказати ключове слово Unit замість типу. Але це не обов'язково, можна нічого не вказувати.
<syntaxhighlight lang="kotlin">
fun max(a: Int, b: Int):Unit{
println(if (a>b) a else b)
}
//або так
fun max(a: Int, b: Int){
println(if (a>b) a else b)
}
</syntaxhighlight>
==Цикли==
===Цикл while===
Звичний цикл з передумовою while працює в Kotlin як і в інших мовах:
<syntaxhighlight lang="kotlin">
var x=1
while (x<20){
x=x+1
}
</syntaxhighlight>
===Цикл for===
Цикл for дозволяє здійснити перебір чисел в певному діапазоні і має вигляд:
<syntaxhighlight lang="kotlin">
for (x in 1..15){
//код програми
}
</syntaxhighlight>
Якщо потрібно, щоб останній елемент не включався використовують замість .. ключове слово until:
<syntaxhighlight lang="kotlin">
for (x in 1 until 100) println(x) // виведе числа від 1 до 99
</syntaxhighlight>
Зверніть увагу, що якщо цикл складається з одного рядка, то фігурні дужки можна опустити.
Для перебору в зворотньому порядку використовується ключове слово <code>downTo</code>.
<syntaxhighlight lang="kotlin">
for (x in 15 downTo 1) println(x)
</syntaxhighlight>
Якщо потрібно перебирати не з одиничним кроком, то можна використати ключове слово <code>step</code> для задання кроку перебору.
<syntaxhighlight lang="kotlin">
for (x in 1..100 step 2) println(x)
</syntaxhighlight>
Існує можливість перебрати всі елементи масиву наступним чином:
<syntaxhighlight lang="kotlin">
var myArray: Array<Byte> = arrayOf(1, 2, 3)
for (item in myArray){
println("myArray has $item")
}
</syntaxhighlight>
Можна перебрати масив використовуючи його індекси:
<syntaxhighlight lang="kotlin">
var myArray: Array<Byte> = arrayOf(1, 2, 3)
for (index in myArray.indices){
println("$index =${myArray[index]}")
}
</syntaxhighlight>
Більш того, можна одночасно пройтися і по індексам і по значенням масиву:
<syntaxhighlight lang="kotlin">
var myArray: Array<Byte> = arrayOf(1, 2, 3, 5)
for ((index, item) in myArray.withIndex()){
println("[$index] =$item")
}
</syntaxhighlight>
Результат останнього шматка коду:
<pre>
[0] =1
[1] =2
[2] =3
[3] =5
</pre>
[[Категорія:Мови програмування]]
{{Стадія|0%}}
1bhpy2jzwa636fzy2212sdupqbwkwpg