Стиль кода Java AOSP для участников

Стили кода на этой странице — это строгие правила для добавления кода Java в Android Open Source Project (AOSP). Вклады в платформу Android, которые не соответствуют этим правилам, как правило , не принимаются . Мы понимаем, что не весь существующий код соответствует этим правилам, но мы ожидаем, что весь новый код будет им соответствовать. См. Кодирование с уважением для примеров терминологии, которую следует использовать и избегать для более инклюзивной экосистемы.

Быть последовательным

Одно из самых простых правил – БУДЬТЕ ПОСЛЕДОВАТЕЛЬНЫ. Если вы редактируете код, потратьте несколько минут, чтобы посмотреть на окружающий код и определить его стиль. Если этот код использует пробелы вокруг предложений if , вы тоже должны это делать. Если вокруг комментариев к коду есть звездочки, сделайте так, чтобы вокруг ваших комментариев тоже были звездочки.

Смысл руководства по стилю состоит в том, чтобы иметь общий словарь кодирования, чтобы читатели могли сосредоточиться на том, что вы говорите, а не на том, как вы это говорите. Мы представляем здесь глобальные правила стиля, чтобы вы знали словарный запас, но локальный стиль также важен. Если код, который вы добавляете в файл, сильно отличается от окружающего его кода, это выбивает читателей из ритма, когда они его читают. Постарайтесь избежать этого.

Правила языка Java

Android следует стандартным соглашениям о кодировании Java с дополнительными правилами, описанными ниже.

Не игнорируйте исключения

Может возникнуть соблазн написать код, который игнорирует исключение, например:

  void setServerPort(String value) {
      try {
          serverPort = Integer.parseInt(value);
      } catch (NumberFormatException e) { }
  }

Не делай этого. Хотя вы можете думать, что ваш код никогда не столкнется с этим состоянием ошибки или что его не нужно обрабатывать, игнорирование этого типа исключения создает мины в вашем коде, которые кто-то другой может когда-нибудь спровоцировать. Вы должны принципиально обрабатывать каждое исключение в своем коде; конкретное обращение варьируется в зависимости от случая.

« Каждый раз, когда у кого-то есть пустое предложение catch, у него должно быть жуткое чувство. Определенно бывают случаи, когда это действительно правильно, но, по крайней мере, вам нужно подумать об этом. В Java вы не можете избежать жуткого чувства. " — Джеймс Гослинг

Приемлемые альтернативы (в порядке предпочтения):

  • Бросьте исключение вызывающей стороне вашего метода.
      void setServerPort(String value) throws NumberFormatException {
          serverPort = Integer.parseInt(value);
      }
    
  • Создайте новое исключение, соответствующее вашему уровню абстракции.
      void setServerPort(String value) throws ConfigurationException {
        try {
            serverPort = Integer.parseInt(value);
        } catch (NumberFormatException e) {
            throw new ConfigurationException("Port " + value + " is not valid.");
        }
      }
    
  • Аккуратно обработайте ошибку и замените соответствующее значение в блоке catch {} .
      /** Set port. If value is not a valid number, 80 is substituted. */
    
      void setServerPort(String value) {
        try {
            serverPort = Integer.parseInt(value);
        } catch (NumberFormatException e) {
            serverPort = 80;  // default port for server
        }
      }
    
  • Перехватите исключение и создайте новый экземпляр RuntimeException . Это опасно, поэтому делайте это только в том случае, если вы уверены, что в случае возникновения этой ошибки правильным решением будет сбой.
      /** Set port. If value is not a valid number, die. */
    
      void setServerPort(String value) {
        try {
            serverPort = Integer.parseInt(value);
        } catch (NumberFormatException e) {
            throw new RuntimeException("port " + value " is invalid, ", e);
        }
      }
    
  • В крайнем случае, если вы уверены, что игнорирование исключения уместно, вы можете игнорировать его, но вы также должны прокомментировать, почему с уважительной причиной.
    /** If value is not a valid number, original port number is used. */
    
    void setServerPort(String value) {
        try {
            serverPort = Integer.parseInt(value);
        } catch (NumberFormatException e) {
            // Method is documented to just ignore invalid user input.
            // serverPort will just be unchanged.
        }
    }
    

Не перехватывайте общие исключения

