Kotlin-Styleguide

Dieses Dokument dient als vollständige Definition der Android-Programmierstandards von Google für Quellcode in der Programmiersprache Kotlin. Eine Kotlin-Quelldatei wird nur dann dem Google Android-Stil zugeordnet, wenn sie den hier genannten Regeln entspricht.

Wie bei anderen Programmierstilen werden auch hier nicht nur die Ästhetik der Formatierung behandelt, sondern auch andere Arten von Konventionen oder Codierungsstandards. Dieses Dokument konzentriert sich jedoch in erster Linie auf die strengen Regeln, die wir allgemein befolgen, und vermeidet Ratschläge, die nicht eindeutig durchsetzbar sind (ob durch Menschen oder Hilfsmittel).

Letzte Aktualisierung: 06.09.2023

Quelldateien

Alle Quelldateien müssen UTF-8-codiert sein.

Benennung

Wenn eine Quelldatei nur eine einzige Klasse der obersten Ebene enthält, sollte der Dateiname den Namen unter Berücksichtigung der Groß- und Kleinschreibung sowie die Erweiterung .kt widerspiegeln. Wenn eine Quelldatei mehrere Deklarationen auf oberster Ebene enthält, wählen Sie einen Namen aus, der den Inhalt der Datei beschreibt, wenden Sie „PascalCase“ an (camelCase ist zulässig, wenn der Dateiname Plural ist) und hängen Sie die Erweiterung .kt an.

// MyClass.kt
class MyClass { }
// Bar.kt
class Bar { }
fun Runnable.toBar(): Bar = // …
// Map.kt
fun <T, O> Set<T>.map(func: (T) -> O): List<O> = // …
fun <T, O> List<T>.map(func: (T) -> O): List<O> = // …
// extensions.kt
fun MyClass.process() = // …
fun MyResult.print() = // …

Sonderzeichen

Leerzeichen

Abgesehen von der Zeilenabschlusssequenz ist das Horizontale Leerzeichen ASCII-Zeichen (0 x 20) das einzige Leerzeichen, das an einer beliebigen Stelle in einer Quelldatei angezeigt wird. Dies impliziert:

  • Alle anderen Leerzeichen in String- und Zeichenliteralen werden maskiert.
  • Tabulatorzeichen werden nicht für den Einzug verwendet.

Spezielle Escape-Sequenzen

