Throw и Throws — механизми бацања и декларације изузетака у програмским језицима. Оператор throw прекида нормално извршење функције и преноси објекат грешке навише по стеку позива. Кључна реч throws у потпису функције упозорава позивајућу страну о могућности грешке, чинећи код предвидљивим. Према Kotlin Documentation (2026), throw у Kotlin-у је израз (expression), а не инструкција, што омогућава његово коришћење унутар when-блокова и елвис-оператора.
Главно
Throw — је оператор који генерише изузетак у тачки извршења програма. Када наиђе на throw, тренутни ток извршења се одмах прекида и контрола се преноси најближем руковаоцу catch у стеку позива. Ако руковалац није пронађен, апликација се аварно завршава. Throw у мобилном развоју се користи за сигнализирање грешака које се не могу обрадити на тренутном нивоу апстракције — на пример, неисправан одговор сервера, недостатак мреже или некоректни аргументи.
Throws — модификатор у потпису функције (углавном у Swift-у) који изјављује да функција може бацити грешку. Ово је део механизма checked errors у Swift-у: позивајућа страна је дужна да обради грешку кроз do-catch, try?, try! или да означи своју функцију са throws ради даљег преношења (propagation). У Kotlin-у и Java-и throws такође постоји, али Kotlin га сматра сувишним — сви изузеци у Kotlin-у су unchecked, односно могу бити необрађени без синтаксичког принуђења. Према Apple Swift Documentation (2026), throws у Swift-у — једини начин да се експлицитно декларише могућност грешке у типу функције, што чини API уговоре транспарентним за програмера.
Разлика између throw и throws је фундаментална: throw — је акција (бацање изузетка у runtime-у), throws — је декларација (compile-time уговор). Функција без throws не може да користи throw — Swift компајлер ће дати грешку. Функција са throws можда не користи throw — то је дозвољено, али бесмислено. Такво раздвајање чини throw/throws моћним алатом за дизајн API-ја, где је уговор о грешци видљив у потпису функције пре њеног позивања.
У Swift-у оператор throw прихвата било који тип који имплементира протокол Error. Најчешће је то enum са кејсевима за различите врсте грешака. Swift не подржава checked exceptions у Java-стилу — уместо тога тип функције се означава са throws, а обрада пада на позивајућу страну. То чини throw у Swift-у флексибилнијим, али и одговорнијим за програмера.
Било који тип који одговара протоколу Error може бити бачен преко throw. Најчешће програмери користе enum са кејсевима без придружених вредности (за једноставне грешке) или са associated values (за преношење контекста). Swift не захтева да грешка буде enum — може се користити struct или class који имплементирају Error, али enum је пожељнији захваљујући exhaustive switch на страни руковаоца. Компајлер проверава да су сви кејсеви обрађени у do-catch.
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 дефинише три сценарија: неважећи акредитиви, истекао токен и блокиран налог са придруженом вредношћу remainingMinutes. Функција login је декларисана као throws — компајлер захтева да се позива преко try. Унутар функције throw се користи на два места: при неважећем username-у и при блокираном налогу. Придружена вредност accountLocked омогућава преношење конкретних података кориснику — колико минута да чека до деблокаде. Овај приступ елиминише потребу за засебним API endpoints за проверу статуса блокирања.
У Kotlin-у throw — је израз (expression) типа Nothing, а не инструкција. То значи да се throw може користити у десној страни доделе, унутар when-израза и елвис-оператора ?:. Тип Nothing — посебан подтип свих типова у Kotlin-у, што омогућава коришћење throw-а на местима где је потребна вредност било ког типа. Компајлер разуме да се после throw-а извршење не наставља и не захтева грану за овај случај.
Nothing — јединствени тип у Kotlin-у који је подтип свих могућих типова. Функција која враћа Nothing (на пример TODO()) никада се нормално не завршава — или увек баца изузетак или улази у бесконачну петљу. То чини throw природним кандидатом за коришћење на местима где је потребна вредност: елвис-оператор, when без else, иницијализација променљиве. Ако се throw налази у грани when, компајлер разуме да грана води ка Nothing-у и не захтева return или else за ту грану.
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")
}
}
}
У првом примеру throw се користи у елвис-оператору ?:: ако поље apiUrl недостаје у JSON-у, израз throw одмах прекида извршење и баца IllegalArgumentException. Тип Nothing омогућава компајлеру да закључи тип десне стране као String (елвис очекује String, throw има тип Nothing, Nothing је подтип String-а). У другом примеру throw унутар when-израза: ако код не одговара ниједном од познатих, баца се изузетак. Компајлер разуме да је после throw-а код недостижан, па повратни тип функције String није нарушен.
У Swift-у throws се наводи после листе параметара и пре стрелице повратног типа. Функција са throws може позивати само друге throws функције унутар do-catch или са try?. Ако throws функција не обрађује грешку, преноси је позивајућој страни. Swift такође подржава rethrows — модификатор за функције вишег реда које примају затворење (closure) са throws и прослеђују његову грешку. Rethrows значи да функција баца грешку само ако је прослеђено затворење бацило — сама функција не генерише грешку.
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
}
// Коришћење са throws-затворењем
let parsed = try mapValues(jsonStrings) { str in
let data = Data(str.utf8)
return try JSONDecoder().decode(Item.self, from: data)
}
Rethrows омогућава функцији mapValues да буде флексибилна: прихвата и throws затворења и обична. Ако се проследи throws затворење, позив mapValues захтева try; ако је обично — try није потребан. То чини rethrows идеалним за функције вишег реда попут map, filter, reduce у стандардној библиотеци Swift-а. Препорука Apple-а: користите rethrows за API-је који примају throws затворења и једини извор грешке је то затворење. Ако функција може бацити сопствену грешку, користите throws.
Swift throws је ближи checked exceptions (као у Java-и) — бачене грешке се декларишу у потпису. Kotlin и Dart користе unchecked изузетке — throws у потпису није потребан. Разлика је суштинска: checked приморава програмера на обраду (сигурније, али опширније), unchecked даје слободу, али повећава ризик да се заборави обрадити грешка. Swift је изабрао checked за throws, Kotlin — unchecked за све изузетке. Оба приступа имају предности: Swift је поузданији на нивоу језика, Kotlin компактнији и погоднији у ланцима функционалних трансформација.
За структурисану обраду грешака у мобилним апликацијама препоручује се креирање сопствених типова грешака уместо коришћења основних Exception или Error. У Swift-у се за то користи enum са протоколом Error, у Kotlin-у — sealed class са наслеђивањем од Throwable (или од Exception), у Dart-у — class са наслеђивањем од Exception. Прилагођени типови омогућавају груписање грешака по категоријама и преношење придружених података.
| Језик | Тип грешке | Карактеристика |
|---|---|---|
| Swift | enum: Error { ... } | Придружене вредности, exhaustive switch у catch |
| Kotlin | sealed class : Throwable() | Data class за грешке са пољима, when-израз |
| Dart | class implements Exception | Message-поље, on-клаузула у catch |
| Java | class extends Exception | Checked vs unchecked, обавезан throws у потпису |
При дизајнирању прилагођених грешака следите правило: једна грешка — један сценарио. Немојте обједињавати различите узроке у један тип са заставицом String message — правите засебне кејсеве/подкласе за сваки сценарио. То ће омогућити позивајућој страни да обрађује сваки случај кроз pattern matching (when/switch), а не кроз поређење стрингова. У Swift-у ово даје exhaustive checking — компајлер ће упозорити ако неки кејс enum NetworkError није обрађен.
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 наслеђује Throwable (стандардни тип изузетака у Kotlin-у). Свака подкласа је data class са сопственим пољима: Timeout садржи трајање тајм-аута у милисекундама, HttpError — код и тело одговора, NoConnection — оригинални IOException. Овакав дизајн омогућава обраду сваке грешке кроз when са исцрпним прегледом (када додате нову подкласу, компајлер ће вас приморати да ажурирате све when-изразе).
Swift нуди три варијанте позивања throws функција, свака са сопственим сигурносним уговором. try — стандардни начин: захтева do-catch или налажење унутар throws функције. try? претвара грешку у nil — резултат постаје опционалан, при грешци се враћа nil, тип се мења из T у T?. try! — принудно извршење без обраде: ако се грешка баци, апликација се руши. Користите try! само када сте апсолутно сигурни да је грешка немогућа (на пример, очигледно исправни подаци).
let configPath = Bundle.main.path(forResource: "config", ofType: "json")!
// try? — опциони резултат
let data = try? Data(contentsOf: URL(fileURLWithPath: configPath))
let json = try? JSONSerialization.jsonObject(with: data ?? Data())
// try! — гарантовани успех (само када сте сигурни)
let decoder = JSONDecoder()
let defaultConfig = try! decoder.decode(
Config.self,
from: Config.defaultJSON
)
// try — стандардна обрада
do {
let user = try fetchUser()
showUser(user)
} catch let error as NetworkError {
showRetryAlert(error.message)
}
У примеру try! се користи за очигледно исправан JSON уграђен у bundle апликације — грешка декодирања је немогућа при исправном издању. try? се примењује за читање конфигурационе датотеке — ако датотека недостаје или је оштећена, апликација користи подразумеване вредности уместо да се сруши. try у do-catch се користи за мрежне захтеве где је грешка очекивана и захтева реакцију корисника. Препорука: избегавајте try! у production коду — изузетно само за константне податке проверене у фази изградње.
Често постављана питања
Throw — оператор који баца грешку током извршења програма, прекидајући ток. Throws — модификатор потписа функције који изјављује да функција може бацити грешку. Функција без throws не може да користи throw. Throws је compile-time уговор, throw је runtime акција.
Kotlin следи филозофију unchecked exceptions: сви изузеци могу бити необрађени без синтаксичког принуђења. Програмери Kotlin-а сматрају да throws у Java-и доводи до сувишних try-catch блокова и игнорисања checked exceptions кроз празне catch. Nothing-тип у Kotlin-у омогућава коришћење throw-а као израза, замењујући throws флексибилнијим начином.
try! је дозвољен само када сте апсолутно сигурни да је грешка немогућа: очигледно исправан JSON из bundle-а, константни подаци, исправне URL шеме. У production коду try! је изузетак, а не правило. try? је пожељнији за опционе сценарије са подразумеваном вредношћу, try са do-catch — за обавезну обраду грешака.
Rethrows — модификатор за функције које примају throws затворења. Функција са rethrows баца грешку само ако је прослеђено затворење бацило. Ово омогућава функцијама вишег реда (map, filter) да раде и са throws и са non-throws затворењима без принудног try-а на позивајућој страни.
Да, унутар catch се може користити throw за преношење грешке навише по стеку, умотавајући је у други тип или додајући контекст. Ово се назива error chaining или rethrow. У Swift-у је довољан још један throw унутар catch, у Kotlin-у — throw унутар catch блока. finally блок ће се извршити пре преношења контроле даље.
Резиме
Развићемо мобилну апликацију под кључ
IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.
Прочитајте такође