Guida di stile Kotlin

Questo documento funge da definizione completa degli standard di codifica Android di Google per il codice sorgente nel linguaggio di programmazione Kotlin. Un file sorgente Kotlin viene descritto come in stile Google Android se e solo se rispetta le regole qui riportate.

Come altre guide di stile di programmazione, i problemi trattati riguardano non solo le questioni estetiche della formattazione, ma anche altri tipi di convenzioni o standard di codifica. Tuttavia, questo documento si concentra principalmente sulle regole rigide che seguiamo universalmente ed evita di fornire consigli che non sono chiaramente applicabili (da persone o strumenti).

Ultimo aggiornamento: 06/09/2023

File di origine

Tutti i file di origine devono essere codificati come UTF-8.

Denominazione

Se un file sorgente contiene una sola classe di primo livello, il nome file deve riflettere il nome sensibile al maiuscolo/minuscolo più l'estensione .kt. Altrimenti, se un file di origine contiene più dichiarazioni di primo livello, scegli un nome che descriva i contenuti del file, applica PascalCase (camelCase è accettabile se il nome file è plurale) e aggiungi l'estensione .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() = { /* ... */ }

Caratteri speciali

Caratteri di spazio vuoto

A parte la sequenza di terminazione della riga, il carattere di spazio orizzontale ASCII (0x20) è l'unico carattere di spaziatura che compare ovunque in un file di origine. Ciò implica che:

  • Tutti gli altri caratteri di spazio vuoto nei valori letterali stringa e carattere vengono sottoposti a escape.
  • I caratteri di tabulazione non vengono utilizzati per il rientro.

Sequenze di escape speciali

Per qualsiasi carattere con una sequenza di escape speciale (\b, \n, \r, \t, \', \", \\ e \$), viene utilizzata questa sequenza anziché l'escape Unicode corrispondente (ad es. \u000a).

Caratteri non ASCII

Per i restanti caratteri non ASCII, viene utilizzato il carattere Unicode effettivo (ad es. ) o l'escape Unicode equivalente (ad es. \u221e). La scelta dipende solo da quale rende il codice più facile da leggere e comprendere. Le sequenze di escape Unicode sono sconsigliate per i caratteri stampabili in qualsiasi posizione e sono fortemente sconsigliate al di fuori dei valori letterali stringa e dei commenti.

Esempio Discussione
val unitAbbrev = "μs" Ottima: perfettamente chiara anche senza un commento.
val unitAbbrev = "\u03bcs" // μs Scarso: non c'è motivo di utilizzare un carattere di escape con un carattere stampabile.
val unitAbbrev = "\u03bcs" Scarso: il lettore non ha idea di cosa sia.
return "\ufeff" + content Buono: utilizza i caratteri di escape per i caratteri non stampabili e aggiungi un commento, se necessario.

Strutturazione

Un file .kt comprende quanto segue, in ordine:

  • (Facoltativo) Intestazione del copyright e/o della licenza
  • Annotazioni a livello di file
  • Estratto conto del pacchetto
  • Importare estratti conto
  • Dichiarazioni di primo livello

Ogni sezione è separata da una riga vuota.

Se un'intestazione di copyright o licenza appartiene al file, deve essere posizionata immediatamente in alto in un commento su più righe.

/*
 * Copyright 2017 Google, Inc.
 *
 * ...
 */
 

Non utilizzare un commento in stile KDoc o in stile a una sola riga.

/**
 * Copyright 2017 Google, Inc.
 *
 * ...
 */
// Copyright 2017 Google, Inc.
//
// ...

Annotazioni a livello di file

Le annotazioni con la destinazione "file" use-site vengono inserite tra qualsiasi commento dell'intestazione e la dichiarazione del pacchetto.

Estratto conto del pacchetto

La dichiarazione del pacchetto non è soggetta ad alcun limite di colonne e non viene mai mandata a capo.

Importare estratti conto

Le istruzioni di importazione per classi, funzioni e proprietà sono raggruppate in un unico elenco e ordinate in formato ASCII.

Le importazioni con caratteri jolly (di qualsiasi tipo) non sono consentite.

Analogamente all'istruzione package, le istruzioni import non sono soggette a un limite di colonne e non vengono mai mandate a capo.

Dichiarazioni di primo livello

Un file .kt può dichiarare uno o più tipi, funzioni, proprietà o alias di tipo a livello principale.

I contenuti di un file devono essere incentrati su un singolo tema. Esempi di questo tipo sono un singolo tipo pubblico o un insieme di funzioni di estensione che eseguono la stessa operazione su più tipi di ricevitore. Le dichiarazioni non correlate devono essere separate in file propri e le dichiarazioni pubbliche all'interno di un singolo file devono essere ridotte al minimo.

Non viene imposta alcuna limitazione esplicita al numero o all'ordine dei contenuti di un file.

I file di origine vengono in genere letti dall'alto verso il basso, il che significa che l'ordine, in generale, dovrebbe riflettere il fatto che le dichiarazioni più in alto influiscono sulla comprensione di quelle più in basso. File diversi possono scegliere di ordinare i propri contenuti in modo diverso. Allo stesso modo, un file può contenere 100 proprietà, un altro 10 funzioni e un altro ancora una sola classe.

L'importante è che ogni file utilizzi un ordine logico, che il suo manutentore potrebbe spiegare se gli viene chiesto. Ad esempio, le nuove funzioni non vengono aggiunte abitualmente alla fine del file, in quanto ciò produrrebbe un ordinamento "cronologico per data di aggiunta", che non è un ordinamento logico.

Ordinamento dei membri del corso

L'ordine dei membri all'interno di una classe segue le stesse regole delle dichiarazioni di primo livello.

Formattazione

Apparecchi ortodontici

Le parentesi graffe non sono necessarie per i rami when e le espressioni if che non hanno più di un ramo else e che rientrano in una sola riga.

if (string.isEmpty()) return

val result =
    if (string.isEmpty()) DEFAULT_VALUE else string

when (value) {
    0 -> return
    // …
}

Le parentesi graffe sono altrimenti necessarie per qualsiasi ramo if, for, when, do, e per le istruzioni e le espressioni while, anche quando il corpo è vuoto o contiene solo una singola istruzione.

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)
}

