Throw/Throws — wat is het, operatoren voor het gooien van uitzonderingen en hoe ze werken in mobiele ontwikkeling

Auteur: IT Sectr Gepubliceerd: 2026-05-26 Leestijd: 9 min

Throw en Throws — mechanismen voor het gooien en declareren van uitzonderingen in programmeertalen. De operator throw onderbreekt de normale uitvoering van een functie en geeft het foutobject door aan de aanroepstack. Het sleutelwoord throws in de functiehandtekening waarschuwt de aanroepende partij voor de mogelijkheid van een fout, waardoor de code voorspelbaar wordt. Volgens Kotlin Documentation (2026) is throw in Kotlin een expressie (expression), geen instructie, waardoor het gebruikt kan worden binnen when-blokken en de elvis-operator.

Belangrijkste punten

  • Throw — operator die de functie-uitvoering onderbreekt en het foutobject doorgeeft aan de aanroepstack
  • Throws — sleutelwoord in de functiehandtekening dat declareert dat de functie een uitzondering kan gooien
  • In Swift wordt de functie gemarkeerd met throws, de aanroep vereist try/try?/try!, en throw accepteert elk type dat het Error-protocol implementeert
  • In Kotlin is throw een expressie van het type Nothing, throws bestaat niet (alle uitzonderingen zijn unchecked)
  • Eigen fouten worden gemaakt via enum (Swift) of sealed class (Kotlin) voor gemakkelijke afhandeling in catch

Wat zijn Throw en Throws?

Throw is de operator die een uitzondering genereert op het uitvoeringspunt van het programma. Wanneer throw wordt aangetroffen, wordt de huidige uitvoeringsstroom onmiddellijk onderbroken en wordt de controle overgedragen aan de dichtstbijzijnde catch-handler in de aanroepstack. Als er geen handler wordt gevonden, crasht de applicatie. Throw wordt in mobiele ontwikkeling gebruikt om fouten te signaleren die niet op het huidige abstractieniveau kunnen worden afgehandeld — bijvoorbeeld een onjuist serverantwoord, geen netwerk of ongeldige argumenten.

Throws is een modificator in de functiehandtekening (voornamelijk in Swift) die declareert dat de functie een fout kan gooien. Dit maakt deel uit van het checked errors-mechanisme in Swift: de aanroepende partij is verplicht de fout af te handelen via do-catch, try?, try! of de eigen functie te markeren met throws voor verdere propagatie. In Kotlin en Java bestaat throws ook, maar Kotlin beschouwt het als overbodig — alle uitzonderingen in Kotlin zijn unchecked, wat betekent dat ze zonder syntactische dwang onbehandeld kunnen blijven. Volgens Apple Swift Documentation (2026) is throws in Swift de enige manier om de mogelijkheid van een fout expliciet te declareren in het functietype, wat API-contracten transparant maakt voor de ontwikkelaar.

Het verschil tussen throw en throws is fundamenteel: throw is een actie (het gooien van een uitzondering in runtime), throws is een declaratie (een compile-time contract). Een functie zonder throws kan geen throw gebruiken — de Swift-compiler geeft een fout. Een functie met throws kan throw niet gebruiken — dit is toegestaan maar zinloos. Deze scheiding maakt throw/throws een krachtig hulpmiddel voor API-ontwerp, waarbij het foutcontract zichtbaar is in de functiehandtekening voordat deze wordt aangeroepen.

Throw in Swift

In Swift accepteert de operator throw elk type dat het Error-protocol implementeert. Meestal is dit een enum met cases voor verschillende soorten fouten. Swift ondersteunt geen checked exceptions in Java-stijl — in plaats daarvan wordt het functietype gemarkeerd met throws en valt de afhandeling onder de verantwoordelijkheid van de aanroepende partij. Dit maakt throw in Swift flexibeler, maar ook verantwoordelijker voor de ontwikkelaar.

Het Error-protocol en fouttypen

