Правила форматирования кода в Java (ч. 4)

Введение
В предыдущей статье мы научились компилировать и запускать нашу программу, решая самые разнообразные проблемы, возникающие при этом.
Данная статья продолжает цикл публикаций для начинающих, и будет посвящена очень важной теме, которую многие игнорируют — теме правильного оформления кода в классе (его форматированию).

1. Форматирование кода

Наблюдательный читатель, наверняка, обратил внимание на то, что написанный нами ранее код визуально как будто оформлен по неким правилам: в нем есть отступы от левого края редактора, пробелы между словами и скобками, которые визуализируются в виде точек.
Да, так и есть, код написан с использованием правил форматирования, которые в процессе изучения Java вам необходимо будет освоить. Со временем и при должной практике вы их запомните. Они чем-то похожи на правила оформления текста в книге или статье.

2. Для чего нужно форматирование

Открою вам секрет, что среднестатистический программист проводит гораздо больше времени за чтением кода, чем за его написанием. Читать код сложнее, чем писать, особенно чужой. Наличие общего стиля оформления программ облегчает понимание исходного кода, написанного разными программистами.
Стандарт оформления кода в каждой компании свой, но львиная его доля обычно одинакова, отличия не такие сильные. Когда, например, в рамках команды все пишут в одном стиле, а не кто как хочет, то это значительно облегчает восприятие кода, делает его понятнее и меньше грузит мозги программиста.
Давайте рассмотрим некоторые из правил оформления кода, которые были использованы при реализации класса MyFirstApp:
  • между ключевыми (зарезервированными языком Java) словами ставится один пробел, например, static void. Вам никогда не придется ставить два или более пробелов. И написать слитно, например, publicstatic по понятным причинам мы не можем, получится абракадабра, которая не заработает
  • после имени класса и перед { нужен пробел: MyFirstApp {
    Это правило относится ко всем открывающимся фигурным скобкам, где бы они не стояли. А вот такой вариант уже выглядит небрежно: MyFirstApp{
  • метод main размещается внутри класса, что говорит о его вложенности. Ее необходимо визуально как-то отображать. Для этого требуется сдвинуть метод целиком вправо на 4 пробела или на один Tab
  • код внутри метода, в свою очередь, вложен и в класс, и в метод main. Значит, его нужно сдвинуть вправо на 4 пробела дважды: относительно начала класса и начала метода. Итого получается 8 пробелов от левого края редактора
  • после имени метода и перед ( пробел не ставится. Такой вариант будет неверным: main (
  • } должна размещаться строго под началом конструкции, к которой она принадлежит
Чтобы на первых порах вам было проще видеть, какой размер отступа используется в коде, ранее мы настроили Sublime Text на отображение пробелов в виде точек.
Чтобы было еще понятнее, начертим стрелки, показывающие направление сдвига кода относительно начала блока (вертикальных линий, которые отображает редактор).
Также необходимо понимать, что несоблюдение правил форматирования никак не влияет на запуск программы, т. к. они не важны для виртуальной машины. Они имеют значения для людей, читающих код.
Давайте напишем тот же самый код, но уже с ошибками форматирования, и попробуем его запустить.
Программа запустилась без каких-либо ошибок.
> java MyFirstApp.java
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding="UTF8"
Написано однажды, работает везде
Можно записать весь код хоть в одну строку, но его никто не поймет. Многие начинающие разработчики не обращают внимание на внешний вид своего кода. Их цель — написать программу. Но есть хорошее выражение Мартина Фаулера: «Любой дурак может написать код, понятный компьютеру. Хороший программист пишет код, понятный человеку».

3. Правила форматирования Java-кода

В этом разделе собрано большое количество правил оформления кода, которые вы можете применять при написании своих программ на Java. Ранее мы уже публиковали (1, 2, 3) похожие правила от компании Google, но их отличие от представленных в этой статье в том, что они не такие детальные и подробные. Правила из этой статьи больше рассчитаны для начинающих программистов: они описывают каждую мелочь, каждую типичную ситуацию.
Применение данных техник сделает ваш код чистым, более читаемым и понятным. Не пренебрегайте ими! Будьте предельно внимательными.

3.1 Правила для классов

a) Имя класса должно быть существительным и может состоять из одного или более слов. Оно не должно содержать глагол
неправильно:
class Sit
class SaveInteger
class CalculateSum
правильно:
class SortedArrayStorage
class CalculatorMain
class Resume
b) Между именем класса и { необходим пробел
неправильно:
public class Calculator{
правильно:
public class Calculator {
c) Размещайте поля в начале класса в одном месте
неправильно:
public class Wolf {

    private String sex;

    public String getSex() {
        return sex;
    }

    private String name;

    public String getName() {
        return name;
    }
}
правильно:
public class Wolf {

    private String sex;
    private String name;

    public String getSex() {
        return sex;
    }

    public String getName() {
        return name;
    }
}
d) В одной строке объявляйте за раз только одну переменную
неправильно:
class Person {

    String uuid, name;
    double height, weight;
}
правильно:
class Person {

    String uuid;
    String name;
    double height;
    double weight;
}
e) Между блоком полей и конструктором необходима пустая строка
неправильно:
public class Resume {

    private String uuid;
    private String name;
    public Resume(String uuid) {
        this.uuid = uuid;
    }
}
правильно:
public class Resume {

    private String uuid;
    private String name;

    public Resume(String uuid) {
        this.uuid = uuid;
    }
}
f) Размещайте конструкторы после всех полей
неправильно:
class BankAccount {

    private String name;

    String getName() {
        return name;
    }

    public BankAccount(String name) {
        this.name = name;
    }
}
правильно:
class BankAccount {

    private String name;

    public BankAccount(String name) {
        this.name = name;
    }

    String getName() {
        return name;
    }
}
g) Между именем конструктора и открывающейся круглой скобкой пробел не требуется
неправильно:
Player (String name)
Resume (String uuid)
new Cat ()
правильно:
Player(String name)
Resume(String uuid)
new Cat()
h) Размещайте конструкторы в классе в порядке, зависящем от принимаемых ими числа аргументов: от меньшего к большему
неправильно:
class Player {