Blocchi non vuoti

Le parentesi graffe seguono lo stile Kernighan e Ritchie ("parentesi egiziane") per blocchi non vuoti e costrutti simili a blocchi:

  • Nessun interruzione di riga prima della parentesi graffa aperta.
  • Interruzione di riga dopo la parentesi graffa di apertura.
  • Interruzione di riga prima della parentesi chiusa.
  • Interruzione di riga dopo la parentesi graffa di chiusura, solo se questa parentesi termina un'istruzione o il corpo di una funzione, un costruttore o una classe con nome. Ad esempio, non c'è un'interruzione di riga dopo la parentesi graffa se è seguita da else o da una virgola.

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()
        }
    }
}

Di seguito sono riportate alcune eccezioni per le classi enum.

Blocchi vuoti

Un blocco vuoto o una struttura simile a un blocco deve essere in stile K&R.

try {
    doSomething()
} catch (e: Exception) {} // WRONG!

try {
    doSomething()
} catch (e: Exception) {
} // Okay

Espressioni

Una condizione if/else utilizzata come espressione può omettere le parentesi graffe solo se l'intera espressione rientra in una riga.

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
}

Rientro

Ogni volta che viene aperto un nuovo blocco o una nuova struttura simile a un blocco, il rientro aumenta di quattro spazi. Al termine del blocco, il rientro torna al livello precedente. Il livello di rientro si applica sia al codice che ai commenti in tutto il blocco.

Un'istruzione per riga

Ogni affermazione è seguita da un'interruzione di riga. I punti e virgola non vengono utilizzati.

Ritorno a capo automatico

Il codice ha un limite di 100 caratteri per colonna. Ad eccezione di quanto indicato di seguito, qualsiasi riga che superi questo limite deve essere mandata a capo, come spiegato di seguito.