Elk type dat voldoet aan het Error-protocol kan worden gegooid via throw. Vaak gebruiken ontwikkelaars een enum met cases zonder geassocieerde waarden (voor eenvoudige fouten) of met associated values (voor het doorgeven van context). Swift vereist niet dat de fout een enum is — een struct of class die Error implementeert kan ook worden gebruikt, maar een enum heeft de voorkeur vanwege exhaustive switch aan de kant van de handler. De compiler controleert of alle cases zijn afgehandeld in do-catch.

swift
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 definieert drie scenario's: ongeldige inloggegevens, verlopen token en geblokkeerd account met de geassocieerde waarde remainingMinutes. De functie login is gedeclareerd als throws — de compiler vereist dat deze wordt aangeroepen via try. Binnen de functie wordt throw op twee plaatsen gebruikt: bij ongeldige username en bij geblokkeerd account. De geassocieerde waarde accountLocked maakt het mogelijk om specifieke gegevens aan de gebruiker door te geven — hoeveel minuten te wachten tot deblokkering. Deze aanpak elimineert de noodzaak voor afzonderlijke API-endpoints om de blokkeringsstatus te controleren.

Throw in Kotlin

In Kotlin is throw een expressie (expression) van het type Nothing, geen instructie. Dit betekent dat throw kan worden gebruikt aan de rechterkant van een toewijzing, binnen when-expressies en de elvis-operator ?:. Het type Nothing is een speciaal subtype van alle typen in Kotlin, waardoor throw kan worden gebruikt op plaatsen waar een waarde van elk type vereist is. De compiler begrijpt dat de uitvoering na throw niet doorgaat en vereist geen tak voor dit geval.

Het Nothing-type en zijn rol in compositie

Nothing is een uniek type in Kotlin dat een subtype is van alle mogelijke typen. Een functie die Nothing retourneert (bijvoorbeeld TODO()) eindigt nooit normaal — of gooit altijd een uitzondering of gaat in een oneindige lus. Dit maakt throw een natuurlijke kandidaat voor gebruik op plaatsen waar een waarde vereist is: de elvis-operator, when zonder else, variabele-initialisatie. Als throw zich in een when-tak bevindt, begrijpt de compiler dat de tak naar Nothing leidt en vereist geen return of else voor deze tak.

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

In het eerste voorbeeld wordt throw gebruikt in de elvis-operator ?:: als het veld apiUrl ontbreekt in JSON, onderbreekt de throw-expressie onmiddellijk de uitvoering en gooit IllegalArgumentException. Het type Nothing stelt de compiler in staat om het type van de rechterkant als String af te leiden (elvis verwacht String, throw heeft type Nothing, Nothing is een subtype van String). In het tweede voorbeeld throw binnen een when-expressie: als de code niet overeenkomt met een van de bekende, wordt een uitzondering gegooid. De compiler begrijpt dat de code na throw onbereikbaar is, dus het retourtype van de functie String wordt niet geschonden.

Throws in de functiehandtekening en rethrows

In Swift wordt throws gespecificeerd na de parameterlijst en voor de pijl van het retourtype. Een functie met throws kan alleen andere throws-functies aanroepen binnen do-catch of met try?. Als een throws-functie de fout niet afhandelt, geeft deze deze door aan de aanroepende partij. Swift ondersteunt ook rethrows — een modificator voor functies van hogere orde die een closure met throws accepteren en de fout ervan propageren. Rethrows betekent dat de functie alleen een fout gooit als de doorgegeven closure deze heeft gegooid — de functie zelf genereert geen fout.

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

// Gebruik met throws-closure
let parsed = try mapValues(jsonStrings) { str in
    let data = Data(str.utf8)
    return try JSONDecoder().decode(Item.self, from: data)
}

Rethrows stelt de functie mapValues in staat flexibel te zijn: het accepteert zowel throws-closures als gewone. Als een throws-closure wordt doorgegeven, vereist de aanroep van mapValues try; als het gewoon is — is try niet nodig. Dit maakt rethrows ideaal voor functies van hogere orde zoals map, filter, reduce in de standaard Swift-bibliotheek. Aanbeveling van Apple: gebruik rethrows voor API's die throws-closures accepteren en waar de enige foutbron deze closure is. Als de functie een eigen fout kan gooien, gebruik dan throws.