    Resume(String name, int number) {}

    Resume(String name) {}

    Resume(String name, int number, String uuid) {}
}
правильно:
class Player {

    Resume(String name) {}

    Resume(String name, int number) {}

    Resume(String name, int number, String uuid) {}
}
i) В конце класса не должно быть пустых строк
неправильно:
public class Player {

    private String name;

    public String getName() {
        return name;
    }
    // лишняя пустая строка
}
// лишняя пустая строка
правильно:
public class Player {

    private String name;

    public String getName() {
        return name;
    }
}
3.2. Правила для методов
a) Имя метода должно быть глаголом (или содержать глагол) и состоять из одного или более слов. Первым в имени, как правило, нужно ставить глагол
неправильно:
void endGame()
int calculation()
String playerArray()
правильно:
int calculate()
void clearNumbers()
void start()
b) Имена методов пишутся с маленькой буквы
неправильно:
char GetLetter()
void ClearEnteredNumbers()
Player CreatePlayer()
правильно:
char getLetter()
void clearEnteredNumbers()
Player createPlayer()
c) Между именем метода и открывающейся круглой скобкой пробел не требуется
неправильно:
public static void main (String[] args)
public int getIndex (String uuid)
System.out.println ("Math operator is wrong!")
правильно:
public static void main(String[] args)
public int getIndex(String uuid)
System.out.println("Math operator is wrong!")
d) после сигнатуры любого метода пустая строка не ставится
неправильно:
public static void main(String[] args) {

    int number = 5;
}
правильно:
*я это называю программерской "клаустрофобией". Ей страдают по началу все новички. В интернете полно примеров, где пустая строка ставится. Но не делайте так. Нет никаких правил или обоснований это делать.
public static void main(String[] args) {
    int number = 5;
}
e) Отделяйте один метод от другого одной пустой строкой
неправильно:
class Jaeger {