Eccezioni:

  • Righe in cui non è possibile rispettare il limite di colonne (ad esempio, un URL lungo in KDoc)
  • package e import
  • Righe di comando in un commento che possono essere tagliate e incollate in una shell

Dove fare una pausa

La direttiva principale del ritorno a capo è: preferisci interrompere a un livello sintattico superiore. Inoltre:

  • Quando una riga viene interrotta in corrispondenza di un operatore o del nome di una funzione infissa, l'interruzione avviene dopo l'operatore o il nome della funzione infissa.
  • Quando una riga viene interrotta in corrispondenza dei seguenti simboli "simili a operatori", l'interruzione si verifica prima del simbolo:
    • Il separatore punto (., ?.).
    • I due punti di un riferimento al membro (::).
  • Il nome di un metodo o di un costruttore rimane collegato alla parentesi aperta (() che lo segue.
  • Una virgola (,) rimane collegata al token che la precede.
  • Una freccia lambda (->) rimane collegata all'elenco di argomenti che la precede.

Funzioni

Quando la firma di una funzione non rientra in una singola riga, dividi ogni dichiarazione di parametro su una riga separata. I parametri definiti in questo formato devono utilizzare un solo rientro (+4). La parentesi chiusa ()) e il tipo restituito si trovano su una riga separata senza rientro aggiuntivo.

fun <T> Iterable<T>.joinToString(
    separator: CharSequence = ", ",
    prefix: CharSequence = "",
    postfix: CharSequence = ""
): String {
    // ...
}

Funzioni di espressione

Quando una funzione contiene una sola espressione, può essere rappresentata come una funzione di espressione.

override fun toString(): String {
    return "Hey"
}

override fun toString(): String = "Hey"

Proprietà

Quando un inizializzatore di proprietà non rientra in una singola riga, vai a capo dopo il segno di uguale (=) e utilizza un rientro.

private val defaultCharset: Charset? =
    EncodingRegistry.getInstance().getDefaultCharsetForPropertiesFiles(file)

Le proprietà che dichiarano una funzione get e/o set devono essere inserite su righe separate con un rientro normale (+4). Formattali utilizzando le stesse regole delle funzioni.

var directory: File? = null
    set(value) {
        // …
    }
Le proprietà di sola lettura possono utilizzare una sintassi più breve che rientra in una sola riga.

val defaultExtension: String get() = "kt"

Spazio vuoto

Verticale

Viene visualizzata una singola riga vuota:

  • Tra membri consecutivi di una classe: proprietà, costruttori, funzioni, classi nidificate e così via.
    • Eccezione: una riga vuota tra due proprietà consecutive (senza altro codice tra loro) è facoltativa. Queste righe vuote vengono utilizzate in base alle necessità per creare raggruppamenti logici di proprietà e associare le proprietà alla proprietà di backup, se presente.
    • Eccezione:le righe vuote tra le costanti enum sono trattate di seguito.
  • Tra le istruzioni, se necessario, per organizzare il codice in sottosezioni logiche.
  • Facoltativamente prima della prima istruzione di una funzione, prima del primo membro di una classe o dopo l'ultimo membro di una classe (né incoraggiato né sconsigliato).
  • Come richiesto da altre sezioni di questo documento (ad esempio la sezione Struttura).

Sono consentite più righe vuote consecutive, ma non sono incoraggiate o mai richieste.

Orizzontale