Checked versus unchecked uitzonderingen

Swift throws ligt dichter bij checked exceptions (zoals in Java) — gegooid fouten worden gedeclareerd in de handtekening. Kotlin en Dart gebruiken unchecked uitzonderingen — throws in de handtekening is niet vereist. Het verschil is fundamenteel: checked dwingt de ontwikkelaar tot afhandeling (veiliger maar uitgebreider), unchecked geeft vrijheid maar verhoogt het risico om een fout te vergeten af te handelen. Swift koos voor checked voor throws, Kotlin voor unchecked voor alle uitzonderingen. Beide benaderingen hebben voordelen: Swift is betrouwbaarder op taalniveau, Kotlin is compacter en handiger in ketens van functionele transformaties.

Eigen fouttypen

Voor gestructureerde foutafhandeling in mobiele applicaties wordt aanbevolen om eigen fouttypen te maken in plaats van de basis Exception of Error te gebruiken. In Swift wordt hiervoor een enum met het Error-protocol gebruikt, in Kotlin een sealed class met overerving van Throwable (of van Exception), in Dart een class met overerving van Exception. Eigen typen maken het mogelijk om fouten te groeperen per categorie en geassocieerde gegevens door te geven.

TaalFouttypeKenmerk
Swiftenum: Error { ... }Geassocieerde waarden, exhaustive switch in catch
Kotlinsealed class : Throwable()Data class voor fouten met velden, when-expressie
Dartclass implements ExceptionMessage-veld, on-clausule in catch
Javaclass extends ExceptionChecked vs unchecked, verplichte throws in handtekening

Bij het ontwerpen van eigen fouten volgt u de regel: één fout — één scenario. Combineer verschillende oorzaken niet in één type met een String-message-vlag — maak afzonderlijke cases/subklassen voor elk scenario. Dit stelt de aanroepende partij in staat om elk geval af te handelen via pattern matching (when/switch) in plaats van stringvergelijking. In Swift geeft dit exhaustive checking — de compiler waarschuwt als een case van de enum NetworkError niet is afgehandeld.

Voorbeeld van een eigen fout in Kotlin

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

Sealed class NetworkError erft van Throwable (het standaard uitzonderingstype in Kotlin). Elke subklasse is een data class met eigen velden: Timeout bevat de time-outduur in milliseconden, HttpError — de code en de body van het antwoord, NoConnection — de originele IOException. Dit ontwerp maakt het mogelijk om elke fout via when af te handelen met volledige dekking (wanneer u een nieuwe subklasse toevoegt, dwingt de compiler u om alle when-expressies bij te werken).

Try, try? en try! in Swift

Swift biedt drie varianten voor het aanroepen van throws-functies, elk met een eigen veiligheidscontract. try is de standaardmanier: vereist do-catch of het bevinden binnen een throws-functie. try? converteert de fout naar nil — het resultaat wordt optioneel, bij een fout wordt nil geretourneerd, het type verandert van T naar T?. try! is geforceerde uitvoering zonder afhandeling: als er een fout wordt gegooid, crasht de applicatie. Gebruik try! alleen wanneer u absoluut zeker weet dat een fout onmogelijk is (bijvoorbeeld overduidelijk correcte gegevens).

swift
let configPath = Bundle.main.path(forResource: "config", ofType: "json")!

// try? — optioneel resultaat
let data = try? Data(contentsOf: URL(fileURLWithPath: configPath))
let json = try? JSONSerialization.jsonObject(with: data ?? Data())

// try! — gegarandeerd succes (alleen wanneer u zeker bent)
let decoder = JSONDecoder()
let defaultConfig = try! decoder.decode(
    Config.self,
    from: Config.defaultJSON
)