    private String name;
    
    public void setName(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }

    public void move() {
        // some code
    }
    public void fire() {
        // some code
    }
}
правильно:
class Jaeger {

    private String name;
    
    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void move() {
        // some code
    }

    public void fire() {
        // some code
    }
}
f) Группируйте геттеры и сеттеры по именам переменных, для которых они созданы. При этом не «приклеивайте» их друг к другу
неправильно:
public class Jaeger {

    private String mark;
    private String origin;

    public String getMark() {
        return mark;
    }
    public String getOrigin() {
        return origin;
    }

    public void setMark(String mark) {
        this.mark = mark;
    }
    public void setOrigin(String origin) {
        this.origin = origin;
    }
}
правильно:
public class Jaeger {

    private String mark;
    private String origin;

    public String getMark() {
        return mark;
    }

    public void setMark(String mark) {
        this.mark = mark;
    }

    public String getOrigin() {
        return origin;
    }
    
    public void setOrigin(String origin) {
        this.origin = origin;
    }
}
g) Размещайте геттеры и сеттеры в порядке следования полей, к которым они относятся
неправильно:
class Player {

    private String name;
    private int number;

    int getNumber() {
        return number;
    }

    void setNumber(int number) {
        this.number = number;
    }

    String getName() {
        return name;
    }

    void setName(String name) {
        this.name = name;
    }
}
правильно:
class Player {

    private String name;
    private int number;

    String getName() {
        return name;
    }

    void setName(String name) {
        this.name = name;
    }
    
    int getNumber() {
        return number;
    }

    void setNumber(int number) {
        this.number = number;
    }
}
h) Если геттеры не используются, то в классе их можно не писать
i) Геттеры для boolean-поля именуются по специальному правилу: вместо get пишется префикс is
правильно:
class Car {

    private boolean active;

    boolean isActive() {
        return active;
    }

    void setActive(boolean active) {
        this.active = active;
    }
}
j) Используйте this только при конфликте имен, например, в сеттерах (и то, не всегда). Если конфликта нет, писать this избыточно.
неправильно:
public int getIndex() {
    return this.index;
}

public void setNumber(int number) {
    this.numbers[index] = number;
}
правильно:
public void setIndex(int index) {
    this.index = index;
}

public void setNumber(int number) {
    this.number = number;
}
k) Приватные методы размещайте в конце класса по мере их вызова из публичных методов. Располагать приватные методы среди публичных допускается только в случае, если они используются только в данном методе. В этом случае размещайте методы в классе тоже в порядке их вызовов. Код должен читаться сверху вниз, как текст в книге
неправильно:
private boolean makeMove() {
    inputNumber();
    return compareNumbers();
}

private void inputNumber() {
    // some code
}

public void start() {
    makeMove();
}

private boolean compareNumbers() {
    return true;
}
правильно:
public void start() {
    makeMove();
}

private boolean makeMove() {
    inputNumber();
    return compareNumbers();
}

private void inputNumber() {
    // some code
}

private boolean compareNumbers() {
    return true;
}
l) Не используйте множественное число в имени сеттера для работы с массивом (если метод за один раз принимает одно значение, а не массив целиком)
неправильно:
private int[] enteredNums;
private int index;

void setEnteredNums(int enteredNums) {
    this.enteredNums[index] = enteredNums;
}
правильно:
private int[] enteredNums;
private int index;

void setEnteredNum(int enteredNum) {
    enteredNums[index] = enteredNum;
}

или