Für jedes Zeichen mit einer speziellen Escape-Sequenz (\b, \n, \r, \t, \', \", \\ und \$) wird diese Sequenz anstelle der entsprechenden Unicode-Sequenz (z.B. \u000a) Esc-Taste.

Nicht-ASCII-Zeichen

Für die restlichen Nicht-ASCII-Zeichen wird entweder das tatsächliche Unicode-Zeichen (z.B. ) oder dem entsprechenden Unicode-Escape-Zeichen (z.B. \u221e) verwendet wird. Die Wahl hängt nur davon ab, was den Code leichter zu lesen und zu verstehen macht. Von Unicode-Escape-Zeichen wird bei druckbaren Zeichen an jeder Stelle abgeraten. Außerdem wird dringend davon abgeraten, außerhalb von Stringliteralen und Kommentaren zu arbeiten.

Beispiel Diskussion
val unitAbbrev = "μs" Ideal: Bilder sind auch ohne Kommentar vollkommen verständlich.
val unitAbbrev = "\u03bcs" // μs Schlecht: Es gibt keinen Grund, eine ausdruckbare Figur zu verwenden.
val unitAbbrev = "\u03bcs" Schlecht: Der Leser weiß nicht, was das ist.
return "\ufeff" + content Gut: Escapezeichen für nicht druckbare Zeichen verwenden und gegebenenfalls Kommentare hinzufügen

Struktur

Eine .kt-Datei enthält Folgendes (in dieser Reihenfolge):

  • Überschrift für Urheberrecht und/oder Lizenz (optional)
  • Anmerkungen auf Dateiebene
  • Paketabrechnung
  • Importanweisungen
  • Deklarationen der obersten Ebene

Die einzelnen Abschnitte werden durch genau eine Leerzeile voneinander getrennt.

Wenn ein Urheberrechts- oder Lizenzheader in die Datei gehört, sollte er in einem mehrzeiligen Kommentar ganz oben platziert werden.

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

Verwenden Sie keinen KDoc-Stil oder einen einzeiligen Kommentar.

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

Anmerkungen auf Dateiebene

Annotationen mit dem use-site-Ziel „file“ werden zwischen jedem Headerkommentar und der Paketdeklaration platziert.

Paketabrechnung

Die Paketanweisung unterliegt keinem Spaltenlimit und ist niemals mit Zeilenumbruch versehen.

Importanweisungen

Importanweisungen für Klassen, Funktionen und Eigenschaften werden in einer einzigen Liste und ASCII-Sortierung zusammengefasst.

Importe mit Platzhaltern (egal welchen Typs) sind nicht zulässig.

Ähnlich wie die Paketanweisung unterliegen Importanweisungen keinem Spaltenlimit und sie werden niemals in einen Zeilenumbruch gefasst.

Deklarationen der obersten Ebene

In einer .kt-Datei können ein oder mehrere Typen, Funktionen, Attribute oder Typaliasse auf oberster Ebene deklariert werden.

Der Inhalt einer Datei sollte sich auf ein einzelnes Thema beziehen. Beispiele dafür sind ein einzelner öffentlicher Typ oder eine Reihe von Erweiterungsfunktionen, die denselben Vorgang für mehrere Empfängertypen ausführen. Nicht zusammenhängende Deklarationen sollten in separate Dateien getrennt und öffentliche Deklarationen in einer einzigen Datei minimiert werden.

Die Anzahl oder Reihenfolge der Inhalte einer Datei wird nicht explizit eingeschränkt.

Quelldateien werden in der Regel von oben nach unten gelesen, sodass im Allgemeinen die Reihenfolge, die weiter oben steht, Aufschluss darüber geben sollte, welche Deklarationen weiter unten stehen. Die Inhalte der Dateien werden möglicherweise unterschiedlich angeordnet. Ebenso kann eine Datei 100 Attribute, weitere 10 Funktionen und noch eine einzelne Klasse enthalten.

Wichtig ist, dass jede Datei eine eine logische Reihenfolge verwendet, die der Verwalter auf Anfrage erklären könnte. Neue Funktionen werden beispielsweise nicht nur gewohnheitsmäßig am Ende der Datei hinzugefügt, da dies eine chronologische Sortierung nach dem hinzugefügten Datum ergeben würde, was keine logische Reihenfolge ist.

Reihenfolge der Kursmitglieder

Die Reihenfolge der Mitglieder innerhalb einer Klasse folgt den gleichen Regeln wie die Deklarierung der obersten Ebene.

Formatierung

Zahnspangen

Für when-Zweige und if-Ausdrücke, die nicht mehr als einen else-Zweig haben und in eine einzelne Zeile passen, sind keine Klammern erforderlich.

if (string.isEmpty()) return

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

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

Ansonsten sind für alle if-, for-, when-Zweig-, do- und while-Anweisungen und -Ausdrücke geschweifte Klammern erforderlich, auch wenn der Text leer ist oder nur eine einzelne Anweisung enthält.

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

Nicht leere Blöcke

Klammern folgen dem Kernighan- und Ritchie-Stil („ägyptische Klammern“) für nicht leere Blöcke und blockähnliche Konstrukte:

  • Kein Zeilenumbruch vor der öffnenden geschweiften Klammer.
  • Zeilenumbruch nach der öffnenden geschweiften Klammer.
  • Zeilenumbruch vor der schließenden Klammer.
  • Zeilenumbruch nach der schließenden Klammer, nur wenn diese Klammer eine Anweisung oder den Hauptteil einer Funktion, eines Konstruktors oder einer named-Klasse beendet. Beispielsweise folgt nach der geschweiften Klammer kein Zeilenumbruch, wenn else oder ein Komma folgt.
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()
        }
    }
}

