JavaRush /Java блог /Random /IntelliJ IDEA: стиль и форматирование кода
Viacheslav
3 уровень

IntelliJ IDEA: стиль и форматирование кода

Статья из группы Random
Современные инструменты позволяют упростить процесс разработки. В том числе, легче следить за стилем своего кода, стараясь сводить к минимуму его "самовольное" форматирование. В данном обзоре предлагаю ознакомиться с тем, какие средства предоставляет IDE IntelliJ Idea разработчику для того, чтобы код было приятно читать и легко понимать.
IntelliJ IDEA: стиль и форматирование кода - 1

Вступление

Язык программирования очень похож на язык, на котором говорят люди. Разница лишь в том, что это особенный язык, который изначально служит для общения с компьютером, чтобы объяснить ему, что мы от него хотим. Но общения один на один с компьютером не может быть. Даже когда вы начинали изучать язык программирования, вы смотрели в книгу или на какой-то образовательный ресурс вроде JavaRush. И в этом источнике вы видели код, который поймёт компьютер. Но и вы должны понимать его по мере того, как у вас появляется знание языка Java. Как и в любом языке, в программировании приняты некоторые правила формирования кода. Например, пИсАтЬ зАбОрОм в приличном обществе посчитается правилом дурного тона, а в Java называть метод с большой буквы является грубым нарушением code style. Правила оформления Java кода сформулированы в документе Java Code Convention. Кроме того, стиль оформления кода может регламентировать и более мелкие детали, например, отступы. А когда используются средства контроля версий, представьте себе весь кошмар, когда каждый будет сохранять файл то с отступами в виде tab, то с отступами в виде пробелов. Каково будет тому, кому надо проверить правку всего в одном методе, а изменён будет весь файл из-за исправления пробелов на табы или наоборот. Естественно, как и с обычным языком, стиль может меняться в зависимости от того места, где он используется. Например, на просторах сети можно найти Google Java Style Guide или Twitter Java Style Guide. Для этой обзорной статьи нам понадобится испытуемый. Воспользуемся услугой системы сборки проектов Gradle. Он позволит нам создать по шаблону новый проект для быстрого старта. У Gradle есть замечательный плагин: Build Init Plugin. Перейдём в новый каталог и выполним там команду: gradle init --type java-application После этого запускаем IntelliJ Idea. Если у вас появится окно с уже открытым проектом (увидите редактор кода, дерево структуры проекта), закроем этот проект при помощи File -< Close Project. Теперь в окне приветствия выполним "Import Project" и импортируем наш новый проект. При импорте выставим флаг "Use autoimport". Давайте разбираться, можно ли как-то упростить жизнь при помощи современных инструментов разработки.

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

Выполнив импорт проекта, нажмём комбинацию клавиш Ctrl+N и перейдём в класс AppTest. Этот класс — класс теста по умолчанию. Он имеет следующий вид:

import org.junit.Test;
import static org.junit.Assert.*;

public class AppTest {
    @Test public void testAppHasAGreeting() {
        App classUnderTest = new App();
        assertNotNull("app should have a greeting", classUnderTest.getGreeting());
    }
}
Что тут сразу бросается в глаза? Аннотация с объявлением метода на одной строке, что выглядит некрасиво, согласитесь. Как же это исправить? В IntelliJ Idea есть раздел меню "Code" для различных манипуляций с кодом. Одной из такой манипуляций является "Reformat Code" или комбинация клавиш Ctrl + L. После применения аннотация будет на одной строке, а сам метод — на другой. Стоит сразу заметить, что данная операция выполняется над выделенным участком кода. А если такого нет, операция форматирования будет выполнена над всем содержимым. Давайте теперь добавим новый тестовый метод:

@Test
public void testSummOfOddNumbers() {
	List<Integer> data = Arrays.asList(1, 4, 2, 3, 6, 7, 9);
	Integer result = data.stream().filter(number -> number % 2 == 0).reduce((n1, n2) -> n1 + n2).get();
	assertThat(result, is(12));
}
И два импорта:

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
Как видно, операция над Stream размещена в одну строку. А что если мы хотим сделать так, чтобы всегда методы, вызов которых выстроен в цепочку, разбивало по точке на новые строки? С одной стороны, мы можем это сделать вручную. Но помните, что мы хотим, чтобы у нас всё работало само. Ведь периодически мы будем забывать, и формат кода станет везде разным, а это не есть хорошо. Получается, надо отредактировать правило, по которому Idea выполняет форматирование. Выберем в Idea в меню пункт File -> Settings (или нажмём Ctrl + Alt + S). В поле поиска в окне настроек напишем "Code style". В разделе Code style есть возможность указать настройки не только для Java. Но сейчас нас интересует именно Java. Как видно, настройки разбиты на несколько вкладок. Что самое полезное, так это то, что результат изменения будет показан на примере в правой части окна:
IntelliJ IDEA: стиль и форматирование кода - 2
Как видно на скриншоте, мы можем указать настройку для "Chained method calls" как "wrap always", т.е. разбивать всегда для объединённых вызовов методов. Теперь нажмём ещё раз форматирование в тесте и увидим, что это действительно работает! Но иногда бывает, что есть нужда отформатировать какой-нибудь код вне общих правил форматирования. Настроим форматирование следующим образом:
IntelliJ IDEA: стиль и форматирование кода - 3
Чтобы форматирование можно было отключать, в разделе Code Style необходимо включить поддержку маркеров отключения форматирования:
IntelliJ IDEA: стиль и форматирование кода - 4
Теперь мы сможем изменить код нашего теста так, что его форматирование останется в том виде, в котором это напишем мы:

@Test
public void testSummOfOddNumbers() {
	List<Integer> data = Arrays.asList(1, 4, 2, 3, 6, 7, 9);
	// @formatter:off
	Integer result = data.stream().filter(number -> number % 2 == 0)
                             .reduce((n1, n2) -> n1 + n2)
                             .get();
	assertThat(result, is(12));
	// @formatter:on
}
Да, если вы заметили: когда вы нажимаете Tab, Idea за вас его интерпретирует как пробелы (поведение по умолчанию). Но изменить это можно там же в Code Style:
IntelliJ IDEA: стиль и форматирование кода - 5
Как Вы видете, там огромное множество настроек. Более подробно про настройки Code style можно прочитать здесь: "Idea Help: Code Style". Есть ещё одна важная особенность форматирования — форматирование импортов. Оно выполняется отдельно и называется "Optimize Imports" и находится в пункте меню Code -> Optimize Imports (Ctrl + Alt + O). Оптимизация импортов убирает ненужные импорты, а также располагает их в правильном порядке в соответствии с настройками из вкладки Imports настроек Code Style для Java. Кроме того, если вам захочется, чтобы форматирование происходило автоматически, для вас есть хорошая новость: это можно сделать при помощи плагина Save Actions.

Распространение настроек в команде

Отлично, выше мы увидели, что можно настроить стиль форматирования так, как нам удобно. Но как этот стиль использовать в команде? Очень просто. Есть несколько вариантов. Самый простой — сохранить схему. Откроем настройки Idea через File -> Settings (или нажмём Ctrl + Alt + S). В разделе Code Style мы можем увидеть надпись Scheme. Это наша схема форматирования. По умолчанию указана схема с именем Default и рядом приписка IDE: это значит, что это настройка только для нашей IDE, и она не действует ни на кого. Чтобы сделать "пользовательскую" схему, по кнопке справа делаем "дубликат" и даём ему название, например: JavaRush
IntelliJ IDEA: стиль и форматирование кода - 6
После этого мы сможем импортировать или экспортировать настройки:
IntelliJ IDEA: стиль и форматирование кода - 7
Другой вариант — это импорт импорт настроек Idea:
IntelliJ IDEA: стиль и форматирование кода - 8
Третий вариант — Settings Repository. Про использование Settings Repository см. подробнее документацию "IntelliJ Idea Help : Settings Repository". В тему распространения единого стиля в команде также не могу не отметить хорошую поддержку стилей из IDE Eclipse. Для этого потребуется установка отдельного плагина: откройте настройки Idea через File -> Settings (Ctrl + Alt + S) и перейдите в раздел Plugins. Для поиска новых плагинов нажмём кнопку "Browse Repositories", после чего в окне поиска найдём плагин Eclipse Code Formatter.
IntelliJ IDEA: стиль и форматирование кода - 9
Теперь, после установки, необходимо перезапустить Idea — это стандартная процедура. После этого всё там же, в настройках Idea, мы найдём новый раздел: "Eclipse Code Formatter" Пример файла форматирования для Eclipse можно взять здесь. Выглядеть это будет примерно так:
IntelliJ IDEA: стиль и форматирование кода - 10