Может возникнуть соблазн полениться перехватывать исключения и сделать что-то вроде этого:

  try {
      someComplicatedIOFunction();        // may throw IOException
      someComplicatedParsingFunction();   // may throw ParsingException
      someComplicatedSecurityFunction();  // may throw SecurityException
      // phew, made it all the way
  } catch (Exception e) {                 // I'll just catch all exceptions
      handleError();                      // with one generic handler!
  }

Не делай этого. Почти во всех случаях нецелесообразно перехватывать общие Exception или Throwable (желательно не Throwable поскольку они включают исключения Error ). Это опасно, потому что это означает, что исключения, которых вы никогда не ожидали (включая исключения времени выполнения, такие как ClassCastException ), попадают в обработку ошибок на уровне приложения. Он скрывает свойства обработки ошибок вашего кода, а это означает, что если кто-то добавит новый тип исключения в код, который вы вызываете, компилятор не укажет, что вам нужно обрабатывать ошибку по-другому. В большинстве случаев вы не должны одинаково обрабатывать различные типы исключений.

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

Альтернативы перехвату общих исключений:

  • Перехватывайте каждое исключение отдельно как часть блока с несколькими перехватами, например:
    try {
        ...
    } catch (ClassNotFoundException | NoSuchMethodException e) {
        ...
    }
    .
  • Рефакторинг вашего кода, чтобы обеспечить более точную обработку ошибок с несколькими блоками try. Отделите ввод-вывод от синтаксического анализа и обрабатывайте ошибки отдельно в каждом случае.
  • Сбросить исключение. Во многих случаях вам все равно не нужно перехватывать исключение на этом уровне, просто позвольте методу сгенерировать его.

Помните, что исключения — ваши друзья! Когда компилятор жалуется, что вы не перехватываете исключение, не сердитесь. Улыбка! Компилятор просто упростил обнаружение проблем во время выполнения в вашем коде.

Не используйте финализаторы

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

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

Полностью квалифицировать импорт

Если вы хотите использовать класс Bar из пакета foo , есть два возможных способа импортировать его:

  • import foo.*;

    Потенциально уменьшает количество операторов импорта.

  • import foo.Bar;

    Делает очевидным, какие классы используются, и код становится более читаемым для сопровождающих.

Используйте import foo.Bar; для импорта всего кода Android. Явное исключение делается для стандартных библиотек Java ( java.util.* , java.io.* и т. д.) и кода модульного тестирования ( junit.framework.* ).

Правила библиотеки Java

Существуют соглашения по использованию библиотек и инструментов Android для Java. В некоторых случаях соглашение существенно изменилось, и старый код может использовать устаревший шаблон или библиотеку. При работе с таким кодом можно продолжать существующий стиль. Однако при создании новых компонентов никогда не используйте устаревшие библиотеки.

Правила стиля Java

Используйте стандартные комментарии Javadoc

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

/*
 * Copyright 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.internal.foo;

import android.os.Blah;
import android.view.Yada;

import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * Does X and Y and provides an abstraction for Z.
 */

public class Foo {
    ...
}

Каждый написанный вами класс и нетривиальный общедоступный метод должен содержать комментарий Javadoc, по крайней мере, с одним предложением, описывающим, что делает класс или метод. Это предложение должно начинаться с описательного глагола третьего лица.

Примеры

/** Returns the correctly rounded positive square root of a double value. */

static double sqrt(double a) {
    ...
}

или

/**
 * Constructs a new String by converting the specified array of
 * bytes using the platform's default character encoding.
 */
public String(byte[] bytes) {
    ...
}

Вам не нужно писать Javadoc для тривиальных методов получения и установки, таких как setFoo() , если все, что ваш Javadoc сказал бы, это "sets Foo". Если метод делает что-то более сложное (например, принудительное применение ограничения или имеет важный побочный эффект), то вы должны это задокументировать. Если не очевидно, что означает свойство «Foo», вы должны задокументировать это.

Каждый написанный вами метод, публичный или нет, выиграет от Javadoc. Публичные методы являются частью API и поэтому требуют Javadoc. Android не применяет определенный стиль для написания комментариев Javadoc, но вы должны следовать инструкциям в разделе Как писать комментарии к документам для инструмента Javadoc .

Пишите короткие методы