// try — standaard afhandeling
do {
    let user = try fetchUser()
    showUser(user)
} catch let error as NetworkError {
    showRetryAlert(error.message)
}

In het voorbeeld wordt try! gebruikt voor overduidelijk geldige JSON die is ingebouwd in de applicatie-bundle — een decoderingsfout is onmogelijk bij een correcte release. try? wordt toegepast voor het lezen van een configuratiebestand — als het bestand ontbreekt of beschadigd is, gebruikt de applicatie standaardwaarden in plaats van te crashen. try in do-catch wordt gebruikt voor netwerkverzoeken waarbij een fout wordt verwacht en gebruikersreactie vereist. Aanbeveling: vermijd try! in productiecode — maak uitzonderingen alleen voor constante gegevens die tijdens de build zijn geverifieerd.

Veelgestelde vragen

Wat is het verschil tussen throw en throws in Swift?

Throw is een operator die een fout gooit tijdens de uitvoering van het programma en de stroom onderbreekt. Throws is een modificator van de functiehandtekening die declareert dat de functie een fout kan gooien. Een functie zonder throws kan geen throw gebruiken. Throws is een compile-time contract, throw is een runtime-actie.

Waarom heeft Kotlin geen throws?

Kotlin volgt de filosofie van unchecked exceptions: alle uitzonderingen kunnen zonder syntactische dwang onbehandeld blijven. Kotlin-ontwikkelaars vinden dat throws in Java leidt tot overbodige try-catch-blokken en het negeren van checked exceptions via lege catch-blokken. Het Nothing-type in Kotlin maakt het mogelijk throw als expressie te gebruiken, wat throws vervangt op een flexibelere manier.

Wanneer moet try! worden gebruikt in Swift?

try! is alleen toegestaan wanneer u absoluut zeker weet dat een fout onmogelijk is: overduidelijk geldige JSON uit de bundle, constante gegevens, correcte URL-schema's. In productiecode is try! een uitzondering, geen regel. try? heeft de voorkeur voor optionele scenario's met een standaardwaarde, try met do-catch voor verplichte foutafhandeling.

Wat is rethrows in Swift?

Rethrows is een modificator voor functies die throws-closures accepteren. Een functie met rethrows gooit alleen een fout als de doorgegeven closure deze heeft gegooid. Dit stelt functies van hogere orde (map, filter) in staat om zowel met throws- als non-throws-closures te werken zonder geforceerde try aan de aanroepende kant.

Kan een fout worden gegooid binnen een catch-blok?

Ja, binnen catch kan throw worden gebruikt om de fout hoger in de stack te propageren, deze in een ander type te verpakken of context toe te voegen. Dit wordt error chaining of rethrow genoemd. In Swift is een extra throw binnen catch voldoende, in Kotlin — throw binnen het catch-blok. Het finally-blok wordt uitgevoerd voordat de controle verder wordt doorgegeven.

Samenvatting

  • Throw — een operator die een uitzondering gooit, de huidige stroom onderbreekt en het foutobject doorgeeft aan de stack
  • Throws — een compile-time declaratie in de functiehandtekening over de mogelijkheid van een fout, verplicht in Swift, afwezig in Kotlin
  • In Swift accepteert throw enum: Error, de functie wordt gemarkeerd met throws en aangeroepen via try / try? / try!
  • In Kotlin is throw een expressie van het type Nothing, die gebruik in when, de elvis-operator en toewijzingen mogelijk maakt
  • Rethrows in Swift stelt functies van hogere orde in staat om fouten alleen van doorgegeven closures te propageren
  • Eigen fouten worden gemaakt via enum (Swift) of sealed class (Kotlin) met geassocieerde waarden voor gedetailleerde informatie
  • Ontwerp fouttypen volgens het principe „één case — één scenario” voor gemakkelijke afhandeling via pattern matching

We ontwikkelen een mobiele applicatie turnkey

IT Sectr creëert sinds 2017 iOS- en Android-applicaties voor startups en bedrijven. We adviseren u en stellen de beste oplossing voor.

Bespreek het project

Lees ook