Throw/Throws — vad är det, operatorer för att kasta undantag och hur de fungerar inom mobilutveckling

Författare: IT Sectr Publicerad: 2026-05-26 Lästid: 9 min

Throw och Throws — mekanismer för att kasta och deklarera undantag i programmeringsspråk. Operatorn throw avbryter normal exekvering av en funktion och skickar felobjektet uppåt i anropsstacken. Nyckelordet throws i funktionens signatur varnar den anropande parten om möjligheten av ett fel, vilket gör koden förutsägbar. Enligt Kotlin Documentation (2026) är throw i Kotlin ett uttryck (expression), inte en instruktion, vilket möjliggör användning inom when-block och elvis-operatorn.

Huvudpunkter

  • Throw — operator som avbryter funktionens exekvering och skickar felobjektet uppåt i anropsstacken
  • Throws — nyckelord i funktionens signatur som deklarerar att funktionen kan kasta ett undantag
  • I Swift markeras funktionen med throws, anrop kräver try/try?/try!, och throw accepterar alla typer som implementerar Error-protokollet
  • I Kotlin är throw ett uttryck av typen Nothing, throws finns inte (alla undantag är unchecked)
  • Anpassade fel skapas via enum (Swift) eller sealed class (Kotlin) för enkel hantering i catch

Vad är Throw och Throws?

Throw är operatorn som genererar ett undantag vid programmets exekveringspunkt. När throw påträffas avbryts den aktuella exekveringsströmmen omedelbart och kontrollen överförs till närmaste catch-hanterare i anropsstacken. Om ingen hanterare hittas avslutas applikationen onormalt. Throw inom mobilutveckling används för att signalera fel som inte kan hanteras på den aktuella abstraktionsnivån — till exempel felaktigt serversvar, saknat nätverk eller ogiltiga argument.

Throws är en modifierare i funktionssignaturen (främst i Swift) som deklarerar att funktionen kan kasta ett fel. Detta är en del av mekanismen för checked errors i Swift: den anropande parten är skyldig att hantera felet via do-catch, try?, try! eller markera sin egen funktion med throws för vidare förmedling (propagation). I Kotlin och Java finns throws också, men Kotlin anser det överflödigt — alla undantag i Kotlin är unchecked, vilket innebär att de kan förbli ohanterade utan syntaktiskt tvång. Enligt Apple Swift Documentation (2026) är throws i Swift — det enda sättet att explicit deklarera möjligheten av ett fel i funktionstypen, vilket gör API-kontrakt transparenta för utvecklaren.

Skillnaden mellan throw och throws är fundamental: throw är en handling (att kasta ett undantag vid körning), throws är en deklaration (ett kontrakt vid kompilering). En funktion utan throws kan inte använda throw — Swift-kompilatorn ger ett fel. En funktion med throws kan låta bli att använda throw — detta är tillåtet men meningslöst. Denna uppdelning gör throw/throws till ett kraftfullt verktyg för API-design, där felkontraktet syns i funktionssignaturen innan den anropas.

Throw i Swift

I Swift accepterar operatorn throw alla typer som implementerar Error-protokollet. Oftast är detta en enum med cases för olika typer av fel. Swift stödjer inte checked exceptions i Java-stil — istället markeras funktionstypen med throws och hanteringen ligger på den anropande parten. Detta gör throw i Swift mer flexibelt, men också mer ansvarsfullt för utvecklaren.

Error-protokollet och feltyper

Alla typer som följer Error-protokollet kan kastas via throw. Oftast använder utvecklare en enum med cases utan associerade värden (för enkla fel) eller med associated values (för att förmedla kontext). Swift kräver inte att felet är en enum — en struct eller class som implementerar Error kan användas, men enum är att föredra tack vare exhaustive switch på hanterarsidan. Kompilatorn kontrollerar att alla cases hanteras i 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 definierar tre scenarier: ogiltiga inloggningsuppgifter, utgången token och blockerat konto med det associerade värdet remainingMinutes. Funktionen login är deklarerad som throws — kompilatorn kräver att den anropas via try. Inuti funktionen används throw på två ställen: vid ogiltigt username och vid blockerat konto. Det associerade värdet accountLocked gör det möjligt att förmedla specifik data till användaren — hur många minuter att vänta tills upplåsning. Denna metod eliminerar behovet av separata API-endpoints för att kontrollera blockeringsstatus.

Throw i Kotlin