По возможности делайте методы небольшими и сфокусированными. Мы понимаем, что длинные методы иногда уместны, поэтому на длину метода не накладывается жесткого ограничения. Если метод превышает 40 строк или около того, подумайте, можно ли его разбить без ущерба для структуры программы.

Определите поля в стандартных местах

Определяйте поля либо в верхней части файла, либо непосредственно перед методами, которые их используют.

Ограничить область видимости переменной

Сведите объем локальных переменных к минимуму. Это повышает удобочитаемость и ремонтопригодность вашего кода и снижает вероятность ошибки. Объявите каждую переменную в самом внутреннем блоке, который содержит все варианты использования переменной.

Объявляйте локальные переменные в том месте, где они впервые используются. Почти каждое объявление локальной переменной должно содержать инициализатор. Если у вас еще недостаточно информации для разумной инициализации переменной, отложите объявление до тех пор, пока вы ее не сделаете.

Исключением являются операторы try-catch. Если переменная инициализируется возвращаемым значением метода, выдающего проверенное исключение, она должна быть инициализирована внутри блока try. Если значение должно использоваться вне блока try, то оно должно быть объявлено перед блоком try, где оно еще не может быть правильно инициализировано:

// Instantiate class cl, which represents some sort of Set

Set s = null;
try {
    s = (Set) cl.newInstance();
} catch(IllegalAccessException e) {
    throw new IllegalArgumentException(cl + " not accessible");
} catch(InstantiationException e) {
    throw new IllegalArgumentException(cl + " not instantiable");
}

// Exercise the set
s.addAll(Arrays.asList(args));

Однако вы даже можете избежать этого случая, инкапсулировав блок try-catch в метод:

Set createSet(Class cl) {
    // Instantiate class cl, which represents some sort of Set
    try {
        return (Set) cl.newInstance();
    } catch(IllegalAccessException e) {
        throw new IllegalArgumentException(cl + " not accessible");
    } catch(InstantiationException e) {
        throw new IllegalArgumentException(cl + " not instantiable");
    }
}

...

// Exercise the set
Set s = createSet(cl);
s.addAll(Arrays.asList(args));

Объявляйте переменные цикла в самом операторе for, если нет веской причины сделать иначе:

for (int i = 0; i < n; i++) {
    doSomething(i);
}

а также

for (Iterator i = c.iterator(); i.hasNext(); ) {
    doSomethingElse(i.next());
}

Заказать отчеты об импорте

Порядок операторов импорта следующий:

  1. Импорт Android
  2. Импорт от третьих лиц ( com , junit , net , org )
  3. java и javax

Чтобы точно соответствовать настройкам IDE, импорт должен быть:

  • В алфавитном порядке внутри каждой группы, с заглавными буквами перед строчными (например, Z перед a)
  • Каждая основная группа разделена пустой строкой ( android , com , junit , net , org , java , javax ).

Первоначально не было требований к стилю для порядка, а это означало, что IDE либо всегда меняли порядок, либо разработчикам IDE приходилось отключать функции автоматического управления импортом и вручную поддерживать импорт. Это считалось плохим. Когда был задан вопрос о стиле Java, предпочтительные стили сильно различались, и все сводилось к тому, что Android нужно было просто «выбрать порядок и быть последовательным». Итак, мы выбрали стиль, обновили руководство по стилю и заставили IDE ему подчиняться. Мы ожидаем, что по мере того, как пользователи IDE будут работать над кодом, импорт во всех пакетах будет соответствовать этому шаблону без дополнительных инженерных усилий.

Мы выбрали этот стиль таким образом, что:

  • Импорт, который люди хотят посмотреть в первую очередь, как правило, находится вверху ( android ).
  • Импорт, который люди хотят посмотреть, как минимум, обычно находится внизу ( java ).
  • Люди могут легко следовать стилю.
  • IDE могут следовать стилю.

Поместите статический импорт выше всех других импортов, упорядоченных так же, как и обычный импорт.

Используйте пробелы для отступов

Мы используем четыре (4) отступа для блоков и никогда не используем вкладки. Если вы сомневаетесь, соблюдайте окружающий код.

Мы используем восемь (8) пробелов для переноса строк, включая вызовы функций и присваивания.

рекомендуемые

Instrument i =
        someLongExpression(that, wouldNotFit, on, one, line);

Не рекомендуется