Einige Ausnahmen für Enum-Klassen sind unten aufgeführt.

Leere Blöcke

Ein leerer Block oder ein blockähnliches Konstrukt muss im K&R-Stil vorliegen.

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

Ausdrücke

Eine if/else-Bedingung, die als Ausdruck verwendet wird, darf nur dann geschweifte Klammern auslassen, wenn der gesamte Ausdruck in eine Zeile passt.

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
}

Einzug

Jedes Mal, wenn ein neuer Block oder ein neues blockähnliches Konstrukt geöffnet wird, vergrößert sich der Einzug um vier Leerzeichen. Wenn der Block endet, kehrt der Einzug zur vorherigen Einrückungsebene zurück. Die Einrückungsebene gilt sowohl für Code als auch für Kommentare im Block.

Eine Anweisung pro Zeile

Auf jede Anweisung folgt ein Zeilenumbruch. Semikolons werden nicht verwendet.

Zeilenumbruch

Der Code hat ein Spaltenlimit von 100 Zeichen. Abgesehen von den unten aufgeführten Ausnahmen müssen Zeilen, die dieses Limit überschreiten, wie unten erläutert einen Zeilenumbruch beinhalten.

Ausnahmen:

  • Zeilen, in denen die Spaltenbeschränkung nicht eingehalten werden kann (z. B. eine lange URL in KDoc)
  • package- und import-Anweisungen
  • Befehlszeilen in einem Kommentar, die per Ausschneiden und Einfügen in eine Shell eingefügt werden können

Wo soll ich brechen?

Die wichtigste Anweisung beim Zeilenumbruch lautet: Brechen Sie den Zeilenumbruch lieber auf einer höheren syntaktischen Ebene. Weitere Hinweise:

  • Wenn eine Zeile bei einem Operator oder einer Infix-Funktionsnamen unterbrochen wird, kommt der Unterbrechung nach dem Namen des Operators oder der Infix-Funktion.
  • Wird eine Linie an folgenden operatorähnlichen Symbolen unterbrochen, wird der Umbruch vor dem Symbol eingefügt:
    • Das Punkttrennzeichen (., ?.).
    • Die beiden Doppelpunkte eines Mitgliedsverweises (::).
  • Ein Methoden- oder Konstruktorname bleibt an der darauffolgenden öffnenden Klammer (() angehängt.
  • Ein Komma (,) bleibt an das vorangehende Token angehängt.
  • Ein Lambda-Pfeil (->) bleibt an die vorausgegangene Argumentliste angehängt.

Funktionen

Wenn eine Funktionssignatur nicht in eine einzelne Zeile passt, trennen Sie jede Parameterdeklaration in eine eigene Zeile. Bei in diesem Format definierten Parametern sollte nur ein Einzug (+4) verwendet werden. Die schließende Klammer ()) und der Rückgabetyp werden in einer eigenen Zeile ohne zusätzlichen Einzug platziert.

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

Wenn eine Funktion nur einen einzigen Ausdruck enthält, kann sie als Ausdrucksfunktion dargestellt werden.

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

Properties

Wenn der Parameter der Eigenschaftsinitialisierung nicht in eine einzelne Zeile passt, brechen Sie den Zeilenumbruch nach dem Gleichheitszeichen (=) ein und verwenden Sie einen Einzug.

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

Attribute, die eine get- und/oder set-Funktion deklarieren, sollten jeweils in einer eigenen Zeile mit einem normalen Einzug (+4) platziert werden. Formatieren Sie sie nach den gleichen Regeln wie für Funktionen.

var directory: File? = null
    set(value) {
        // …
    }
Bei schreibgeschützten Properties kann eine kürzere Syntax verwendet werden, die in eine einzelne Zeile passt.
val defaultExtension: String get() = "kt"

Leerraum

Vertikal

