Глава 11. Хитрости и хакове

В настоящата глава ще разгледаме някои хитрости, хакове и техники, които ще улеснят работата ни с езика Java в средата за разработка IntelliJ IDEA. По-специално ще се запознаем:

  • Как правилно да форматираме код
  • С конвенции за именуване на елементи от код
  • С някои бързи клавиши (keyboard shortcuts)
  • С някои шаблони с код (code snippets)
  • С техники за дебъгване на код

Форматиране на кода

Правилното форматиране на нашия код ще го направи по-четим и разбираем, в случай че се наложи някой друг да работи с него. Това е важно, защото в практиката ще ни се наложи да работим в екип с други хора и е от голямо значение дали пишем кода си така, че колегите ни да могат бързо да се ориентират в него.

Има определени правила за правилно форматиране на кода, които събрани в едно се наричат конвенции. Конвенциите са група от правила, общоприети от програмистите на даден език, и се ползват масово. Тези конвенции помагат за изграждането на норми в дадени езици - как е най-добре да се пише и какви са добрите практики. Приема се, че ако един програмист ги спазва, то кодът му е лесно четим и разбираем. Програмният език Java е създаден от Sun Microsystems и те са тези, които създават една от първите конвенции за Java. Трябва да знаете също така, че дори да не спазвате общоприетите конвенциите, кодът ви ще работи (стига да е написан правилно), но просто няма да бъде лесно разбираем. Това, разбира се, не е фатално на основно ниво, но колкото по-бързо свикнете да пишете качествен код, толкова по-добре. (Съвременна Java конвенция е Google Java Style Guide: https://google.github.io/styleguide/javaguide.html)

За форматиране на кода в Java света се препоръчва къдравите скоби {} да са в следното разположение - отварящата скоба да е на същия ред, а затварящата скоба да е точно под конструкцията, към която се отнасят, както е в примера по-долу.

if (true) {
    System.out.println("влязох в if-a");
}

Вижда се, че командата System.out.println(...) в примера е 4 празни полета навътре (един таб), което е стандарта в Java. Без значение колко таба навътре започва определена конструкция с къдрави скоби (т.е. без значение колко влагания на различни оператори имаме), затварящата скоба трябва да е под началото на конструкцията, както е в примера по-долу:

if (true) {
   if (true) {
       System.out.println("влязох в if-a");
   }
}

Ето това е пример за лошо форматиран код спрямо общоприетите конвенции за писане на код на езика Java:

if(true)
{
System.out.println("влязох в if-a");}

Първото, което се забелязва са къдравите скоби {}. Първата (отваряща) скоба трябва да е след if условието, a втората (затваряща) скоба - под командата System.out.println(...), на отделен празен ред. В допълнение, командата вътре в if конструкцията трябва да бъде 4 празни полета навътре (един таб). Същото правило важи и за for цикли и всякакви други конструкции с къдрави скоби {}. Ето още няколко примера:

Правилно:

for (int i = 0; i < 5; i++) {
    System.out.println(i);
}

Грешно:

for(int i=0;i<5;i++)
{
System.out.println(i);
}

За ваше удобство има бързи клавиши в IntelliJ IDEA, за които ще говорим по-късно в настоящата глава, но засега ни интересуват две конкретни комбинации. Едната комбинация е за форматиране на кода в целия документ, а другата комбинация - за форматиране на част от кода. Ако искаме да форматираме целия код, то трябва да натиснем [CTRL + ALT + L]. В случай, че искаме да форматираме само част от кода, то ние трябва да маркираме частта, която искаме да форматираме, и да натиснем [Ctrl + Shift + Alt + L].

Нека използваме грешния пример от преди малко:

for(int i=0;i<5;i++)
{
System.out.println(i);
}

Ако натиснем [CTRL + ALT + L], което е нашата комбинация за форматиране на целия документ, ще получим код, форматиран според общоприетите конвенции за Java, който ще изглежда по следния начин:

for (int i = 0; i < 5; i++) {
    System.out.println(i);
}

Тази комбинация може да ни помогне, ако попаднем на лошо форматиран код.

Именуване на елементите на кода

В тази подглава ще се фокусираме върху общоприетите конвенции за именуване на проекти, файлове и променливи в Java света.

Именуване на проекти и класове

За именуване на проекти и класове се препоръчва описателно име, което подсказва каква е ролята на въпросния клас/проект и в същото време се препоръчва Upper Camel Case конвенцията. Накратко, това е конвенция за именуване на елементи, при която всяка дума, включително първата, започва с главна буква. Пример: в този курс се започва с лекция на име First steps in coding и следователно едно примерно именуване на проекта за тази лекция може да бъде FirstStepsInCoding. Същата конвенция важи и за класовете в даден проект. Ако вземем за пример първата задача от лекцията First steps in coding, тя се казва Hello World и следователно нашият файл в проекта ще се казва HelloWorld.

Именуване на променливи

Нещата стоят по по-различен начин при променливи. Правилaта за именуване на променливи гласят, че:

  • Името трябва да е кратко и описателно и да обяснява за какво служи дадената променлива.
  • Името трябва да се състои само от буквите a-z, A-Z, цифрите 0-9, както и символите '$' и '_'.
  • В Java е прието променливите да започват винаги с малка буква и да съдържат малки букви, като всяка следваща дума в тях започва с главна буква (това е още познато като Lower Camel Case).
  • Трябва да се внимава за главни и малки букви, тъй като Java прави разлика между тях. Например age и Age са различни променливи. Имената на променливите не могат да съвпадат със служебна дума (keyword) от езика Java.

Ето няколко примера за добре именувани променливи:

  • firstName
  • age
  • startIndex
  • lastNegativeNumberIndex

Ето няколко примера за лошо именувани променливи, макар и имената да са коректни от гледна точка на компилатора на Java:

  • _firstName (започва с '_')
  • last_name (съдържа '_')
  • AGE (изписана е с главни букви, което е грешно име за променлива, но е правилно име за константа)
  • Start_Index (започва с главна буква и съдържа '_')
  • lastNegativeNumber_Index (съдържа '_')

Първоначално всички тези правила може да ни се струват безсмислени и ненужни, но с течение на времето и натрупването на опит ще видите нуждата от норми за писане на качествен код, за да може да се работи по-лесно и по-бързо в екип. Ще разберете, че е изключително досадна работата с код, който е написан без да се спазват никакви правила за качествен код.

Бързи клавиши в IntelliJ IDEA

В миналата подглава споменахме за две от комбинациите, които се отнасят за форматиране на код. Едната комбинация [Ctrl + Alt + L] беше за форматиране на целия код в даден файл, а втората [Ctrl + Shift + Alt + L] ни служеше в случай, че искаме да форматираме само дадена част от кода. Тези комбинации се наричат бързи клавиши и сега ще говорим по-подробно за тях.

Бързи клавиши са комбинации, които ни предоставят възможността да извършваме някои действия по-лесно и по-бързо, като всяка среда за разработка на софтуер си има своите бързи клавиши, въпреки че повечето се повтарят. Сега ще разгледаме някои от бързите клавиши в IntelliJ IDEA.

Комбинация Действие
[CTRL + F] Комбинацията отваря търсачка, с която можем да търсим в нашия код.
[CTRL + /] Закоментира част от кода. / Разкоментира код, който е вече закоментиран.
[CTRL + Z] Връща една промяна назад (т.нар. Undo).
[Ctrl + Shift + Z] Комбинацията има противоположно действие на [CTRL + Z] (т.нар. Redo).
[CTRL + ALT + L] Форматира кода според конвенциите по подразбиране.
[CTRL + Backspace] Изтрива думата вляво от курсора.
[CTRL + Del] Изтрива думата вдясно от курсора.
[CTRL + S] Запазва всички файлове в проекта.
[CTRL + D] Копира ред или маркирания фрагмент.
[CTRL + Y] Изтрива текущия ред.

Повече за бързите клавиши в IntelliJ IDEA може да намерите тук: https://www.jetbrains.com/help/idea/keyboard-shortcuts-by-category.html

Шаблони с код (code snippets)

В IntelliJ IDEA съществуват т.нар. шаблони с код (code snippets), при изписването на които се генерира шаблон с код. Примерно при изписването на [sout + Enter] се генерира кодът System.out.println();:

В тази подглава ще покажем как сами да си направим собствен шаблон. Ще разгледаме как се прави code snippet за scanner.nextLine();. Като за начало ще си създадем нов празен проект и ще отидем на [File → Settings → Editor → Live Templates], като избираме [+Live Template], както е показано на снимката по-долу.

Излиза нов прозорец, който изглежда както на следващата картинката.

Тук попълваме следната информация:

  • [Abbreviation] - тук се вписва code snippet-a, който ще използваме. В конкретния случай това е scnl.
  • [Description] - тук се попълва описание за snippet-a. В нашия случай това е scanner.nextLine().
  • [Template text] - тук въвеждаме кода, който ще се генерира при изписване на съкращението. В този случай, това е кода по-долу:
Scanner scanner = new scanner(Sysrtem.in);
String s = scanner.nextLine();

След това маркираме [Reformat according to style], a от [Define] избираме [Java], след което натискаме [OK], както е показано на картинката по-долу.

Вече когато напишем scnl в IntelliJ IDEA, нашият нов snippet се появява:

Техники за дебъгване на кода

Дебъгването играе важна роля в процеса на създаване на софтуер, която ни позволява постъпково да проследим изпълнението на нашата програма. С помощта на тази техника можем да следим стойностите на локалните променливи, тъй като те се променят по време на изпълнение на програмата, и да отстраним евентуални грешки (бъгове). Процесът на дебъгване включва:

  • Забелязване на проблемите (бъговете).
  • Намиране на кода, който причинява проблемите.
  • Коригиране на кода, причиняващ проблемите, така че програмата да работи правилно.
  • Тестване, за да се убедим, че програмата работи правилно след нанесените корекции.

IntelliJ IDEA ни предоставя вграден дебъгер (debugger), чрез който можем да поставяме точки на прекъсване (или breakpoints) на избрани от нас места. При среща на стопер (breakpoint), програмата спира изпълнението си и позволява постъпково изпълнение на останалите редове. Дебъгването ни дава възможност да вникнем в детайлите на програмата и да видим къде точно възникват грешките, както и каква е причината за това.

За да демонстрираме работа с дебъгера ще използваме следната програма:

public static void main(String[] args) {
    for (int i = 0; i < 100; i++) {
        System.out.println(i);
    }
}

Ще сложим стопер (breakpoint) на функцията System.out.println(...). За целта трябва да преместим курсора на реда, който печата на конзолата, и да натиснем [Ctrl + F8] или да кликнем с десния бутон на мишката от дясно на номера на реда. Появява се точка на прекъсване, където програмата ще спре изпълнението си.

За да стартираме програмата в режим на дебъгване, избираме [Run] → [Debug <име на класа>] или натискаме [SHIFT + F9].

След стартиране на програмата виждаме, че тя спира изпълнението си на ред 8, където сложихме стопера (breakpoint). Кодът на текущия ред се маркира в допълнителен цвят и можем да го изпълняваме постъпково. За да преминем на следващ ред използваме клавиш [F8]. Забелязваме, че кодът на текущия ред все още не е изпълнен. Изпълнява се, когато преминем на следващия ред. В зелено се показва текущата стойност на променливата, на снимката по-долу i = 0.

От прозореца [Variables] можем да наблюдаваме промените по локалните променливи.

Справочник с хитрости

Тази подглава съдържа някои основни и полезни неща, разглеждани в тази книга:

Форматиран изход с printf()

За отпечатването на дълги и сложни поредици от елементи можем да използваме метода printf(...). Този метод е съкращение на "Print Formatted". Основната идея на printf(...) е да приеме специален стринг, форматиран със специални форматиращи символи и списък със стойностите, които трябва да се заместят на мястото на "форматните спецификатори".

printf(<formatted string>, <param1>, <param2>, <param3>, …)

Пример:

String str = "some text";
System.out.printf("%s", str);
// това ще изкара на конзолата "some text"

Първият аргумент на метода printf(...) е форматиращият стринг. В случая %s означава, че трябва да се разпечата стринг str, на мястото на %s.

String str1 = "some text";
int number = 5;
String str2 = "some more text";
System.out.printf("%s %d %s \n", str1, number, str2);
// това ще изкара "some text 5 some more text"

В този пример забелязваме, че можем да подаваме не само текстови променливи. Първият аргумент е форматиращият низ. Следва поредица от аргументи, които се заместват на местата, където има процент, следван от буква (%s или %d). Първият %s означава да се постави на негово място първия аргумент, подаден след форматиращия низ, в случая str1. Следва %d, което означава да се замести с първото целочислено число, подадено в аргументите. Последният специален символ е отново %s, което означава да се замести със следващия по ред символен низ str2. Следва \n, което е специален символ, който указва преминаване на нов ред. Можем да използваме дадена променлива няколко пъти.

String str = "some text";
int number = 5;
System.out.printf("%s %d %s \n", str, number, str);
// това ще изкара "some text 5 some text"

Закръгляне на числа с плаваща запетая

Реалните типове с плаваща запетая, които използваме в Java, са float и double.

double number = 5.432432;
System.out.println(Math.round(number));
// това ще изкара на конзолата "5"

Ако първата цифра след десетичния знак е по-малкa от 5, както в примера по-горе, то закръглянето е надолу, но ако е 5 или по-голяма - закръглянето е нагоре, както е в примера по-долу:

double number = 5.543;
System.out.println(Math.round(number));
// това ще изкара на конзолата "6"

Други методи за закръгляне

В случай, че искаме винаги да закръгляме надолу можем вместо Math.round(...) да използваме друг метод - Math.floor(...), който винаги закръгля надолу. Например, ако имаме числото 5.99 и използваме Math.floor(5.99), то ние ще получим числото 5.0. Можем и да направим точно обратното - винаги да закръгляме нагоре, използвайки метода Math.ceil(...). Отново, ако имаме число, примерно 5.11 и използваме Math.ceil(5.11), то ние ще получим 6.0. Това е показано и в примерите по-долу:

double numberToFloor = 5.99;
double numberToCeiling = 5.11;
System.out.println(Math.floor(numberToFloor));
// това ще изкара на конзолата 5.0
System.out.println(Math.ceil(numberToCeiling));
// това ще изкара на конзолата 6.0

Форматиране с две цифри след десетичния знак

double number = 5.432432;
System.out.printf("%.2f%n", number);
// това ще изкара на конзолата 5.43

В случая използваме форматиращият стринг %.2f, което ще ограничи числовата променлива до 2 цифри след десетичния знак. Tрябва да имаме предвид, че числото пред буквата f означава до колко цифри след десетичния знак да е закръглено резултата (т.е. може да е %.3f или %.5f). Препоръчително е с printf() като символ за нов ред да използваме %n, вместо /n.

Как сe прави условна конструкция

If конструкцията се състои от следните елементи:

  • If клауза
  • Булев израз (условие)
  • Тяло на условната конструкция
  • Незадължително: else клауза
if (условие) {
    // тяло
} else (условие) {
    // тяло
}

За улеснение може да използваме code snippet за if клауза: [if + Ctrl + Space]

Как се прави цикъл

За for цикъл ни трябват няколко неща:

  • Инициализационен блок, изпълнява се само веднъж преди да се провери условието за повторение. Най-често се декларира променливата-брояч (int i) и се задава нейна начална стойност.
  • Условие за повторение (i <= 10).
  • Обновяване на брояча (i++).
  • Тяло на цикъла.
for (int i = 0; i <= 10; i++) {
    // тяло
}

Важно е да знаем, че и трите части на for цикъла са незадължителни и могат да се пропуснат. for(; ; ) { ... } е валиден пример за for цикъл.

За улеснение може да използваме code snippet за for цикъл: [fori + Enter]

Какво научихме от тази глава?

В настоящата глава се запознахме как правилно да форматираме и именуваме елементите на нашия код, някои бързи клавиши (shortcuts) за работа в IntelliJ IDEA, шаблони с код (code snippets) и разгледахме как се дебъгва код.

results matching ""

    No results matching ""