void addNum(int num) {
    enteredNums[index] = num;
}
3.3. Правила для переменных
a) Давайте переменным осмысленные и понятные имена, глядя на которые, любому читающему код было бы ясно, какие значения они хранят
неправильно:
char a = '+';
int b = 10;
String с = "yes";
правильно:
char sign = '+';
int size = 10;
String answer = "yes";
b) Объявляйте переменные максимально близко к месту их первого использования. Не группируйте их в начале метода
c) Имя переменной не должно быть глаголом или содержать глагол
неправильно:
Resume[] getAll = storage.getAll();
правильно:
Resume[] resumes = storage.getAll();
или
Resume[] allResume = storage.getAll();
d) Перед переменной при приведении типа требуется пробел
неправильно:
(char)i
правильно:
(char) i
e) Имена переменных начинайте с маленькой буквы
неправильно:
int Age;
int Title;
int FullName
правильно:
int age;
int title;
int fullName
f) Аббревиатуры в Java записываются как имена обычных переменных
неправильно:
int RAM;
long freqCPU;
String OS;
правильно:
int ram;
long freqCpu;
String os;
g) При использовании сокращенной формы инкремента и декремента, после имени переменной пробел не ставится
неправильно:
number ++
for (int i = 10; i > 0; i --)
правильно:
number++
for (int i = 10; i > 0; i--)
h) При именовании переменных для разделения слов нижнее подчеркивание _ ставится только у констант. Все остальные переменные должны именоваться с использованием camelCase
неправильно:
int hidden_number;
String player_answer;
правильно:
int hiddenNumber;
String playerAnswer;
i) Инициализируйте переменные (если это возможно) в строке их объявления, а не где-то ниже в коде
неправильно:
double num1;
char sign;
num1 = 4;
sign = '*';
правильно:
double num1 = 4;
char sign = '*';
3.4. Общие правила
a) Перед и после операторов =, +, -, /, *, ==, ≠, <, <=, >, >= требуется пробел
неправильно:
System.out.println("дата="+m+"."+d+"."+y);
int length=5;
for (int i=0;i<length;i++)
правильно:
System.out.println("дата = " + m + "." + d + "." + y);
int length = 5;
for (int i = 0; i < length; i++)
b) Между ){ скобками требуется пробел
неправильно:
- public static void main(String[] args){
- for (int i = 10; i > 0; i--){
- if (a > 10){
правильно:
- public static void main(String[] args) {
- for (int i = 10; i > 0; i--) {
- if (a > 10) {
c) Размещайте { на той же строке, что и конструкция к которой она принадлежит
неправильно (так форматируют в C# и C++):
foo()
{
}
правильно:
foo() {
}
d) Форматирование else и else if
неправильно:
}
else {
    System.out.println("Exit");
}
правильно:
} else {
    System.out.println("Exit");
}
неправильно:
}
else if (size < storage.length) {
правильно:
} else if (size < storage.length) {
плохо (зачем тратить лишнюю строку под if):
} else {
    if (number > randomNumber) {
хорошо:
} else if (number > randomNumber) {
неправильно:
if (firstNum1 == firstNum2) {
    System.out.print();
} if (secondNum1 == secondNum2) {
    System.out.print();
}
правильно:
if (firstNum1 == firstNum2) {
    System.out.print();
}
if (secondNum1 == secondNum2) {
    System.out.print();
}
e) Форматирование цикла do-while
неправильно:
do {
    // code
}
while ("yes".equals(answer));
правильно:
do {
    // code
} while ("yes".equals(answer));
f) Если ветка if-else или тело цикла состоит из одного выражения, всегда заключайте их в {}. Это поможет избежать трудноуловимых багов
плохо:
if (doc.important)
    send(doc);
else
    System.out.println("Throw out the trash");
    delete(doc);
хорошо:
if (doc.important) {
    send(doc);
} else {
    log.info("Throw out the trash");
    delete(doc);
}
плохо:
while (number < 5)
    System.out.println("number less");
    number++;
хорошо:
while (number < 5) {
    System.out.println("number less");
    number++;
}
g) После , и ; требуется пробел
неправильно:
public void addAttempt(int number,int i)
for (int i = 0;i < storage.length;i++)
правильно:
public void addAttempt(int number, int i)
for (int i = 0; i < storage.length; i++)
h) После ( и перед ) скобками пробел не требуется
неправильно:
for ( int i = 0; i < 21; i++ )
compareNumber( String number )
правильно:
for (int i = 0; i < 21; i++)
compareNumber(String number)
i) Не используйте в имени полей и методов имя класса, где они находятся, т.к. и так понятно, что все, что в нем размещается, относится к данному классу
неправильно:
public class Player {
	
    private int[] playerNumbers = new int[10];

    public int getPlayerNumber(int index) {
        return playerNumbers[index];
    }
}
правильно:
public class Player {
	
    private int[] numbers = new int[10];

    public int getNumber(int index) {
        return numbers[index];
    }
}
j) После package и import требуется пустая строка
неправильно:
package com.webapp.storage;
import java.util.Scanner;
public class ArrayStorage {
правильно:
package com.webapp.storage;

import java.util.Scanner;

public class ArrayStorage {
k) Размещайте комментарии над комментируемым кодом, а не справа от него. Комментарий должен начинаться с той же позиции, что и код
неправильно:
int sumOdd = 10; // сумма нечетных чисел
правильно:
// сумма нечетных чисел
int sumOdd = 10;
l) При создании переменной для хранения ссылки на массив и самого массива, размещайте [] в Java-стиле, а не в Си или С++, а также не ставьте лишних пробелов
неправильно:
int numbers[]
int [] numbers
int numbers []
new int [10]
правильно:
int[] numbers = new int[10]
m) имена boolean-переменных должны быть прилагательным
неправильно:
boolean security
boolean answer
boolean continue
правильно:
boolean active
boolean current
boolean alive
n) Не забывайте код, вложенный в класс, метод, цикл и другие конструкции, которые имеют тело в виде { }, каждый раз сдвигать вправо на 4 пробела (или один Tab) относительно начала этой конструкции
неправильно:
public class Person {

