Either<L, R>: typowana obsługa błędów bez wyjątków
Użyj Either do reprezentowania powodzenia i niepowodzenia bez zgłaszania wyjątków.
Either<L, R>: typowana obsługa błędów bez wyjątków to bezpłatna lekcja Kotlin Academy na CoddyKit. To lekcja 1 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Kotlin Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Kotlin Academy zawiera 4 lekcji w sumie.
Problem z wyjątkami w logice biznesowej
Wyjątki są przeznaczone do obsługi nieoczekiwanych awarii (null pointer, błąd wejścia-wyjścia). Używanie ich do sygnalizowania oczekiwanych niepowodzeń biznesowych (błąd walidacji, „nie znaleziono”) sprawia, że przepływ sterowania staje się niewidoczny, wymusza używanie try/catch w każdym miejscu wywołania i ukrywa błędy w sygnaturach funkcji.
Czym jest Either<L, R>?
Either to typ sumy z dwoma przypadkami: Left(value: L) konwencjonalnie przechowuje błąd, a Right(value: R) — wartość oznaczającą powodzenie. Funkcja zwracająca Either jawnie wskazuje w swojej sygnaturze możliwość niepowodzenia.
Either w Arrow
Należy dodać Arrow do projektu, aby uzyskać Either i pełny ekosystem jego operatorów:
// build.gradle.kts
implementation("io.arrow-kt:arrow-core:1.2.4")
// Usage
import arrow.core.Either
import arrow.core.left
import arrow.core.rightZwracanie Either z funkcji
W przypadku powodzenia należy zwrócić value.right(), a w przypadku niepowodzenia — error.left(). Wywołujący musi obsłużyć obie gałęzie:
sealed class UserError { object NotFound : UserError(); data class InvalidEmail(val msg: String) : UserError() }
fun findUser(id: Long): Either<UserError, User> =
if (id <= 0) UserError.NotFound.left()
else User(id, "Alice").right()Obsługa Either za pomocą fold
Należy użyć fold(ifLeft, ifRight), aby obsłużyć oba przypadki w jednym wyrażeniu:
val result = findUser(1L)
val message = result.fold(
ifLeft = { error -> "Error: $error" },
ifRight = { user -> "Found: ${user.name}" }
)
println(message)Przekształcanie wartości Right za pomocą map
map { } przekształca wartość Right, nie zmieniając Left. Dzięki temu Either jest funktorem — można bezpiecznie łączyć przekształcenia:
val nameResult: Either<UserError, String> = findUser(1L).map { it.name }Łączenie za pomocą flatMap
flatMap { } łączy obliczenia, które same zwracają Either. Jeśli dowolny krok zwróci Left, łańcuch zostanie przerwany, a błąd propagowany bez wykonywania kolejnych kroków:
fun validateEmail(email: String): Either<UserError, String> =
if (email.contains("@")) email.right()
else UserError.InvalidEmail("bad format").left()
fun createUser(email: String): Either<UserError, User> =
validateEmail(email).flatMap { validEmail ->
User(1L, validEmail).right()
}Either.catch do opakowywania wyjątków
Either.catch { } wykonuje blok i opakowuje każdy wyjątek jako Left. Należy używać go na granicy między starszym kodem, który zgłasza wyjątki, a domeną opartą na Either:
val result: Either<Throwable, User> = Either.catch {
userRepository.findOrThrow(id)
}Odzyskiwanie za pomocą getOrElse i orElse
getOrElse { default } wyodrębnia wartość Right albo zwraca wartość domyślną. orElse { alternativeEither } zastępuje Left innym obliczeniem:
val user: User = findUser(0L).getOrElse { User(-1L, "Guest") }
val user2: Either<UserError, User> = findUser(0L).orElse { User(99L, "Default").right() }Dopasowywanie wzorców za pomocą when
Należy użyć when na klasie zapieczętowanej w stylu Either albo bezpośrednio na Either za pomocą is Either.Left / Either.Right, aby wyczerpująco obsłużyć wszystkie przypadki:
when (val r = findUser(1L)) {
is Either.Left -> println("Error: ${r.value}")
is Either.Right -> println("User: ${r.value.name}")
}Either w warstwach usług
Należy zwracać Either z funkcji repozytorium i usług. Należy mapować je na odpowiedzi HTTP na poziomie tras Ktor, utrzymując logikę biznesową niezależną od szczegółów frameworka:
get("/users/{id}") {
val id = call.parameters["id"]?.toLongOrNull() ?: return@get call.respond(HttpStatusCode.BadRequest)
userService.findById(id).fold(
ifLeft = { call.respond(HttpStatusCode.NotFound) },
ifRight = { call.respond(it) }
)
}Szybkie sprawdzenie
Co robi flatMap { } dla wartości Either.Left?
Podsumowanie: Either<L, R>
Najważniejsze informacje:
Eitherjawnie wskazuje ścieżkę niepowodzenia w sygnaturze funkcjiRight= powodzenie;Left= niepowodzenie (zgodnie z konwencją)map { }— przekształca wartość oznaczającą powodzenie;flatMap { }— łączy obliczenia, które mogą zakończyć się niepowodzeniemfold(ifLeft, ifRight)— obsługuje oba przypadki w jednym wyrażeniuEither.catch { }— opakowuje kod zgłaszający wyjątki na granicach systemu
Często zadawane pytania
Czy lekcja „Either<L, R>: typowana obsługa błędów bez wyjątków” jest bezpłatna?
Tak — pełny tekst „Either<L, R>: typowana obsługa błędów bez wyjątków” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Kotlin Academy, przejdź na CoddyKit PRO. Kurs Kotlin Academy zawiera 4 lekcji w sumie.
Co nauczysz się w „Either<L, R>: typowana obsługa błędów bez wyjątków”?
Użyj Either do reprezentowania powodzenia i niepowodzenia bez zgłaszania wyjątków. Ćwiczysz Kotlin Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć Kotlin Academy?
Nie wymagamy żadnego doświadczenia. Kotlin Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 1 z 4.
Ile czasu zajmuje lekcja „Either<L, R>: typowana obsługa błędów bez wyjątków”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji Kotlin Academy?
Tak. Każda lekcja Kotlin Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Either : typowana obsługa błędów bez wyjątków
- DSL Raise w Arrow: składanie typowanych błędów
- Option i nullable: kiedy używać każdego z nich
- Funkcjonalne modelowanie domeny za pomocą typów podstawowych Arrow