Instrument i =
    someLongExpression(that, wouldNotFit, on, one, line);

Соблюдайте соглашения об именах полей

  • Непубличные, нестатические имена полей начинаются с m .
  • Имена статических полей начинаются с s .
  • Другие поля начинаются со строчной буквы.
  • Статические конечные поля (константы, глубоко неизменяемые) — ALL_CAPS_WITH_UNDERSCORES .

Например:

public class MyClass {
    public static final int SOME_CONSTANT = 42;
    public int publicField;
    private static MyClass sSingleton;
    int mPackagePrivate;
    private int mPrivate;
    protected int mProtected;
}

Используйте стандартный стиль скобок

Ставьте фигурные скобки на той же строке, что и код перед ними, а не на отдельной строке:

class MyClass {
    int func() {
        if (something) {
            // ...
        } else if (somethingElse) {
            // ...
        } else {
            // ...
        }
    }
}

Нам нужны фигурные скобки вокруг утверждений условного оператора. Исключение: если все условное предложение (условие и тело) умещается на одной строке, вы можете (но не обязаны) поместить его все на одну строку. Например, допустимо:

if (condition) {
    body();
}

и это приемлемо:

if (condition) body();

но это неприемлемо:

if (condition)
    body();  // bad!

Ограничить длину строки

Каждая строка текста в вашем коде должна иметь длину не более 100 символов. Несмотря на то, что вокруг этого правила было много дискуссий, остается решение, что 100 символов — это максимум со следующими исключениями :

  • Если строка комментария содержит пример команды или буквальный URL-адрес длиннее 100 символов, эта строка может быть длиннее 100 символов для удобства вырезания и вставки.
  • Строки импорта могут превышать лимит, потому что люди редко их видят (это также упрощает написание инструментов).

Используйте стандартные аннотации Java

Аннотации должны предшествовать другим модификаторам того же языкового элемента. Аннотации простых маркеров (например, @Override ) могут быть перечислены в одной строке с элементом языка. Если имеется несколько аннотаций или параметризованных аннотаций, перечислите их по одной на строку в алфавитном порядке.

Стандартные практики Android для трех предопределенных аннотаций в Java:

  • Используйте аннотацию @Deprecated всякий раз, когда использование аннотированного элемента не рекомендуется. Если вы используете аннотацию @Deprecated , у вас также должен быть тег @deprecated Javadoc, и он должен указывать альтернативную реализацию. Кроме того, помните, что метод @Deprecated по- прежнему должен работать . Если вы видите старый код с тегом Javadoc @deprecated , добавьте аннотацию @Deprecated .
  • Используйте аннотацию @Override всякий раз, когда метод переопределяет объявление или реализацию из суперкласса. Например, если вы используете тег @inheritdocs Javadoc и наследуете класс (а не интерфейс), вы также должны отметить, что метод переопределяет метод родительского класса.
  • Используйте аннотацию @SuppressWarnings только в тех случаях, когда невозможно удалить предупреждение. Если предупреждение проходит этот тест «невозможно устранить», необходимо использовать аннотацию @SuppressWarnings , чтобы гарантировать, что все предупреждения отражают реальные проблемы в коде.

    Когда аннотация @SuppressWarnings необходима, она должна начинаться с комментария TODO , объясняющего условие «невозможно устранить». Обычно это идентифицирует класс-нарушитель с неудобным интерфейсом. Например:

    // TODO: The third-party class com.third.useful.Utility.rotate() needs generics
    @SuppressWarnings("generic-cast")
    List<String> blix = Utility.rotate(blax);
    

    Если требуется аннотация @SuppressWarnings , выполните рефакторинг кода, чтобы изолировать программные элементы, к которым применяется аннотация.

Относитесь к аббревиатурам как к словам

Считайте аббревиатуры и аббревиатуры словами в именах переменных, методов и классов, чтобы сделать имена более читабельными:

Хорошо Плохой
XmlHttpRequest XMLHTTPRequest
getCustomerId получитьCustomerID
класс HTML класс HTML
Строковый URL URL-адрес строки
длинный идентификатор длинный идентификатор

Поскольку базы кода JDK и Android несовместимы с аббревиатурами, практически невозможно добиться согласованности с окружающим кодом. Поэтому всегда относитесь к аббревиатурам как к словам.