Ужесточение требований

Помимо средств Idea, можно также использовать плагины систем сборок для ужесточения требований. Никак не проверишь, что человек использовал форматирование. Если в команде 5 человек — ещё можно. Если в компании 100 человек — нереально. Да даже за пятью уследить будет трудно. Да и зачем лишняя трата времени на такое? Куда проще запретить собирать проект при нарушении некоторых правил. На самом деле, это уже целая отдельная тема под названием "Inspect Code". В рамках данной статьи хочется просто показать, как это работает. Одним из самых распространённых плагинов для Gradle (т.к. он собирает у нас проект, если помните) является pmd. Для его включения достаточно перейти в build script нашего gradle проекта (файл build.gradle в корне нашего проекта) и указать в нём pmd рядом с остальными плагинами:

plugins {
    // Apply the java plugin to add support for Java
    id 'java'
    // Check source code
    id 'pmd'
    // Apply the application plugin to add support for building an application
    id 'application'
}
Теперь можем задать более детальные настройки там же:

pmd {
    ignoreFailures = false
    pmdTest.enabled = true
    ruleSets = [
            'java-basic',
            'java-braces',
            'java-clone',
            'java-codesize',
            'java-comments',
            'java-controversial',
            'java-coupling',
            'java-design',
            'java-empty',
            'java-finalizers',
            'java-imports',
            'java-optimizations',
            'java-strictexception',
            'java-strings',
            'java-typeresolution',
            'java-unnecessary',
            'java-unusedcode'
    ]
}
Даже в нашем проекте уже всё не хорошо. Выполним gradle build и получим ошибку. Что приятно, при сборке формируется отчёт. И если будут ошибки, мы получим сообщение вида:

BUILD FAILED in 35s
6 actionable tasks: 6 executed
7 PMD rule violations were found. See the report at: file:///C:/_study/codestyle/build/reports/pmd/main.html
Если мы перейдём в отчёт, увидим что-то вроде:
IntelliJ IDEA: стиль и форматирование кода - 11
Причём в колонке Problem дана ссылка на описание проблемы на сайте плагина pmd. Например, для ошибки "headerCommentRequirement Required" ссылка ведёт сюда: pmd - CommentRequired. Данная ошибка намекает нам, что наш класс не имеет JavaDoc. Наличие JavaDoc над классами можно настроить при помощи шаблонов:
IntelliJ IDEA: стиль и форматирование кода - 12
И указать для File Header содержимое:
IntelliJ IDEA: стиль и форматирование кода - 13
После этого можем превратить комментарий над классом App в JavaDoc и увидим при новом Build, что ошибка исчезла.

Итог

Стиль кода важен для продуктивной работы над проектом. Красивый код, написанный по общим правилам — залог того, что ваши коллеги его проще и быстрее поймут, и не скажут в ваш адрес пары ласковых. Учитывая современные средства разработки придерживаться правил не так уж сложно. Надеюсь, данный обзор показал, что это действительно так. Ну и по традиции, немного материала по теме: #Viacheslav
Комментарии (1)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Шамиль Зарипов Уровень 5
16 октября 2018
Долго смеялся над ситуацией в сериале "Силиконовая долина", где Ричард поссорился с девушкой из-за пробелов и табов, но про себя-то думал, что пользуюсь табами.... Пока не прочитал эту статью и не полез в настройки...) На гитхаб мои пока ещё учебные примеры-то падают с пробелами (а если начать менять, начинается ерунда). Короче, глупость Ричарда в фильме мне показалась глупостью, так что оставлю как есть, буду всё валить на IDE)