Oltre a quanto richiesto dalla lingua o da altre regole di stile, e a parte i valori letterali, i commenti e KDoc, uno spazio ASCII singolo viene visualizzato solo nei seguenti punti:

  • Separando qualsiasi parola riservata, ad esempio if, for o catch da una parentesi aperta (() che la segue sulla stessa riga.
    // WRONG!
    for(i in 0..1) {
    }
    // Okay
    for (i in 0..1) {
    }
  • Separando qualsiasi parola riservata, ad esempio else o catch, da una parentesi graffa chiusa (}) che la precede sulla stessa riga.
    // WRONG!
    }else {
    }
    // Okay
    } else {
    }
  • Prima di qualsiasi parentesi graffa aperta ({).
    // WRONG!
    if (list.isEmpty()){
    }
    // Okay
    if (list.isEmpty()) {
    }
  • Su entrambi i lati di qualsiasi operatore binario.
    // WRONG!
    val two = 1+1
    // Okay
    val two = 1 + 1
    Ciò vale anche per i seguenti simboli "simili a operatori":
    • la freccia in un'espressione lambda (->).
      // WRONG!
      ints.map { value->value.toString() }
      // Okay
      ints.map { value -> value.toString() }
    Ma non:
    • i due punti (::) di un riferimento a un membro.
      // WRONG!
      val toString = Any :: toString
      // Okay
      val toString = Any::toString
    • il separatore punto (.).
      // WRONG
      it . toString()
      // Okay
      it.toString()
    • l'operatore di intervallo (..).
      // WRONG
      for (i in 1 .. 4) {
        print(i)
      }
      // Okay
      for (i in 1..4) {
        print(i)
      }
  • Prima dei due punti (:) solo se utilizzati in una dichiarazione di classe per specificare una classe base o interfacce oppure se utilizzati in una clausola where per vincoli generici.
    // 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> {}
  • Dopo una virgola (,) o due punti (:).
    // WRONG!
    val oneAndTwo = listOf(1,2)
    // Okay
    val oneAndTwo = listOf(1, 2)
    // WRONG!
    class Foo :Runnable
    // Okay
    class Foo : Runnable
  • Su entrambi i lati della doppia barra (//) che inizia un commento di fine riga. Qui sono consentiti più spazi, ma non sono obbligatori.
    // WRONG!
    var debugging = false//disabled by default
    // Okay
    var debugging = false // disabled by default

Questa regola non viene mai interpretata come se richiedesse o vietasse spazi aggiuntivi all'inizio o alla fine di una riga; riguarda solo lo spazio interno.

Costrutti specifici

Classi enum

Un'enumerazione senza funzioni e senza documentazione sulle costanti può essere formattata facoltativamente come una singola riga.

enum class Answer { YES, NO, MAYBE }

Quando le costanti di un'enumerazione vengono inserite su righe separate, non è necessaria una riga vuota tra loro, tranne nel caso in cui definiscano un corpo.

enum class Answer {
    YES,
    NO,

    MAYBE {
        override fun toString() = """¯\_(ツ)_/¯"""
    }
}

Poiché le classi enum sono classi, si applicano tutte le altre regole per la formattazione delle classi.

Annotazioni

Le annotazioni di membri o tipi vengono inserite su righe separate immediatamente prima del costrutto annotato.

@Retention(SOURCE)
@Target(FUNCTION, PROPERTY_SETTER, FIELD)
annotation class Global

Le annotazioni senza argomenti possono essere inserite su una sola riga.

@JvmField @Volatile
var disposable: Disposable? = null

Quando è presente una sola annotazione senza argomenti, può essere inserita sulla stessa riga della dichiarazione.

@Volatile var disposable: Disposable? = null

@Test fun selectAll() {
    // …
}

La sintassi @[...] può essere utilizzata solo con un target di utilizzo del sito esplicito e solo per combinare due o più annotazioni senza argomenti su una singola riga.

@field:[JvmStatic Volatile]
var disposable: Disposable? = null

Tipi di proprietà/restituzione implicita

Se il corpo di una funzione di espressione o un inizializzatore di proprietà è un valore scalare o il tipo restituito può essere dedotto chiaramente dal corpo, può essere omesso.

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")

Quando scrivi una libreria, mantieni la dichiarazione di tipo esplicita quando fa parte dell'API pubblica.

Denominazione

Gli identificatori utilizzano solo lettere e cifre ASCII e, in un numero ridotto di casi indicati di seguito, trattini bassi. Pertanto, ogni nome di identificatore valido corrisponde all'espressione regolare \w+.

I prefissi o i suffissi speciali, come quelli mostrati negli esempi name_, mName, s_name e kName, non vengono utilizzati, tranne nel caso di proprietà di backup (vedi Proprietà di backup).

Nomi pacchetto

I nomi dei pacchetti sono tutti in minuscolo e le parole consecutive vengono semplicemente concatenate (senza trattini bassi).

// Okay
package com.example.deepspace
// WRONG!
package com.example.deepSpace
// WRONG!
package com.example.deep_space

Nomi dei tipi

I nomi delle classi sono scritti in PascalCase e in genere sono nomi o sintagmi nominali. Ad esempio, Character o ImmutableList. I nomi delle interfacce possono anche essere sostantivi o sintagmi nominali (ad esempio, List), ma a volte possono essere aggettivi o sintagmi aggettivali (ad esempio Readable).

Le classi di test iniziano con il nome della classe che stanno testando e terminano con Test. Ad esempio, HashTest o HashIntegrationTest.

Nomi delle funzioni

I nomi delle funzioni sono scritti in camelCase e sono in genere verbi o frasi verbali. Ad esempio, sendMessage o stop.

I trattini bassi sono consentiti nei nomi delle funzioni di test per separare i componenti logici del nome.

@Test fun pop_emptyStack() {
    // …
}

Le funzioni annotate con @Composable che restituiscono Unit sono in formato PascalCase e denominate come sostantivi, come se fossero tipi.

@Composable
fun NameTag(name: String) {
    // …
}

I nomi delle funzioni non devono contenere spazi perché questa funzionalità non è supportata su tutte le piattaforme (in particolare, non è completamente supportata su Android).

// WRONG!
fun `test every possible case`() {}
// OK
fun testEveryPossibleCase() {}

Nomi delle costanti

I nomi delle costanti utilizzano UPPER_SNAKE_CASE: tutte le lettere maiuscole, con le parole separate da trattini bassi. Ma che cos'è esattamente una costante?

Le costanti sono proprietà val senza funzione get personalizzata, il cui contenuto è profondamente immutabile e le cui funzioni non hanno effetti collaterali rilevabili. Ciò include tipi immutabili e raccolte immutabili di tipi immutabili, nonché scalari e stringhe se contrassegnati come const. Se uno qualsiasi degli stati osservabili di un'istanza può cambiare, non è una costante. La semplice intenzione di non modificare mai l'oggetto non è sufficiente.

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>()

Questi nomi sono in genere sostantivi o sintagmi nominali.

I valori costanti possono essere definiti solo all'interno di un object o come dichiarazione di primo livello. I valori che altrimenti soddisfano il requisito di una costante, ma definiti all'interno di un class, devono utilizzare un nome non costante.

Le costanti che sono valori scalari devono utilizzare il const modificatore.

Nomi non costanti

I nomi non costanti sono scritti in camelCase. Questi si applicano a proprietà dell'istanza, proprietà locali e nomi dei parametri.

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")

Questi nomi sono in genere sostantivi o sintagmi nominali.

Proprietà di supporto

Quando è necessaria una proprietà di backup, il suo nome deve corrispondere esattamente a quello della proprietà reale, tranne che per il prefisso con un trattino basso.

private var _table: Map<String, Int>? = null

val table: Map<String, Int>
    get() {
        if (_table == null) {
            _table = HashMap()
        }
        return _table ?: throw AssertionError()
    }

Digitare i nomi delle variabili

Ogni variabile di tipo ha un nome in uno dei due stili:

  • Una singola lettera maiuscola, seguita facoltativamente da un singolo numero (ad esempio E, T, X, T2)
  • Un nome nel formato utilizzato per le classi, seguito dalla lettera maiuscola T (ad esempio RequestT, FooBarT)

Camel case

A volte esiste più di un modo ragionevole per convertire una frase inglese in camel case, ad esempio quando sono presenti acronimi o costrutti insoliti come "IPv6" o "iOS". Per migliorare la prevedibilità, utilizza il seguente schema.

A partire dalla forma in prosa del nome:

  1. Converti la frase in ASCII semplice e rimuovi gli apostrofi. Ad esempio, "Algoritmo di Müller" potrebbe diventare "Algoritmo di Muellers".
  2. Dividi questo risultato in parole, separando gli spazi e la punteggiatura rimanente (in genere i trattini). Consigliato:se una parola ha già un aspetto camel case convenzionale nell'uso comune, dividila nelle sue parti costituenti (ad es. "AdWords" diventa "ad words"). Tieni presente che una parola come "iOS" non è in camel case di per sé; non rispetta alcuna convenzione, quindi questo consiglio non si applica.
  3. Ora converti tutto in minuscolo (incluse le abbreviazioni), poi esegui una delle seguenti operazioni:
    • Metti in maiuscolo il primo carattere di ogni parola per ottenere il formato Pascal.
    • Metti in maiuscolo il primo carattere di ogni parola, tranne la prima, per ottenere il camel case.
  4. Infine, unisci tutte le parole in un unico identificatore.

Tieni presente che la distinzione tra maiuscole e minuscole delle parole originali viene quasi completamente ignorata.

Prose form Corretto Risposta sbagliata
"XML Http Request" XmlHttpRequest XMLHTTPRequest
"new customer ID" newCustomerId newCustomerID
"cronometro interno" innerStopwatch innerStopWatch
"supporta IPv6 su iOS" supportsIpv6OnIos supportsIPv6OnIOS
"YouTube importer" YouTubeImporter YoutubeImporter*

(* Accettabile, ma non consigliato.)

Documentazione

Formattazione

La formattazione di base dei blocchi KDoc è illustrata in questo esempio:

/**
 * Multiple lines of KDoc text are written here,
 * wrapped normally…
 */
fun method(arg: String) {
    // …
}

… o in questo esempio su una sola riga:

/** An especially short bit of KDoc. */

Il modulo base è sempre accettabile. Il modulo a una sola riga può essere sostituito quando l'intero blocco KDoc (inclusi i marcatori di commento) può essere contenuto in una sola riga. Tieni presente che questa opzione si applica solo quando non sono presenti tag di blocco come @return.

Paragrafi

Tra i paragrafi e prima del gruppo di tag di blocco, se presenti, viene visualizzata una riga vuota, ovvero una riga contenente solo l'asterisco iniziale allineato (*).

Tag di blocco

I "tag di blocco" standard utilizzati vengono visualizzati nell'ordine @constructor, @receiver, @param, @property, @return, @throws, @see e non vengono mai visualizzati con una descrizione vuota. Quando un tag di blocco non rientra in una singola riga, le righe di continuazione sono rientrate di 4 spazi rispetto alla posizione di @.

Frammento di riepilogo

Ogni blocco KDoc inizia con un breve frammento di riepilogo. Questo frammento è molto importante: è l'unica parte del testo che viene visualizzata in determinati contesti, come gli indici di classi e metodi.

Si tratta di un frammento, ovvero di una frase nominale o verbale, non di una frase completa. Non inizia con "A `Foo` is a...", o "This method returns...", né deve formare una frase imperativa completa come "Save the record.". Tuttavia, il frammento è scritto in maiuscolo e punteggiato come se fosse una frase completa.

Utilizzo

Come minimo, KDoc è presente per ogni tipo di public e per ogni membro public o protected di questo tipo, con alcune eccezioni indicate di seguito.

Eccezione: funzioni autoesplicative

KDoc è facoltativo per le funzioni "semplici e ovvie" come getFoo e le proprietà come foo, nei casi in cui non c'è davvero nient'altro di utile da dire se non "Restituisce foo".

Non è opportuno citare questa eccezione per giustificare l'omissione di informazioni pertinenti che un lettore tipo potrebbe aver bisogno di conoscere. Ad esempio, per una funzione denominata getCanonicalName o una proprietà denominata canonicalName, non omettere la documentazione (con la motivazione che direbbe solo /** Returns the canonical name. */) se un lettore tipico potrebbe non avere idea di cosa significhi il termine "nome canonico".

Eccezione: override

KDoc non è sempre presente in un metodo che esegue l'override di un metodo supertipo.