I Kotlin är throw — ett uttryck (expression) av typen Nothing, inte en instruktion. Detta innebär att throw kan användas på höger sida av tilldelning, inuti when-uttryck och elvis-operatorn ?:. Typen Nothing är en speciell undertyp av alla typer i Kotlin, vilket möjliggör användning av throw på platser där ett värde av valfri typ krävs. Kompilatorn förstår att exekveringen inte fortsätter efter throw och kräver ingen gren för detta fall.

Nothing-typen och dess roll i komposition

Nothing är en unik typ i Kotlin som är en undertyp av alla möjliga typer. En funktion som returnerar Nothing (till exempel TODO()) avslutas aldrig normalt — antingen kastar den alltid ett undantag eller går in i en oändlig loop. Detta gör throw till en naturlig kandidat för användning på platser där ett värde krävs: elvis-operatorn, when utan else, variabelinitiering. Om throw finns i en when-gren förstår kompilatorn att grenen leder till Nothing och kräver inget return eller else för denna gren.

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

I det första exemplet används throw i elvis-operatorn ?:: om fältet apiUrl saknas i JSON, avbryter throw-uttrycket omedelbart exekveringen och kastar IllegalArgumentException. Typen Nothing gör det möjligt för kompilatorn att härleda typen av höger sida som String (elvis förväntar sig String, throw har typen Nothing, Nothing är en undertyp av String). I det andra exemplet throw inuti ett when-uttryck: om koden inte matchar någon av de kända, kastas ett undantag. Kompilatorn förstår att koden efter throw är oåtkomlig, så funktionens returtyp String är inte bruten.

Throws i funktionssignaturen och rethrows

I Swift anges throws efter parameterlistan och före returtypens pil. En funktion med throws kan endast anropa andra throws-funktioner inom do-catch eller med try?. Om en throws-funktion inte hanterar felet, skickar hon det vidare till den anropande parten. Swift stödjer även rethrows — en modifierare för högre ordningens funktioner som tar en closure med throws och vidarebefordrar dess fel. Rethrows innebär att funktionen endast kastar ett fel om den skickade closuren kastade det — funktionen själv genererar inget fel.

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
}

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

Rethrows gör funktionen mapValues flexibel: den accepterar både throws-closures och vanliga. Om en throws-closure skickas, kräver anropet av mapValues try; om den är vanlig — krävs inget try. Detta gör rethrows idealiskt för högre ordningens funktioner som map, filter, reduce i Swifts standardbibliotek. Apples rekommendation: använd rethrows för API:er som accepterar throws-closures och där den enda felkällan är denna closure. Om funktionen kan kasta ett eget fel, använd throws.

Checked vs unchecked undantag

Swift throws ligger närmare checked exceptions (som i Java) — kastade fel deklareras i signaturen. Kotlin och Dart använder unchecked undantag — throws i signaturen krävs inte. Skillnaden är fundamental: checked tvingar utvecklaren att hantera (säkrare men mer pratigt), unchecked ger frihet men ökar risken att glömma hantera ett fel. Swift valde checked för throws, Kotlin — unchecked för alla undantag. Båda metoderna har fördelar: Swift är mer tillförlitligt på språknivå, Kotlin är mer kompakt och bekvämt i kedjor av funktionella transformationer.

Anpassade feltyper

För strukturerad felhantering i mobila applikationer rekommenderas att skapa egna feltyper istället för att använda grundläggande Exception eller Error. I Swift används en enum med Error-protokollet, i Kotlin — sealed class med arv från Throwable (eller Exception), i Dart — class med arv från Exception. Anpassade typer möjliggör gruppering av fel efter kategori och förmedling av associerade data.

SpråkFeltypEgenskap
Swiftenum: Error { ... }Associerade värden, exhaustive switch i catch
Kotlinsealed class : Throwable()Data class för fel med fält, when-uttryck
Dartclass implements ExceptionMessage-fält, on-klausul i catch
Javaclass extends ExceptionChecked vs unchecked, obligatoriskt throws i signaturen

Vid design av anpassade fel, följ regeln: ett fel — ett scenario. Kombinera inte olika orsaker i en typ med en String-message-flagga — skapa separata cases/subklasser för varje scenario. Detta gör att den anropande parten kan hantera varje fall genom pattern matching (when/switch) istället för strängjämförelse. I Swift ger detta exhaustive checking — kompilatorn varnar om ett case i enum NetworkError inte har hanterats.