    int age = 25;

    public static void main(String[] args) {
    if (age > 20) {
    System.out.println("Человек старше 20 лет");
    }
}
}
правильно:
public class Person {

    int age = 25;

    public static void main(String[] args) {
        if (age > 20) {
            System.out.println("Человек старше 20 лет");
        }
    }
}
o) Если имя переменной/метода/класса состоит из более, чем одного слова, то для именования используется camelCase (CamelCase для классов)
неправильно:
int playeranswer
class Guessnumbermain
void addnumber()
правильно:
int playerAnswer
class GuessNumberMain
void addNumber()
p) Стандартное именование для счетчиков в цикле for — это i, j, k. Последние два используются для вложенных циклов
плохо:
for (a = 0; a < 3; a++) {    
}
хорошо:
for (i = 0; i < 3; i++) {    
}
плохо:
for (d = 0; d < 10; d++) {
    for (c = 0; c < 4; c++) {    
    }
}
хорошо:
for (i = 0; i < 10; i++) {
    for (j = 0; j < 4; j++) {    
    }
}
q) При переносе строки каждую следующую ее подстроку необходимо смещать вправо на 8 пробелов относительно первой строки
неправильно:
System.out.println("Characteristics:\n" +
"age = " + age + "\n" +
"name = " + name + "\n" +
"color = " + color);
правильно:
System.out.println("Characteristics:\n" +
        "age = " + age + "\n" +
        "name = " + name + "\n" +
        "color = " + color);
r) При проверке boolean-значений явно указывать true или false не нужно
неправильно:
if (male == false)
while (isNext() == true)
if (isExist(uuid) != true)
правильно:
if (!male)
while (isNext())
if (!isExist(uuid))
Автор: Чимаев Максим
Оцените статью, если она вам понравилась!