Eine einzelne Leerzeile wird angezeigt:

  • Zwischen aufeinanderfolgenden Mitgliedern einer Klasse: Attribute, Konstruktoren, Funktionen, verschachtelte Klassen usw.
    • Ausnahme: Eine leere Zeile zwischen zwei aufeinanderfolgenden Attributen (ohne weiteren Code) ist optional. Solche Leerzeilen werden nach Bedarf verwendet, um logische Gruppierungen von Properties zu erstellen und Properties mit ihren unterstützenden Properties zu verknüpfen, sofern vorhanden.
    • Ausnahme: Leere Zeilen zwischen enum-Konstanten werden unten beschrieben.
  • Zwischen Anweisungen, nach Bedarf, um den Code in logische Unterabschnitte zu organisieren.
  • Optional vor der ersten Anweisung in einer Funktion, vor dem ersten Mitglied einer Klasse oder nach dem letzten Element einer Klasse (weder empfohlen noch nicht empfohlen).
  • Wenn dies in anderen Abschnitten dieses Dokuments erforderlich ist, z. B. im Abschnitt Struktur.

Mehrere aufeinanderfolgende Leerzeilen sind zulässig, werden aber nicht empfohlen oder sind überhaupt nicht erforderlich.

Horizontal

Neben den von der Sprache oder anderen Stilregeln geforderten Vorgaben und abgesehen von Literalen, Kommentaren und KDoc wird ein einzelnes ASCII-Leerzeichen auch nur an folgenden Stellen angezeigt:

  • Trennen Sie alle reservierten Wörter wie if, for oder catch durch eine offene Klammer ((), die in dieser Zeile darauf folgt.
    // WRONG!
    for(i in 0..1) {
    }
    
    // Okay
    for (i in 0..1) {
    }
    
  • Trennung eines reservierten Wortes, z. B. else oder catch, durch eine schließende geschweifte Klammer (}), die in dieser Zeile vorangestellt ist.
    // WRONG!
    }else {
    }
    
    // Okay
    } else {
    }
    
  • Vor einer offenen geschweiften Klammer ({).
    // WRONG!
    if (list.isEmpty()){
    }
    
    // Okay
    if (list.isEmpty()) {
    }
    
  • Auf beiden Seiten jedes binären Operators.
    // WRONG!
    val two = 1+1
    
    // Okay
    val two = 1 + 1
    
    Das gilt auch für die folgenden Symbole, die einem Operator ähneln:
    • Pfeil in einem Lambda-Ausdruck (->).
      // WRONG!
      ints.map { value->value.toString() }
      
      // Okay
      ints.map { value -> value.toString() }
      
    Aber nicht:
    • die beiden Doppelpunkte (::) eines Mitgliedsverweises.
      // WRONG!
      val toString = Any :: toString
      
      // Okay
      val toString = Any::toString
      
    • das Punkttrennzeichen (.).
      // WRONG
      it . toString()
      
      // Okay
      it.toString()
      
    • den Bereichsoperator (..)
      // WRONG
      for (i in 1 .. 4) {
        print(i)
      }
      
      // Okay
      for (i in 1..4) {
        print(i)
      }
      
  • Vor einem Doppelpunkt (:), wenn er in einer Klassendeklaration zum Angeben einer oder mehrerer Basisklasse(s) oder in einer where-Klausel für allgemeine Einschränkungen verwendet wird.
    // WRONG!
    class Foo: Runnable
    
    // Okay
    class Foo : Runnable
    
    // WRONG
    fun <T: Comparable> max(a: T, b: T)
    
    // Okay
    fun <T : Comparable> 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>
    
  • Nach einem Komma (,) oder Doppelpunkt (:).
    // WRONG!
    val oneAndTwo = listOf(1,2)
    
    // Okay
    val oneAndTwo = listOf(1, 2)
    
    // WRONG!
    class Foo :Runnable
    
    // Okay
    class Foo : Runnable
    
  • Auf beiden Seiten des doppelten Schrägstrichs (//), mit dem ein Kommentar am Zeilenende beginnt. Hier sind mehrere Leerzeichen zulässig, aber nicht erforderlich.
    // WRONG!
    var debugging = false//disabled by default
    
    // Okay
    var debugging = false // disabled by default
    

Diese Regel wird nie so ausgelegt, dass zusätzliche Leerzeichen am Anfang oder Ende einer Zeile erforderlich oder verboten sind. Sie bezieht sich nur auf den Innenraum.

Spezifische Konstrukte

Enum-Klassen

Ein Enum ohne Funktionen und ohne Dokumentation zu seinen Konstanten kann optional als eine Zeile formatiert werden.

enum class Answer { YES, NO, MAYBE }

Wenn die Konstanten in einer Enum in separaten Zeilen stehen, ist zwischen ihnen keine Leerzeile erforderlich, es sei denn, sie definieren einen Textkörper.

enum class Answer {
    YES,
    NO,

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

Da es sich bei enum-Klassen um Klassen handelt, gelten alle anderen Regeln für Formatierungsklassen.

Anmerkungen

Mitglieder- oder Typanmerkungen werden in separaten Zeilen direkt vor dem annotierten Konstrukt platziert.

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

Anmerkungen ohne Argumente können in einer einzelnen Zeile eingefügt werden.

@JvmField @Volatile
var disposable: Disposable? = null

Wenn nur eine Annotation ohne Argumente vorhanden ist, kann sie in dieselbe Zeile wie die Deklaration eingefügt werden.

@Volatile var disposable: Disposable? = null

@Test fun selectAll() {
    // …
}

Die @[...]-Syntax darf nur mit einem expliziten Ziel der Nutzungswebsite verwendet werden und nur zum Kombinieren von zwei oder mehr Anmerkungen ohne Argumente in einer einzigen Zeile.

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

Implizite Rückgabe-/Eigenschaftstypen

Wenn ein Ausdrucksfunktionstext oder ein Eigenschaftsinitialisierer ein skalarer Wert ist oder der Rückgabetyp klar aus dem Text abgeleitet werden kann, kann er weggelassen werden.

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

Behalten Sie beim Schreiben einer Bibliothek die explizite Typdeklaration bei, wenn sie Teil der öffentlichen API ist.

Benennung

Kennungen verwenden nur ASCII-Buchstaben und -Ziffern und, in einigen wenigen unten genannten Fällen, Unterstriche. Somit entspricht jeder gültige Kennzeichnungsname dem regulären Ausdruck \w+.

Spezielle Präfixe oder Suffixe wie in den Beispielen name_, mName, s_name und kName werden nur im Fall von unterstützenden Attributen verwendet (siehe Sicherungsattribute).

Paketnamen

Paketnamen werden alle in Kleinbuchstaben geschrieben und aufeinander folgende Wörter einfach verkettet (keine Unterstriche).

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

Typnamen

Klassennamen werden im PascalCase geschrieben und sind in der Regel Substantive oder Nominalsätze. Beispiel: Character oder ImmutableList. Benutzeroberflächennamen können auch Substantive oder Nominalsätze sein (z. B. List), manchmal jedoch auch Adjektive oder Adjektive (z. B. Readable).

Die Namen von Testklassen beginnen mit dem Namen der Klasse, die sie testen, und enden mit Test. Beispiel: HashTest oder HashIntegrationTest.

Funktionsnamen

Funktionsnamen werden in CamelCase geschrieben und sind in der Regel Verben oder Verbformulierungen. Beispiel: sendMessage oder stop.

Unterstriche sind in Testfunktionsnamen zulässig, um die logischen Komponenten des Namens zu trennen.

@Test fun pop_emptyStack() {
    // …
}

Mit @Composable annotierte Funktionen, die Unit zurückgeben, sind PascalCased und werden wie Substantive benannt.

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

Funktionsnamen sollten keine Leerzeichen enthalten, da dies nicht auf jeder Plattform unterstützt wird. Insbesondere ist dies in Android nicht vollständig möglich.

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

Konstantennamen

Für Konstantennamen wird UPPER_SNAKE_CASE verwendet: nur Großbuchstaben, wobei Wörter durch Unterstriche getrennt sind. Aber was genau ist eine Konstante?

Konstanten sind val-Attribute ohne benutzerdefinierte get-Funktion, deren Inhalte völlig unveränderlich sind und deren Funktionen keine erkennbaren Nebeneffekte haben. Dazu gehören unveränderliche Typen und unveränderliche Sammlungen unveränderlicher Typen sowie Skalare und Strings, wenn sie mit const gekennzeichnet sind. Wenn sich der beobachtbare Status einer Instanz ändern kann, ist er keine Konstante. Die bloße Absicht, das Objekt nie zu ändern, reicht nicht aus.

const val NUMBER = 5
val NAMES = listOf("Alice", "Bob")
val AGES = mapOf("Alice" to 35, "Bob" to 32)
val COMMA_JOINER = Joiner.on(',') // Joiner is immutable
val EMPTY_ARRAY = arrayOf()

Diese Namen sind in der Regel Substantive oder Nominalsätze.

Konstante Werte können nur innerhalb eines object oder als Deklaration auf oberster Ebene definiert werden. Werte, die ansonsten die Anforderung einer Konstanten erfüllen, aber in einer class definiert sind, müssen einen nicht konstanten Namen haben.

Für Konstanten, die skalare Werte sind, muss der Modifizierer const verwendet werden.

Nicht konstante Namen

Nicht konstante Namen werden in CamelCase geschrieben. Diese gelten für Instanzeigenschaften, lokale Eigenschaften und Parameternamen.

val variable = "var"
val nonConstScalar = "non-const"
val mutableCollection: MutableSet = 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")

Diese Namen sind in der Regel Substantive oder Nominalsätze.

Sicherungseigenschaften

Wenn ein unterstützendes Attribut benötigt wird, muss sein Name genau mit dem des realen Attributs übereinstimmen, es sei denn, es muss ein Unterstrich vorangestellt werden.

private var _table: Map? = null

val table: Map
    get() {
        if (_table == null) {
            _table = HashMap()
        }
        return _table ?: throw AssertionError()
    }

Variablennamen eingeben

Jede Typvariable wird in einem von zwei Stilen benannt:

  • Ein einzelner Großbuchstaben, optional gefolgt von einer einzelnen Ziffer (z. B. E, T, X, T2)
  • Ein Name in der für Klassen verwendeten Form, gefolgt vom Großbuchstaben T (z. B. RequestT, FooBarT)

CamelCase

Manchmal gibt es mehrere vernünftige Möglichkeiten, eine englische Phrase in die Camel-Case-Schreibweise umzuwandeln, z. B. wenn Akronyme oder ungewöhnliche Konstrukte wie „IPv6“ oder „iOS“ vorhanden sind. Verwenden Sie das folgende Schema, um die Vorhersehbarkeit zu verbessern.

Beginnend mit der Prosaform des Namens:

  1. Konvertieren Sie die Wortgruppe in einfachen ASCII-Code und entfernen Sie alle Apostrophe. So könnte beispielsweise „Müllers Algorithmus“ zu „Muellers-Algorithmus“ werden.
  2. Teilen Sie dieses Ergebnis in Wörter auf, indem Sie Leerzeichen und verbleibende Satzzeichen (in der Regel Bindestriche) verwenden. Empfohlen:Wenn ein Wort bereits die übliche Schreibweise eines Wortes mit Camel-Case-Schreibweise aufweist, teilen Sie es in seine Bestandteile auf (z.B. „AdWords“ wird zu „Anzeigenwörtern“). Ein Wort wie „iOS“ entspricht nicht wirklich der Camel-Case-Schreibweise, da es gegen alle Konventionen verstößt, sodass diese Empfehlung nicht zutrifft.
  3. Schreiben Sie jetzt alles in Kleinbuchstaben (einschließlich Akronyme) und führen Sie dann einen der folgenden Schritte aus:
    • Schreiben Sie das erste Zeichen jedes Wortes groß, um die Schreibweise „pascal“ zu verwenden.
    • Schreiben Sie das erste Zeichen jedes Wortes außer dem ersten groß, um die Camel-Case-Schreibweise zu erhalten.
  4. Abschließend müssen Sie alle Wörter zu einer einzigen Kennung zusammenführen.

Beachten Sie, dass die Groß- und Kleinschreibung der ursprünglichen Wörter fast vollständig ignoriert wird.

Prose-Formular Richtig Falsch
„XML-HTTP-Anfrage“ XmlHttpRequest XMLHTTPRequest
„neue Kundennummer“ newCustomerId newCustomerID
„innere Stoppuhr“ innerStopwatch innerStopWatch
„unterstützt IPv6 unter iOS“ supportsIpv6OnIos supportsIPv6OnIOS
„YouTube Importeur“ YouTubeImporter YoutubeImporter*

(* Zulässig, aber nicht empfohlen.)

Dokumentation

Formatierung

Die grundlegende Formatierung von KDoc-Blöcken wird in diesem Beispiel veranschaulicht:

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

...oder in diesem einzeiligen Beispiel:

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

Das grundlegende Formular ist immer zulässig. Die einzeilige Form kann ersetzt werden, wenn der gesamte KDoc-Block (einschließlich Kommentarmarkierungen) in eine einzige Zeile passt. Dies gilt nur, wenn keine Block-Tags wie @return vorhanden sind.

Absätze

Zwischen den Absätzen und vor der Gruppe von Block-Tags, falls vorhanden, wird eine Leerzeile – also eine Zeile, die nur das führende Sternchen (*) enthält, eingefügt.

Tags blockieren

Alle Standard-Blockier-Tags, die in der Reihenfolge @constructor, @receiver, @param, @property, @return, @throws, @see verwendet werden, erscheinen nie ohne leere Beschreibung. Wenn ein Block-Tag nicht in eine einzelne Zeile passt, werden Fortsetzungszeilen um vier Leerzeichen gegenüber der Position von @ eingerückt.

Zusammenfassungsfragment

Jeder KDoc-Block beginnt mit einem kurzen Zusammenfassungsfragment. Dieses Fragment ist sehr wichtig: Es ist der einzige Teil des Textes, der in bestimmten Kontexten wie Klassen- und Methodenindexen angezeigt wird.

Dies ist ein Fragment – eine Nominalphrase oder eine Verbformulierung, kein vollständiger Satz. Er beginnt nicht mit „A `Foo` is a...“ oder „This method returns...“ und muss auch keinen vollständigen imperativen Satz wie „Save the record.“ bilden. Das Fragment wird jedoch großgeschrieben und die Satzzeichen verwenden, als wäre es ein vollständiger Satz.

Nutzung

KDoc ist mindestens für jeden public-Typ und jedes public- oder protected-Mitglied dieses Typs vorhanden. Es gibt jedoch einige Ausnahmen, die unten aufgeführt sind.

Ausnahme: selbsterklärende Funktionen

KDoc ist optional für „einfache, offensichtliche“ Funktionen wie getFoo und Attribute wie foo, wenn es wirklich nichts wert ist, zu sagen, dass es nur „gibt den foo zurück“.

Es ist nicht angemessen, diese Ausnahme angeführt zu haben, um das Weglassen relevanter Informationen zu rechtfertigen, die ein typischer Leser möglicherweise wissen muss. Bei einer Funktion mit dem Namen getCanonicalName oder einer Property mit dem Namen canonicalName solltest du beispielsweise die Dokumentation (mit der Begründung, dass nur /** Returns the canonical name. */ lauten würde) nicht ausgelassen, wenn ein typischer Leser vielleicht keine Ahnung hat, was der Begriff „kanonischer Name“ bedeutet.

Ausnahme: Überschreibungen

KDoc ist bei einer Methode, die eine Supertype-Methode überschreibt, nicht immer vorhanden.