Throw und Throws sind Mechanismen zum Werfen und Deklarieren von Ausnahmen in Programmiersprachen. Der throw-Operator unterbricht die normale Ausführung einer Funktion und reicht das Fehlerobjekt den Aufrufstapel hinauf. Das Schlüsselwort throws in einer Funktionssignatur warnt die aufrufende Seite vor der Möglichkeit eines Fehlers und macht den Code vorhersagbar. Laut Kotlin-Dokumentation (2026) ist throw in Kotlin ein Ausdruck (expression), keine Anweisung, was die Verwendung innerhalb von when-Blöcken und des Elvis-Operators ermöglicht.
Wichtige Punkte
Throw ist ein Operator, der am Punkt der Programmausführung eine Ausnahme erzeugt. Wenn throw auftritt, wird der aktuelle Ausführungsfluss sofort unterbrochen und die Steuerung an den nächstgelegenen catch-Handler im Aufrufstapel übergeben. Wenn kein Handler gefunden wird, stürzt die Anwendung ab. Throw wird in der mobilen Entwicklung verwendet, um Fehler zu signalisieren, die auf der aktuellen Abstraktionsebene nicht behandelt werden können — zum Beispiel eine ungültige Serverantwort, fehlendes Netzwerk oder falsche Argumente.
Throws — ein Modifikator in einer Funktionssignatur (hauptsächlich in Swift), der deklariert, dass die Funktion einen Fehler werfen kann. Dies ist Teil des Mechanismus der checked errors in Swift: Die aufrufende Seite ist verpflichtet, den Fehler über do-catch, try?, try! zu behandeln oder ihre eigene Funktion als throws für die weitere Weitergabe zu markieren. In Kotlin und Java existiert throws ebenfalls, aber Kotlin hält es für überflüssig — alle Ausnahmen in Kotlin sind unchecked, können also ohne syntaktischen Zwang unbehandelt bleiben. Laut Apple Swift-Dokumentation (2026) ist throws in Swift die einzige Möglichkeit, die Möglichkeit eines Fehlers im Funktionstyp explizit zu deklarieren, was API-Verträge für den Entwickler transparent macht.
Der Unterschied zwischen throw und throws ist grundlegend: throw ist eine Aktion (Ausnahme zur Laufzeit werfen), throws ist eine Deklaration (Compilezeit-Vertrag). Eine Funktion ohne throws kann throw nicht verwenden — der Swift-Compiler gibt einen Fehler aus. Eine Funktion mit throws darf throw nicht verwenden — es ist erlaubt, aber sinnlos. Diese Trennung macht throw/throws zu einem leistungsstarken API-Designwerkzeug, bei dem der Fehlervertrag vor dem Aufruf in der Funktionssignatur sichtbar ist.
In Swift akzeptiert der throw-Operator jeden Typ, der das Error-Protokoll implementiert. Meistens ist dies ein enum mit Fällen für verschiedene Fehlerarten. Swift unterstützt keine checked exceptions im Java-Stil — stattdessen wird der Funktionstyp mit throws markiert und die Behandlung an die aufrufende Seite delegiert. Dies macht throw in Swift flexibler, aber auch verantwortungsvoller für den Entwickler.
Jeder Typ, der dem Error-Protokoll entspricht, kann über throw geworfen werden. Entwickler verwenden häufig ein enum mit Fällen ohne assoziierte Werte (für einfache Fehler) oder mit assoziierten Werten (zum Übergeben von Kontext). Swift verlangt nicht, dass der Fehler ein enum ist — Sie können ein struct oder class verwenden, das Error implementiert, aber enum ist dank exhaustive switch auf der Handlerseite vorzuziehen. Der Compiler prüft, ob alle Fälle in do-catch behandelt werden.
enum AuthError: Error {
case invalidCredentials
case tokenExpired
case accountLocked(remainingMinutes: Int)
}
func login(username: String, password: String) throws -> Session {
guard isValid(username) else {
throw AuthError.invalidCredentials
}
let response = try api.authenticate(username, password)
if response.isLocked {
throw AuthError.accountLocked(
remainingMinutes: response.lockDuration
)
}
return Session(token: response.token)
}
AuthError definiert drei Szenarien: ungültige Anmeldedaten, abgelaufenes Token und gesperrtes Konto mit einem assoziierten Wert für remainingMinutes. Die Funktion login wird als throws deklariert — der Compiler verlangt den Aufruf über try. Innerhalb der Funktion wird throw an zwei Stellen verwendet: bei einem ungültigen Benutzernamen und bei einem gesperrten Konto. Der assoziierte Wert accountLocked ermöglicht es, dem Benutzer konkrete Daten zu übergeben — wie viele Minuten bis zur Entsperrung gewartet werden müssen. Dieser Ansatz macht separate API-Endpunkte zur Überprüfung des Sperrstatus überflüssig.
In Kotlin ist throw ein Ausdruck vom Typ Nothing, keine Anweisung. Das bedeutet, dass throw auf der rechten Seite einer Zuweisung, innerhalb von when-Ausdrücken und des Elvis-Operators ?: verwendet werden kann. Der Typ Nothing ist ein spezieller Subtyp aller Typen in Kotlin, was die Verwendung von throw an Stellen ermöglicht, an denen ein Wert eines beliebigen Typs benötigt wird. Der Compiler versteht, dass die Ausführung nach throw nicht fortgesetzt wird, und benötigt keinen Zweig für diesen Fall.
Nothing ist ein einzigartiger Typ in Kotlin, der ein Subtyp aller möglichen Typen ist. Eine Funktion, die Nothing zurückgibt (z.B. TODO()), wird niemals normal abgeschlossen — sie wirft entweder immer eine Ausnahme oder tritt in eine Endlosschleife ein. Dies macht throw zu einem natürlichen Kandidaten für die Verwendung an Stellen, an denen ein Wert benötigt wird: Elvis-Operator, when ohne else, Variableninitialisierung. Wenn throw in einem when-Zweig steht, versteht der Compiler, dass der Zweig zu Nothing führt, und verlangt kein return oder else für diesen Zweig.
data class Config(val apiUrl: String, val timeoutSec: Int)
class ConfigParser {
fun parse(json: String): Config {
val obj = JSONObject(json)
val url = obj.optString("apiUrl")
?: throw IllegalArgumentException("apiUrl is required")
val timeout = obj.optInt("timeoutSec", 30)
return Config(url, timeout)
}
fun getErrorMessage(code: Int): String {
return when (code) {
404 -> "Not found"
500 -> "Server error"
else -> throw IllegalArgumentException("Unknown code: $code")
}
}
}
Im ersten Beispiel wird throw im Elvis-Operator ?: verwendet: Wenn das Feld apiUrl im JSON fehlt, unterbricht der throw-Ausdruck sofort die Ausführung und wirft eine IllegalArgumentException. Der Typ Nothing ermöglicht es dem Compiler, den Typ der rechten Seite als String abzuleiten (Elvis erwartet String, throw hat den Typ Nothing, Nothing ist ein Subtyp von String). Im zweiten Beispiel wird throw innerhalb eines when-Ausdrucks verwendet: Wenn der Code mit keinem bekannten übereinstimmt, wird eine Ausnahme geworfen. Der Compiler versteht, dass der Code nach throw unerreichbar ist, sodass der Rückgabetyp der Funktion String nicht verletzt wird.
In Swift wird throws nach der Parameterliste und vor dem Pfeil des Rückgabetyps angegeben. Eine Funktion mit throws kann nur andere throws-Funktionen innerhalb von do-catch oder mit try? aufrufen. Wenn eine throws-Funktion den Fehler nicht behandelt, gibt sie ihn an die aufrufende Seite weiter. Swift unterstützt auch rethrows — einen Modifikator für höherwertige Funktionen, die einen throws-Closure akzeptieren und dessen Fehler weiterleiten. rethrows bedeutet, dass die Funktion nur dann einen Fehler wirft, wenn der übergebene Closure einen geworfen hat — die Funktion selbst erzeugt keinen Fehler.
func mapValues<T>(
_ array: [T],
transform: (T) throws -> U
) rethrows -> [U] {
var result = [U]()
for element in array {
result.append(try transform(element))
}
return result
}
// Verwendung mit throws-Closure
let parsed = try mapValues(jsonStrings) { str in
let data = Data(str.utf8)
return try JSONDecoder().decode(Item.self, from: data)
}
rethrows ermöglicht der Funktion mapValues, flexibel zu sein: Sie akzeptiert sowohl throws-Closures als auch normale. Wenn ein throws-Closure übergeben wird, erfordert der Aufruf von mapValues try; bei einem normalen ist try nicht erforderlich. Dies macht rethrows ideal für höherwertige Funktionen wie map, filter, reduce in der Swift-Standardbibliothek. Apple-Empfehlung: Verwenden Sie rethrows für APIs, die throws-Closures akzeptieren und deren einzige Fehlerquelle dieser Closure ist. Wenn die Funktion ihren eigenen Fehler werfen kann, verwenden Sie throws.
Swift throws ist näher an checked exceptions (wie in Java) — geworfene Fehler werden in der Signatur deklariert. Kotlin und Dart verwenden unchecked Ausnahmen — throws in der Signatur ist nicht erforderlich. Der Unterschied ist grundlegend: checked zwingt den Entwickler zur Fehlerbehandlung (sicherer aber ausführlicher), unchecked gibt Freiheit, erhöht aber das Risiko, einen Fehler zu vergessen. Swift wählte checked für throws, Kotlin wählte unchecked für alle Ausnahmen. Beide Ansätze haben Vorteile: Swift ist auf Sprachebene zuverlässiger, Kotlin ist kompakter und bequemer in funktionalen Transformationsketten.
Für eine strukturierte Fehlerbehandlung in mobilen Anwendungen wird empfohlen, benutzerdefinierte Fehlertypen anstelle von Basis-Exception oder Error zu erstellen. In Swift wird dafür ein enum mit dem Error-Protokoll verwendet, in Kotlin eine sealed class, die von Throwable (oder von Exception) erbt, in Dart eine Klasse, die von Exception erbt. Benutzerdefinierte Typen ermöglichen die Gruppierung von Fehlern nach Kategorien und das Übergeben assoziierter Daten.
| Sprache | Fehlertyp | Besonderheit |
|---|---|---|
| Swift | enum: Error { ... } | Assoziierte Werte, exhaustive switch in catch |
| Kotlin | sealed class : Throwable() | Data class für Fehler mit Feldern, when-Ausdruck |
| Dart | class implements Exception | Message-Feld, on-Klausel in catch |
| Java | class extends Exception | Checked vs unchecked, throws in Signatur erforderlich |
Beim Entwerfen benutzerdefinierter Fehler befolgen Sie die Regel: ein Fehler — ein Szenario. Kombinieren Sie nicht verschiedene Ursachen in einem Typ mit einem String-Message-Flag — erstellen Sie separate Fälle/Unterklassen für jedes Szenario. Dadurch kann die aufrufende Seite jeden Fall über Pattern Matching (when/switch) anstelle von String-Vergleichen behandeln. In Swift bietet dies exhaustive Checking — der Compiler warnt, wenn ein Fall des enum NetworkError nicht behandelt wird.
sealed class NetworkError(val message: String) : Throwable(message) {
data class Timeout(val durationMs: Long) :
NetworkError("Request timed out after ${durationMs}ms")
data class HttpError(val code: Int, val body: String?) :
NetworkError("HTTP $code")
data class NoConnection(val cause: IOException) :
NetworkError("No internet connection")
}
Die sealed class NetworkError erbt von Throwable (dem Standard-Ausnahmetyp in Kotlin). Jede Unterklasse ist eine data class mit eigenen Feldern: Timeout enthält die Timeout-Dauer in Millisekunden, HttpError enthält den Code und den Antworttext, NoConnection enthält die ursprüngliche IOException. Dieses Design ermöglicht die Behandlung jedes Fehlers über when mit erschöpfendem Matching (wenn Sie eine neue Unterklasse hinzufügen, zwingt der Compiler zur Aktualisierung aller when-Ausdrücke).
Swift bietet drei Möglichkeiten, throws-Funktionen aufzurufen, jede mit ihrem eigenen Sicherheitsvertrag. try ist die Standardmethode: erfordert do-catch oder das Befinden innerhalb einer throws-Funktion. try? wandelt den Fehler in nil um — das Ergebnis wird optional, im Fehlerfall wird nil zurückgegeben, der Typ ändert sich von T zu T?. try! — erzwungene Ausführung ohne Behandlung: Wenn ein Fehler geworfen wird, stürzt die Anwendung ab. Verwenden Sie try! nur, wenn Sie absolut sicher sind, dass ein Fehler unmöglich ist (z.B. offensichtlich gültige Daten).
let configPath = Bundle.main.path(forResource: "config", ofType: "json")!
// try? — optionales Ergebnis
let data = try? Data(contentsOf: URL(fileURLWithPath: configPath))
let json = try? JSONSerialization.jsonObject(with: data ?? Data())
// try! — garantierter Erfolg (nur wenn sicher)
let decoder = JSONDecoder()
let defaultConfig = try! decoder.decode(
Config.self,
from: Config.defaultJSON
)
// try — Standardbehandlung
do {
let user = try fetchUser()
showUser(user)
} catch let error as NetworkError {
showRetryAlert(error.message)
}
Im Beispiel wird try! für offensichtlich gültiges JSON verwendet, das in das App-Bundle eingebettet ist — ein Decodierungsfehler ist bei einer korrekten Veröffentlichung unmöglich. try? wird zum Lesen einer Konfigurationsdatei verwendet — wenn die Datei fehlt oder beschädigt ist, verwendet die App Standardwerte anstatt abzustürzen. try in do-catch wird für Netzwerkanfragen verwendet, bei denen ein Fehler erwartet wird und eine Benutzerreaktion erfordert. Empfehlung: Vermeiden Sie try! im Produktionscode — verwenden Sie es nur für konstante Daten, die zur Build-Zeit überprüft wurden.
Häufig gestellte Fragen
Throw ist ein Operator, der während der Programmausführung einen Fehler wirft und den Fluss unterbricht. Throws ist ein Funktionssignatur-Modifikator, der deklariert, dass die Funktion einen Fehler werfen kann. Eine Funktion ohne throws kann throw nicht verwenden. Throws ist ein Compilezeit-Vertrag, throw eine Laufzeit-Aktion.
Kotlin folgt der Philosophie der unchecked exceptions: Alle Ausnahmen können ohne syntaktischen Zwang unbehandelt bleiben. Kotlin-Entwickler glauben, dass throws in Java zu übermäßigen try-catch-Blöcken und zur Ignorierung von checked exceptions durch leere catch-Blöcke führt. Der Nothing-Typ von Kotlin ermöglicht die Verwendung von throw als Ausdruck und ersetzt throws durch einen flexibleren Ansatz.
try! ist nur akzeptabel, wenn Sie absolut sicher sind, dass ein Fehler unmöglich ist: offensichtlich gültiges JSON aus dem Bundle, konstante Daten, korrekte URL-Schemata. Im Produktionscode ist try! eine Ausnahme, keine Regel. try? ist für optionale Szenarien mit einem Fallback-Wert vorzuziehen, try mit do-catch für die obligatorische Fehlerbehandlung.
Rethrows ist ein Modifikator für Funktionen, die throws-Closures akzeptieren. Eine Funktion mit rethrows wirft nur dann einen Fehler, wenn der übergebene Closure einen geworfen hat. Dies ermöglicht es höherwertigen Funktionen (map, filter), sowohl mit throws- als auch mit Nicht-throws-Closures zu arbeiten, ohne try auf der aufrufenden Seite zu erzwingen.
Ja, innerhalb von catch kann throw verwendet werden, um den Fehler den Stapel hinauf zu propagieren, indem man ihn in einen anderen Typ einwickelt oder Kontext hinzufügt. Dies nennt man Error Chaining oder erneutes Werfen. In Swift reicht ein weiteres throw innerhalb von catch; in Kotlin ein throw innerhalb eines catch-Blocks. Der finally-Block wird ausgeführt, bevor die Steuerung weitergegeben wird.
Zusammenfassung
Wir entwickeln eine mobile Applikation schlüsselfertig
IT Sectr entwickelt seit 2017 iOS- und Android-Apps für Startups und Unternehmen. Wir beraten Sie und schlagen die beste Lösung vor.
Lesen Sie auch