Используйте комментарии TODO

Используйте комментарии TODO для кода, который является временным, краткосрочным решением или достаточно хорошим, но не идеальным. Эти комментарии должны включать строку TODO всеми заглавными буквами, за которой следует двоеточие:

// TODO: Remove this code after the UrlTable2 has been checked in.

а также

// TODO: Change this to use a flag instead of a constant.

Если ваш TODO имеет форму «Сделайте что-нибудь в будущем», убедитесь, что вы указали либо конкретную дату («Исправить к ноябрю 2005 г.»), либо конкретное событие («Удалите этот код после того, как все микшеры продакшена поймут протокол V7». ).

Войти экономно

Хотя ведение журнала необходимо, оно негативно влияет на производительность и теряет свою полезность, если не вести его достаточно кратко. Средства ведения журнала обеспечивают пять различных уровней ведения журнала:

  • ERROR : используйте, когда произошло что-то фатальное, то есть что-то будет иметь видимые для пользователя последствия и не может быть восстановлено без удаления некоторых данных, удаления приложений, очистки разделов данных или перепрошивки всего устройства (или хуже). Этот уровень всегда регистрируется. О проблемах, которые оправдывают некоторую регистрацию на уровне ERROR , можно сообщить на сервер сбора статистики.
  • WARNING . Используйте, когда произошло что-то серьезное и неожиданное, то есть что-то, что будет иметь видимые для пользователя последствия, но может быть восстановлено без потери данных путем выполнения какого-либо явного действия, начиная от ожидания или перезапуска приложения и заканчивая повторной загрузкой. новая версия приложения или перезагрузка устройства. Этот уровень всегда регистрируется. Проблемы, которые оправдывают ведение журнала на уровне WARNING , также могут быть рассмотрены для отправки отчетов на сервер сбора статистики.
  • INFORMATIVE : Используйте, чтобы отметить, что произошло что-то интересное, то есть когда обнаружена ситуация, которая может иметь широкомасштабные последствия, хотя и не обязательно является ошибкой. Такое условие должно регистрироваться только тем модулем, который считает, что он является наиболее авторитетным в этом домене (во избежание двойного ведения журнала неавторизованными компонентами). Этот уровень всегда регистрируется.
  • DEBUG : Используйте, чтобы дополнительно отметить, что происходит на устройстве, что может иметь отношение к расследованию и отладке неожиданного поведения. Записывайте в журнал только то, что необходимо для сбора достаточной информации о том, что происходит с вашим компонентом. Если ваши журналы отладки преобладают в журнале, вам следует использовать подробный журнал.

    Этот уровень регистрируется даже в релизных сборках и должен быть окружен if (LOCAL_LOG) или if LOCAL_LOGD) , где LOCAL_LOG[D] определен в вашем классе или подкомпоненте, чтобы была возможность отключить все такие журналы. . Следовательно, в блоке if (LOCAL_LOG) не должно быть активной логики. Все построение строк для лога также нужно поместить внутрь блока if (LOCAL_LOG) . Не преобразовывайте вызов ведения журнала в вызов метода, если это приведет к тому, что построение строки произойдет за пределами блока if (LOCAL_LOG) .

    Есть некоторый код, который все еще говорит if (localLOGV) . Это тоже считается приемлемым, хотя название нестандартное.

  • VERBOSE : Используйте для всего остального. Этот уровень регистрируется только в отладочных сборках и должен быть окружен блоком if (LOCAL_LOGV) (или эквивалентным), чтобы его можно было скомпилировать по умолчанию. Любое строковое построение удаляется из сборок выпуска и должно отображаться внутри блока if (LOCAL_LOGV) .