Exempel på anpassat fel i 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 ärver från Throwable (standardundantagstypen i Kotlin). Varje underklass är en data class med egna fält: Timeout innehåller timeoutens varaktighet i millisekunder, HttpError — svarskoden och svarskroppen, NoConnection — det ursprungliga IOException. En sådan design möjliggör hantering av varje fel via when med fullständig täckning (när du lägger till en ny underklass tvingar kompilatorn dig att uppdatera alla when-uttryck).

Try, try? och try! i Swift

Swift erbjuder tre varianter för att anropa throws-funktioner, var och en med sitt eget säkerhetskontrakt. try är standardsättet: kräver do-catch eller att vara inuti en throws-funktion. try? omvandlar felet till nil — resultatet blir valfritt, vid fel returneras nil, typen ändras från T till T?. try! är tvingad exekvering utan hantering: om ett fel kastas kraschar applikationen. Använd try! endast när du är absolut säker på att felet är omöjligt (till exempel uppenbart korrekt data).

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

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

// try! — garanterad framgång (endast när du är säker)
let decoder = JSONDecoder()
let defaultConfig = try! decoder.decode(
    Config.self,
    from: Config.defaultJSON
)

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

I exemplet används try! för uppenbart giltig JSON inbäddad i applikationens bundle — avkodningsfel är omöjligt vid en korrekt utgåva. try? tillämpas för att läsa en konfigurationsfil — om filen saknas eller är skadad använder applikationen standardvärden istället för att krascha. try i do-catch används för nätverksförfrågningar där fel förväntas och kräver användarrespons. Rekommendation: undvik try! i produktionskod — gör undantag endast för konstanta data som verifierats vid byggstadiet.

Vanliga frågor

Vad är skillnaden mellan throw och throws i Swift?

Throw är en operator som kastar ett fel under programexekveringen och avbryter flödet. Throws är en modifierare av funktionssignaturen som deklarerar att funktionen kan kasta ett fel. En funktion utan throws kan inte använda throw. Throws är ett kompileringskontrakt, throw är en körningshandling.

Varför finns inte throws i Kotlin?

Kotlin följer filosofin med unchecked exceptions: alla undantag kan förbli ohanterade utan syntaktiskt tvång. Kotlin-utvecklare anser att throws i Java leder till överflödiga try-catch-block och ignorering av checked exceptions genom tomma catch-block. Nothing-typen i Kotlin gör det möjligt att använda throw som ett uttryck och ersätter throws på ett mer flexibelt sätt.

När ska try! användas i Swift?

try! är endast tillåtet när du är absolut säker på att felet är omöjligt: uppenbart giltig JSON från bundle, konstanta data, korrekta URL-scheman. I produktionskod är try! ett undantag, inte en regel. try? är att föredra för valfria scenarier med standardvärde, try med do-catch för obligatorisk felhantering.

Vad är rethrows i Swift?

Rethrows är en modifierare för funktioner som accepterar throws-closures. En funktion med rethrows kastar endast ett fel om den skickade closuren kastade det. Detta gör att högre ordningens funktioner (map, filter) kan arbeta med både throws- och non-throws-closures utan tvingat try på den anropande sidan.

Kan man kasta ett fel inuti ett catch-block?

Ja, inuti catch kan throw användas för att vidarebefordra felet uppåt i stacken, packa in det i en annan typ eller lägga till kontext. Detta kallas error chaining eller rethrow. I Swift räcker en till throw inuti catch, i Kotlin — throw inuti catch-blocket. Finally-blocket körs innan kontrollen skickas vidare.

Sammanfattning

  • Throw — operator för att kasta undantag som avbryter det aktuella flödet och skickar felobjektet uppåt i stacken
  • Throws — kompileringsdeklaration i funktionssignaturen om felmöjlighet, obligatorisk i Swift, saknas i Kotlin
  • I Swift accepterar throw enum: Error, funktionen markeras med throws, anropas via try / try? / try!
  • I Kotlin är throw ett uttryck av typen Nothing, vilket möjliggör användning i when, elvis-operatorn och tilldelningar
  • Rethrows i Swift låter högre ordningens funktioner vidarebefordra fel endast från skickade closures
  • Anpassade fel skapas via enum (Swift) eller sealed class (Kotlin) med associerade värden för detaljerad information
  • Designa feltyper enligt principen ett case — ett scenario för enkel hantering via pattern matching

Vi utvecklar en mobil applikation nyckelfärdigt

IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.

Diskutera projektet

Läs också