Ten dokument zawiera pełną definicję standardów kodowania w Google dla kodu źródłowego w języku programowania Kotlin. Plik źródłowy w języku Kotlin jest uznawany za zgodny ze stylem Google Android tylko wtedy, gdy przestrzega zasad opisanych w tym dokumencie.
Podobnie jak w przypadku innych przewodników po stylach programowania, omawiane problemy obejmują nie tylko kwestie estetyczne związane z formatowaniem, ale także inne rodzaje konwencji i standardów kodowania. Ten dokument koncentruje się jednak przede wszystkim na ścisłych zasadach, których przestrzegamy powszechnie, i nie zawiera porad, których nie można jednoznacznie wyegzekwować (ani przez człowieka, ani przez narzędzie).
Ostatnia aktualizacja: 2023-09-06
Pliki źródłowe
Wszystkie pliki źródłowe muszą być zakodowane w formacie UTF-8.
Nazwa
Jeśli plik źródłowy zawiera tylko jedną klasę najwyższego poziomu, nazwa pliku powinna odzwierciedlać nazwę z uwzględnieniem wielkości liter oraz rozszerzenie .kt. W przeciwnym razie, jeśli plik źródłowy zawiera kilka deklaracji najwyższego poziomu, wybierz nazwę opisującą zawartość pliku, zastosuj notację PascalCase (notacja camelCase jest dopuszczalna, jeśli nazwa pliku jest w liczbie mnogiej) i dodaj rozszerzenie .kt.
// MyClass.kt class MyClass { }
// Bar.kt class Bar { } fun Runnable.toBar(): Bar = Bar()
// Map.kt fun <T, O> Set<T>.map(func: (T) -> O): List<O> = emptyList() fun <T, O> List<T>.map(func: (T) -> O): List<O> = emptyList()
// extensions.kt fun MyClass.process() = { /* ... */ } fun MyResult.print() = { /* ... */ }
Znaki specjalne
Znaki odstępu
Oprócz sekwencji zakończenia wiersza w pliku źródłowym może występować tylko znak spacji ASCII (0x20). Oznacza to, że:
- Wszystkie inne znaki odstępu w ciągach znaków i literałach znakowych są objęte kodowaniem.
- Do wcięć nie używa się znaków tabulacji.
Specjalne sekwencje zmiany znaczenia
W przypadku każdego znaku, który ma specjalną sekwencję zmiany znaczenia (\b, \n, \r, \t, \', \", \\ i \$), używana jest ta sekwencja, a nie odpowiednia sekwencja zmiany znaczenia Unicode (np. \u000a).
Znaki inne niż ASCII
W przypadku pozostałych znaków spoza zestawu ASCII używany jest rzeczywisty znak Unicode (np. ∞) lub jego odpowiednik w postaci znaku modyfikacji Unicode (np. \u221e).
Wybór zależy tylko od tego, która opcja sprawia, że kod jest łatwiejszy do odczytania i zrozumienia.
Nie zalecamy używania sekwencji Unicode w przypadku znaków drukowalnych w dowolnym miejscu. Zdecydowanie odradzamy ich stosowanie poza literałami ciągów znaków i komentarzami.
| Przykład | Dyskusja |
|---|---|
val unitAbbrev = "μs" |
Najlepszy: doskonale zrozumiały nawet bez komentarza. |
val unitAbbrev = "\u03bcs" // μs |
Słabo: nie ma powodu, aby używać znaku ucieczki ze znakiem, który można wydrukować. |
val unitAbbrev = "\u03bcs" |
Słaba: czytelnik nie ma pojęcia, o co chodzi. |
return "\ufeff" + content |
Dobrze: używaj znaków ucieczki w przypadku znaków niedrukowalnych i w razie potrzeby dodawaj komentarze. |
Struktura
Plik .kt zawiera w kolejności:
- Nagłówek dotyczący praw autorskich lub licencji (opcjonalnie)
- Adnotacje na poziomie pliku
- Oświadczenie dotyczące pakietu
- Importowanie wyciągów
- Deklaracje najwyższego poziomu
Każda z tych sekcji jest oddzielona od pozostałych dokładnie 1 pustym wierszem.
Prawa autorskie / licencja
Jeśli nagłówek dotyczący praw autorskich lub licencji powinien znajdować się w pliku, należy go umieścić na samym początku w komentarzu wielowierszowym.
/* * Copyright 2017 Google, Inc. * * ... */
Nie używaj komentarza w stylu KDoc ani komentarza jednoliniowego.
/** * Copyright 2017 Google, Inc. * * ... */
// Copyright 2017 Google, Inc. // // ...
Adnotacje na poziomie pliku
Adnotacje z miejscem docelowym „file” są umieszczane między dowolnym komentarzem w nagłówku a deklaracją pakietu.
Oświadczenie dotyczące pakietu
Oświadczenie o pakiecie nie podlega żadnym ograniczeniom liczby kolumn i nigdy nie jest zawijane.
Importowanie wyciągów
Instrukcje importowania klas, funkcji i właściwości są pogrupowane na jednej liście i posortowane według kodu ASCII.
Importy z użyciem symboli wieloznacznych (dowolnego typu) są niedozwolone.
Podobnie jak w przypadku instrukcji pakietu, instrukcje importu nie podlegają limitowi kolumn i nigdy nie są zawijane.
Deklaracje najwyższego poziomu
.kt Plik może deklarować co najmniej jeden typ, funkcję, właściwość lub alias typu na najwyższym poziomie.
Zawartość pliku powinna być skupiona na jednym temacie. Przykładem może być pojedynczy typ publiczny lub zestaw funkcji rozszerzających wykonujących tę samą operację na wielu typach odbiorników. Niepowiązane deklaracje powinny być rozdzielone na osobne pliki, a deklaracje publiczne w jednym pliku powinny być ograniczone do minimum.
Nie ma wyraźnych ograniczeń co do liczby ani kolejności zawartości pliku.
Pliki źródłowe są zwykle odczytywane od góry do dołu, co oznacza, że kolejność powinna odzwierciedlać fakt, że deklaracje znajdujące się wyżej wpływają na interpretację tych, które znajdują się niżej. Różne pliki mogą mieć różną kolejność treści. Podobnie jeden plik może zawierać 100 właściwości, inny 10 funkcji, a jeszcze inny tylko jedną klasę.
Ważne jest, aby każdy plik miał jakąś logiczną kolejność, którą jego opiekun mógłby wyjaśnić na żądanie. Na przykład nowe funkcje nie są dodawane do końca pliku, ponieważ spowodowałoby to uporządkowanie „chronologiczne według daty dodania”, które nie jest logiczne.
Kolejność elementów klasy
Kolejność elementów w klasie jest zgodna z tymi samymi regułami co deklaracje najwyższego poziomu.
Format
Aparaty ortodontyczne
Nawiasy klamrowe nie są wymagane w przypadku when gałęzi i if wyrażeń, które mają nie więcej niż 1 else gałąź i mieszczą się w jednym wierszu.
if (string.isEmpty()) return val result = if (string.isEmpty()) DEFAULT_VALUE else string when (value) { 0 -> return // … }
Nawiasy klamrowe są wymagane w przypadku wszystkich gałęzi if, for, when, do i while, nawet jeśli treść jest pusta lub zawiera tylko jedno wyrażenie.
if (string.isEmpty()) return // WRONG! if (string.isEmpty()) { return // Okay } if (string.isEmpty()) return // WRONG else doLotsOfProcessingOn(string, otherParametersHere) if (string.isEmpty()) { return // Okay } else { doLotsOfProcessingOn(string, otherParametersHere) }
Niepuste bloki
Nawiasy klamrowe są zgodne ze stylem Kernighana i Ritchiego („nawiasy egipskie”) w przypadku niepustych bloków i konstrukcji podobnych do bloków:
- Przed nawiasem otwierającym nie ma znaku podziału wiersza.
- Podział wiersza po nawiasie otwierającym.
- Przed nawiasem zamykającym znajduje się znak końca wiersza.
- Podział wiersza po nawiasie zamykającym tylko wtedy, gdy kończy on instrukcję lub treść funkcji, konstruktora lub nazwanej klasy.
Na przykład nie ma znaku końca wiersza po nawiasie klamrowym, jeśli po nim występuje znak
elselub przecinek.
return Runnable { while (condition()) { foo() } }
return object : MyClass() { override fun foo() { if (condition()) { try { something() } catch (e: ProblemException) { recover() } } else if (otherCondition()) { somethingElse() } else { lastThing() } } }
Poniżej znajdziesz kilka wyjątków dotyczących klas wyliczeniowych.
Puste bloki
Pusty blok lub konstrukcja podobna do bloku musi być w stylu K&R.
try { doSomething() } catch (e: Exception) {} // WRONG!
try { doSomething() } catch (e: Exception) { } // Okay
Wyrażenia
if/else Warunek użyty jako wyrażenie może pominąć nawiasy klamrowe tylko wtedy, gdy całe wyrażenie mieści się w jednym wierszu.
val value = if (string.isEmpty()) 0 else 1 // Okay
val value = if (string.isEmpty()) // WRONG! 0 else 1
val value = if (string.isEmpty()) { // Okay 0 } else { 1 }
Wcięcie
Za każdym razem, gdy otwierany jest nowy blok lub konstrukcja podobna do bloku, wcięcie zwiększa się o 4 spacje. Po zakończeniu bloku wcięcie wraca do poprzedniego poziomu. Poziom wcięcia dotyczy zarówno kodu, jak i komentarzy w całym bloku.
Jedno stwierdzenie w wierszu
Po każdym stwierdzeniu następuje znak podziału wiersza. Nie używaj średników.
Zawijanie wierszy
Kod może mieć maksymalnie 100 znaków. Z wyjątkiem przypadków opisanych poniżej każdy wiersz, który przekracza ten limit, musi być zawijany, jak wyjaśniono poniżej.
Wyjątki:
- Wiersze, w których nie można zachować limitu kolumn (np. długi adres URL w KDoc)
packageiimport- wiersze poleceń w komentarzu, które można skopiować i wkleić do powłoki;
Gdzie zrobić przerwę
Główna zasada zawijania wierszy brzmi: preferuj podział na wyższym poziomie składniowym. Również:
- Jeśli wiersz jest dzielony przy operatorze lub nazwie funkcji wrostkowej, podział następuje po operatorze lub nazwie funkcji wrostkowej.
- Jeśli wiersz jest dzielony przy symbolach podobnych do operatorów, podział następuje przed symbolem:
- Separator w postaci kropki (
.,?.). - Dwa dwukropki w odwołaniu do elementu (
::).
- Separator w postaci kropki (
- Nazwa metody lub konstruktora pozostaje przy otwierającym nawiasie (
(), który po niej występuje. - Przecinek (
,) pozostaje przyłączony do tokena, który go poprzedza. - Strzałka lambda (
->) pozostaje dołączona do listy argumentów, która ją poprzedza.
Funkcje
Jeśli sygnatura funkcji nie mieści się w jednym wierszu, każdą deklarację parametru umieść w osobnym wierszu. Parametry zdefiniowane w tym formacie powinny mieć pojedyncze wcięcie (+4). Nawias zamykający ()) i typ zwracany są umieszczane w osobnym wierszu bez dodatkowego wcięcia.
fun <T> Iterable<T>.joinToString( separator: CharSequence = ", ", prefix: CharSequence = "", postfix: CharSequence = "" ): String { // ... }
Funkcje wyrażeń
Jeśli funkcja zawiera tylko jedno wyrażenie, można ją przedstawić jako funkcję wyrażenia.
override fun toString(): String { return "Hey" }
override fun toString(): String = "Hey"
Właściwości
Jeśli inicjator właściwości nie mieści się w jednym wierszu, podziel go po znaku równości (=) i użyj wcięcia.
private val defaultCharset: Charset? = EncodingRegistry.getInstance().getDefaultCharsetForPropertiesFiles(file)
Właściwości deklarujące funkcję get lub set powinny być umieszczone w osobnych wierszach z normalnym wcięciem (+4). Sformatuj je zgodnie z tymi samymi regułami co funkcje.
var directory: File? = null set(value) { // … }
val defaultExtension: String get() = "kt"
Odstęp
Branża
Pojawi się jeden pusty wiersz:
- Między kolejnymi elementami klasy: właściwościami, konstruktorami, funkcjami, zagnieżdżonymi klasami itp.
- Wyjątek: pusta linia między 2 kolejnymi właściwościami (bez innego kodu między nimi) jest opcjonalna. Puste wiersze są używane w razie potrzeby do tworzenia logicznych grup właściwości i powiązania właściwości z ich właściwością bazową, jeśli taka istnieje.
- Wyjątek: puste wiersze między stałymi wyliczeniowymi są opisane poniżej.
- między instrukcjami w razie potrzeby, aby uporządkować kod w logiczne podsekcje;
- Opcjonalnie przed pierwszym wyrażeniem w funkcji, przed pierwszym elementem klasy lub po ostatnim elemencie klasy (nie jest to ani zalecane, ani odradzane).
- Zgodnie z wymaganiami innych sekcji tego dokumentu (np. sekcji Struktura).
Dozwolone jest używanie kilku kolejnych pustych wierszy, ale nie jest to zalecane ani wymagane.
Poziomo
Poza miejscami, w których jest to wymagane przez język lub inne reguły stylu, a także poza literałami, komentarzami i KDoc, pojedyncza spacja ASCII występuje tylko w tych miejscach:
- oddzielenie dowolnego słowa zastrzeżonego, np.
if,forlubcatch, od otwartego nawiasu ((), który występuje po nim w tym samym wierszu;// WRONG! for(i in 0..1) { }
// Okay for (i in 0..1) { }
- oddzielenie dowolnego słowa zastrzeżonego, np.
elselubcatch, od zamykającego nawiasu klamrowego (}), który występuje przed nim w tym wierszu;// WRONG! }else { }
// Okay } else { }
-
Przed otwierającym nawiasem klamrowym (
{).// WRONG! if (list.isEmpty()){ }
// Okay if (list.isEmpty()) { }
-
Po obu stronach dowolnego operatora binarnego.
// WRONG! val two = 1+1
Dotyczy to również tych symboli „podobnych do operatorów”:// Okay val two = 1 + 1
- strzałka w wyrażeniu lambda (
->).// WRONG! ints.map { value->value.toString() }
// Okay ints.map { value -> value.toString() }
-
dwie dwukropki (
::) w odwołaniu do elementu;// WRONG! val toString = Any :: toString
// Okay val toString = Any::toString
-
separatora w postaci kropki (
.).// WRONG it . toString()
// Okay it.toString()
-
operator zakresu (
..).// WRONG for (i in 1 .. 4) { print(i) }
// Okay for (i in 1..4) { print(i) }
- strzałka w wyrażeniu lambda (
-
Przed dwukropkiem (
:) tylko wtedy, gdy jest używany w deklaracji klasy do określania klasy bazowej lub interfejsów albo w klauzuliwheredo ograniczeń ogólnych.// WRONG! class Foo: Runnable
// Okay class Foo : Runnable
// WRONG fun <T: Comparable> max(a: T, b: T)
// Okay fun <T : Comparable<T>> max(a: T, b: T)
// WRONG fun <T> max(a: T, b: T) where T: Comparable<T>
// Okay fun <T> max(a: T, b: T) where T : Comparable<T> {}
-
Po przecinku (
,) lub dwukropku (:).// WRONG! val oneAndTwo = listOf(1,2)
// Okay val oneAndTwo = listOf(1, 2)
// WRONG! class Foo :Runnable
// Okay class Foo : Runnable
-
Po obu stronach podwójnego ukośnika (
//), który rozpoczyna komentarz na końcu wiersza. W tym przypadku można użyć kilku spacji, ale nie jest to wymagane.// WRONG! var debugging = false//disabled by default
// Okay var debugging = false // disabled by default
Ta reguła nigdy nie jest interpretowana jako wymagająca lub zabraniająca dodatkowej spacji na początku lub na końcu wiersza. Dotyczy ona tylko spacji wewnątrz wiersza.
Określone konstrukcje
Klasy wyliczeniowe
Wyliczenie bez funkcji i dokumentacji stałych może być opcjonalnie sformatowane jako jeden wiersz.
enum class Answer { YES, NO, MAYBE }
Gdy stałe w wyliczeniu są umieszczone w osobnych wierszach, nie jest wymagany między nimi pusty wiersz, z wyjątkiem sytuacji, gdy definiują one treść.
enum class Answer { YES, NO, MAYBE { override fun toString() = """¯\_(ツ)_/¯""" } }
Klasy wyliczeniowe są klasami, więc obowiązują w ich przypadku wszystkie inne reguły formatowania klas.
Adnotacje
Adnotacje dotyczące elementów lub typów są umieszczane w osobnych wierszach bezpośrednio przed adnotowanym konstruktem.
@Retention(SOURCE) @Target(FUNCTION, PROPERTY_SETTER, FIELD) annotation class Global
Adnotacje bez argumentów można umieszczać w jednym wierszu.
@JvmField @Volatile var disposable: Disposable? = null
Jeśli występuje tylko jedna adnotacja bez argumentów, można ją umieścić w tym samym wierszu co deklaracja.
@Volatile var disposable: Disposable? = null @Test fun selectAll() { // … }
Składni @[...] można używać tylko w przypadku wyraźnego miejsca docelowego i tylko do łączenia co najmniej 2 adnotacji bez argumentów w jednym wierszu.
@field:[JvmStatic Volatile] var disposable: Disposable? = null
Typy zwracanych wartości lub właściwości
Jeśli treść funkcji wyrażenia lub inicjator właściwości jest wartością skalarną lub typ zwracany można wyraźnie wywnioskować z treści, można go pominąć.
override fun toString(): String = "Hey" // becomes override fun toString() = "Hey"
private val ICON: Icon = IconLoader.getIcon("/icons/kotlin.png") // becomes private val ICON = IconLoader.getIcon("/icons/kotlin.png")
Podczas pisania biblioteki zachowaj jawną deklarację typu, jeśli jest ona częścią publicznego interfejsu API.
Nazwa
Identyfikatory zawierają tylko litery i cyfry ASCII oraz w niewielu przypadkach wymienionych poniżej znaki podkreślenia. Dlatego każda prawidłowa nazwa identyfikatora jest dopasowywana przez wyrażenie regularne \w+.
Prefiksy ani sufiksy specjalne, takie jak w przykładach name_, mName, s_name i kName, nie są używane, z wyjątkiem właściwości pomocniczych (patrz sekcja Właściwości pomocnicze).
Nazwy pakietów
Nazwy pakietów są pisane małymi literami, a kolejne słowa są po prostu łączone (bez podkreśleń).
// Okay package com.example.deepspace // WRONG! package com.example.deepSpace // WRONG! package com.example.deep_space
Nazwy typów
Nazwy klas są pisane w formacie PascalCase i zwykle są rzeczownikami lub wyrażeniami rzeczownikowymi. Na przykład Character lub ImmutableList. Nazwy interfejsów mogą być też rzeczownikami lub wyrażeniami rzeczownikowymi (np. List), ale czasami mogą być przymiotnikami lub wyrażeniami przymiotnikowymi (np. Readable).
Nazwy klas testowych zaczynają się od nazwy testowanej klasy, a kończą się znakiem Test. Na przykład HashTest lub HashIntegrationTest.
Nazwy funkcji
Nazwy funkcji są pisane w notacji camelCase i zwykle są czasownikami lub wyrażeniami czasownikowymi. Na przykład sendMessage lub stop.
W nazwach funkcji testowych można używać podkreśleń do oddzielania logicznych komponentów nazwy.
@Test fun pop_emptyStack() { // … }
Funkcje oznaczone symbolem @Composable, które zwracają wartość Unit, są zapisywane w notacji PascalCase i nazywane rzeczownikami, tak jakby były typami.
@Composable fun NameTag(name: String) { // … }
Nazwy funkcji nie powinny zawierać spacji, ponieważ nie jest to obsługiwane na wszystkich platformach (w szczególności nie jest w pełni obsługiwane na Androidzie).
// WRONG! fun `test every possible case`() {} // OK fun testEveryPossibleCase() {}
Nazwy stałych
Nazwy stałych są pisane wielkimi literami (UPPER_SNAKE_CASE), a słowa są oddzielone podkreśleniami. Ale czym dokładnie jest stała?
Stałe to właściwości val bez niestandardowej funkcji get, których zawartość jest niezmienna, a funkcje nie mają wykrywalnych efektów ubocznych. Obejmuje to typy niezmienne i niezmienne kolekcje typów niezmiennych, a także wartości skalarne i ciągi znaków, jeśli są oznaczone symbolem const. Jeśli jakikolwiek obserwowalny stan instancji może się zmienić, nie jest ona stałą. Samo założenie, że obiekt nigdy nie będzie modyfikowany, nie wystarczy.
const val NUMBER = 5 val NAMES = listOf("Alice", "Bob") val AGES = mapOf("Alice" to 35, "Bob" to 32) val COMMA_JOINED = NAMES.joinToString(", ") val EMPTY_ARRAY = arrayOf<SomeMutableType>()
Są to zwykle rzeczowniki lub wyrażenia rzeczownikowe.
Wartości stałe można definiować tylko w ramach elementu object lub jako deklarację najwyższego poziomu. Wartości, które w inny sposób spełniają wymagania dotyczące stałej, ale są zdefiniowane w class, muszą używać nazwy innej niż stała.
Stałe, które są wartościami skalarnymi, muszą używać const
modyfikatora.
Nazwy niebędące stałymi
Nazwy niebędące stałymi są zapisywane w formacie camelCase. Dotyczy to właściwości instancji, właściwości lokalnych i nazw parametrów.
val variable = "var" val nonConstScalar = "non-const" val mutableCollection: MutableSet<String> = HashSet() val mutableElements = listOf(mutableInstance) val mutableValues = mapOf("Alice" to mutableInstance, "Bob" to mutableInstance2) val logger = Logger.getLogger(MyClass::class.java.name) val nonEmptyArray = arrayOf("these", "can", "change")
Są to zwykle rzeczowniki lub wyrażenia rzeczownikowe.
Właściwości podkładu
Gdy potrzebna jest właściwość pomocnicza, jej nazwa powinna być identyczna z nazwą rzeczywistej właściwości, z tym wyjątkiem, że powinna mieć prefiks w postaci podkreślenia.
private var _table: Map<String, Int>? = null val table: Map<String, Int> get() { if (_table == null) { _table = HashMap() } return _table ?: throw AssertionError() }
Wpisz nazwy zmiennych
Każda zmienna typu ma nazwę w jednym z 2 stylów:
- Pojedyncza wielka litera, opcjonalnie z pojedynczą cyfrą (np.
E,T,X,T2) - Nazwa w formie używanej w przypadku klas, po której następuje wielka litera
T(np.RequestT,FooBarT).
Camel case
Czasami istnieje więcej niż jeden rozsądny sposób przekształcenia angielskiego wyrażenia na zapis camel case, np. w przypadku akronimów lub nietypowych konstrukcji, takich jak „IPv6” czy „iOS”. Aby zwiększyć przewidywalność, użyj tego schematu.
Zacznij od formy prozy nazwy:
- Przekonwertuj frazę na zwykły tekst ASCII i usuń apostrofy. Na przykład „algorytm Müllera” może stać się „algorytmem Muellersa”.
- Podziel ten wynik na słowa, rozdzielając je spacjami i pozostałymi znakami interpunkcyjnymi (zwykle łącznikami). Zalecane: jeśli jakieś słowo jest już powszechnie używane w formie camel case, podziel je na części składowe (np. „AdWords” na „ad words”). Pamiętaj, że słowo „iOS” nie jest w formie camel case; nie podlega żadnym konwencjom, więc ta rekomendacja nie ma zastosowania.
- Teraz zmień wszystkie litery na małe (w tym akronimy) i wykonaj jedną z tych czynności:
- Zmień pierwszą literę każdego słowa na wielką, aby uzyskać format PascalCase.
- Zmień pierwszą literę każdego słowa z wyjątkiem pierwszego na wielką, aby uzyskać format camel case.
- Na koniec połącz wszystkie słowa w jeden identyfikator.
Zwróć uwagę, że wielkość liter w oryginalnych słowach jest prawie całkowicie ignorowana.
| Forma prozatorska | Dobrze | Nieprawidłowe |
|---|---|---|
| „XML Http Request” | XmlHttpRequest |
XMLHTTPRequest |
| „nowy identyfikator klienta”, | newCustomerId |
newCustomerID |
| „wewnętrzny stoper”, | innerStopwatch |
innerStopWatch |
| „obsługuje IPv6 na iOS” | supportsIpv6OnIos |
supportsIPv6OnIOS |
| „Importer YouTube” | YouTubeImporter |
YoutubeImporter* |
(* Dopuszczalne, ale niezalecane).
Dokumentacja
Format
Podstawowe formatowanie bloków KDoc widać na tym przykładzie:
/** * Multiple lines of KDoc text are written here, * wrapped normally… */ fun method(arg: String) { // … }
…lub w tym przykładzie jednowierszowym:
/** An especially short bit of KDoc. */
Podstawowa forma jest zawsze akceptowalna. Formularz jednowierszowy można zastąpić, gdy cały blok KDoc (wraz ze znacznikami komentarzy) mieści się w jednym wierszu. Pamiętaj, że ma to zastosowanie tylko wtedy, gdy nie ma tagów blokujących, takich jak @return.
Akapity
Między akapitami i przed grupą tagów blokowych (jeśli występuje) pojawia się jeden pusty wiersz, czyli wiersz zawierający tylko wyrównaną gwiazdkę wiodącą (*).
Blokowanie tagów
Wszystkie użyte standardowe „tagi blokowe” pojawiają się w kolejności @constructor, @receiver, @param, @property, @return, @throws, @see i nigdy nie występują z pustym opisem.
Gdy tag bloku nie mieści się w jednym wierszu, wiersze kontynuacji są wcięte o 4 spacje od pozycji znaku @.
Fragment podsumowania
Każdy blok KDoc zaczyna się od krótkiego fragmentu podsumowania. Ten fragment jest bardzo ważny: to jedyna część tekstu, która pojawia się w niektórych kontekstach, np. w indeksach klas i metod.
To fragment – fraza rzeczownikowa lub czasownikowa, a nie pełne zdanie.
Nie zaczyna się od „A `Foo` is a...” ani „This method returns...” i nie musi tworzyć pełnego zdania w trybie rozkazującym, np. „Save the record.”. Fragment jest jednak pisany wielką literą i zawiera znaki interpunkcyjne tak, jakby był pełnym zdaniem.
Wykorzystanie
Dokumentacja KDoc jest dostępna co najmniej dla każdego public typu oraz każdego public lub protected elementu takiego typu, z kilkoma wyjątkami wymienionymi poniżej.
Wyjątek: funkcje niewymagające wyjaśnienia
KDoc jest opcjonalny w przypadku „prostych, oczywistych” funkcji, takich jak getFoo, i właściwości, takich jak foo, gdy naprawdę nie ma nic innego wartego uwagi poza „Zwraca foo”.
Nie należy powoływać się na ten wyjątek, aby uzasadnić pominięcie istotnych informacji, które typowy czytelnik może potrzebować. Na przykład w przypadku funkcji o nazwie getCanonicalName lub właściwości o nazwie canonicalName nie pomijaj dokumentacji (z uzasadnieniem, że zawierałaby tylko /** Returns the canonical name. */), jeśli typowy czytelnik może nie wiedzieć, co oznacza termin „nazwa kanoniczna”.
Wyjątek: zastąpienia
Dokumentacja KDoc nie zawsze jest dostępna w przypadku metody, która zastępuje metodę typu nadrzędnego.