Примечания

  • В данном модуле, за исключением уровня VERBOSE , об ошибке следует сообщать только один раз, если это возможно. В одной цепочке вызовов функций в модуле только самая внутренняя функция должна возвращать ошибку, а вызывающие функции в том же модуле должны добавлять некоторую регистрацию только в том случае, если это значительно помогает изолировать проблему.
  • В цепочке модулей, отличной от уровня VERBOSE , когда модуль более низкого уровня обнаруживает недопустимые данные, поступающие от модуля более высокого уровня, модуль более низкого уровня должен только записывать эту ситуацию в журнал DEBUG , и только если журналирование обеспечивает информацию, которая иначе недоступна для вызывающего абонента. В частности, нет необходимости регистрировать ситуации, когда возникает исключение (исключение должно содержать всю необходимую информацию) или когда единственная регистрируемая информация содержится в коде ошибки. Это особенно важно при взаимодействии между платформой и приложениями, и условия, вызванные сторонними приложениями, которые должным образом обрабатываются платформой, не должны инициировать ведение журнала выше уровня DEBUG . Единственные ситуации, которые должны инициировать ведение журнала на INFORMATIVE уровне или выше, — это когда модуль или приложение обнаруживает ошибку на своем собственном уровне или на более низком уровне.
  • Когда условие, которое обычно оправдывает некоторую запись в журнал, вероятно, возникает много раз, может быть хорошей идеей реализовать какой-либо механизм ограничения скорости, чтобы предотвратить переполнение журналов множеством дубликатов одной и той же (или очень похожей) информации.
  • Потеря подключения к сети считается обычным явлением и вполне ожидаема, и ее не следует регистрировать необоснованно. Потеря подключения к сети, имеющая последствия для приложения, должна регистрироваться на уровне DEBUG или VERBOSE (в зависимости от того, являются ли последствия достаточно серьезными и неожиданными, чтобы их можно было зарегистрировать в сборке выпуска).
  • Наличие полной файловой системы в файловой системе, доступной для сторонних приложений или от их имени, не должно регистрироваться на уровне выше ИНФОРМАЦИОННОГО.
  • Недопустимые данные, поступающие из любого ненадежного источника (включая любой файл в общем хранилище или данные, поступающие через сетевое соединение), считаются ожидаемыми и не должны инициировать запись в журнал на уровне выше, чем DEBUG , когда они обнаружены как недействительные (и даже тогда должно быть как можно меньше).
  • При использовании на объектах String оператор + неявно создает экземпляр StringBuilder с размером буфера по умолчанию (16 символов) и потенциально другими временными объектами String . Таким образом, явное создание объектов StringBuilder не дороже, чем использование оператора + по умолчанию (и может быть намного эффективнее). Имейте в виду, что код, который вызывает Log.v() , компилируется и выполняется в сборках выпуска, включая построение строк, даже если журналы не читаются.
  • Любое ведение журнала, предназначенное для чтения другими людьми и доступное в релизных сборках, должно быть кратким, но не загадочным и должно быть понятным. Это включает в себя всю регистрацию до уровня DEBUG .
  • По возможности продолжайте вести журнал одной строкой. Допускается длина строки до 80 или 100 символов. По возможности избегайте длины более 130 или 160 символов (включая длину тега).
  • Если протоколирование сообщает об успехе, никогда не используйте его на уровнях выше VERBOSE .
  • Если вы используете временное ведение журнала для диагностики проблемы, которую трудно воспроизвести, оставьте ее на уровне DEBUG или VERBOSE и заключите в блоки if, которые позволяют отключить ее во время компиляции.
  • Будьте осторожны с утечками безопасности через журнал. Избегайте регистрации личной информации. В частности, избегайте регистрации информации о защищенном контенте. Это особенно важно при написании кода фреймворка, так как нелегко заранее знать, что будет, а что не будет частной информацией или защищенным содержимым.
  • Никогда не используйте System.out.println() (или printf() для нативного кода). System.out и System.err перенаправляются на /dev/null , поэтому ваши операторы печати не имеют видимых эффектов. Однако все построение строк, которое происходит для этих вызовов, все равно выполняется.
  • Золотое правило ведения журналов заключается в том, что ваши журналы не должны без необходимости вытеснять другие журналы из буфера, так же как другие не могут вытеснять ваши.

Правила стиля Javatests

Следуйте соглашениям об именах методов тестирования и используйте знак подчеркивания, чтобы отделить то, что тестируется, от конкретного тестируемого случая. Этот стиль упрощает просмотр того, какие случаи тестируются. Например:

testMethod_specificCase1 testMethod_specificCase2

void testIsDistinguishable_protanopia() {
    ColorMatcher colorMatcher = new ColorMatcher(PROTANOPIA)
    assertFalse(colorMatcher.isDistinguishable(Color.RED, Color.BLACK))
    assertTrue(colorMatcher.isDistinguishable(Color.X, Color.Y))
}