programowanieProgramista Kotlin

Czym jest konstrukcja when w Kotlinie, jak działa, czym różni się od switch-case w Javie i jakie możliwości oferuje do obsługi różnych sytuacji? Podaj przykłady różnych przypadków użycia.

Zdaj rozmowy kwalifikacyjne z asystentem AI Hintsage

Odpowiedź.

Konstrukcja when w Kotlinie to potężne narzędzie do zarządzania przepływem wykonania programu, które zastępuje tradycyjny switch-case z Javy. when został wprowadzony w celu zwiększenia wyrazistości, skrócenia kodu boilerplate oraz zwiększenia bezpieczeństwa typów.

Historia pytania

W Javie konstrukcja switch-case jest ograniczona tylko do określonych typów (enum, int, String). W przeciwieństwie do Javy, twórcy Kotlina dążyli do uproszczenia gałęzi warunkowych, czyniąc je bardziej wyrazistymi i bezpiecznymi.

Problem

Ograniczenia switch-case w Javie utrudniają rozszerzanie i utrzymywanie kodu, szczególnie podczas pracy z kolekcjami, porównywaniem zakresów lub obsługą różnych typów.

Rozwiązanie

Konstrukcja when w Kotlinie jest uniwersalna: działa jako wyrażenie (może zwracać wartość), obsługuje warunki, zakresy, pojedyncze wartości, typy i łączenie warunków.

Przykład kodu:

fun describe(obj: Any): String = when (obj) { 1 -> "Jeden" in 2..10 -> "Od dwóch do dziesięciu" is String -> "String o długości ${obj.length}" else -> "Nieznany" } val res1 = describe(1) // "Jeden" val res2 = describe(5) // "Od dwóch do dziesięciu" val res3 = describe("Kotlin") // "String o długości 6" val res4 = describe(42.0) // "Nieznany"

Kluczowe cechy:

  • Możliwość pracy zarówno z wyrażeniami, jak i operatorami.
  • Sprawdzanie według wartości, typu, zakresu i złożonych warunków.
  • Zapewnienie bezpieczeństwa podczas obsługi wszystkich wariantów (np. z klasami sealed).

Pytania z podstępem.

Czy when może być używane bez argumentu?

Tak, when może być używane jako zamiennik długiego łańcucha if-else, jeśli nie trzeba sprawdzać wartości konkretnej zmiennej.

when { x < 0 -> println("Negatywny") x == 0 -> println("Zero") else -> println("Pozytywny") }

Czy blok else jest obowiązkowy w konstrukcji when?

Blok else nie jest obowiązkowy, jeśli wszystkie możliwe przypadki zostały obsłużone, na przykład, dla enum lub klas sealed. Ale jeśli istnieje prawdopodobieństwo nieobsłużonego przypadku, else jest obowiązkowy, aby uniknąć błędów podczas kompilacji.

sealed class Fruit object Apple : Fruit() object Pear : Fruit() fun check(f: Fruit): String = when (f) { Apple -> "To jest jabłko" Pear -> "To jest gruszka" // Brak bloku else, a kompilator się nie wymądrza — wszystkie warianty zostały uwzględnione }

Czy można w when używać wielu wartości w jednym przypadku?

Tak, wiele wartości można łączyć za pomocą przecinka.

when (value) { 0, 1 -> println("Zero lub Jeden") else -> println("Inne") }

Typowe błędy i antywzorce

  • Pomijanie bloku else przy niepełnych wariantach (może prowadzić do błędów w czasie wykonania).
  • Przeciążenie when zbyt skomplikowanymi gałęziami (naruszenie czytelności).
  • Używanie when tylko jako switch-case, bez stosowania sprawdzania typów i zakresów.

Przykład z życia

Negatywny przypadek

W systemie płatniczym switch-case jest używany do określenia statusu operacji. Przy dodawaniu nowego typu statusu zapomniano zaktualizować switch. Nieobsłużony status prowadzi do silent-error.

Zalety:

  • Szybka realizacja zmian przy niewielkiej liczbie statusów.

Wady:

  • Brak gwarancji, że wszystkie statusy są uwzględnione.
  • Niejawne silent-błędy przy pojawieniu się nowych wartości.

Pozytywny przypadek

W Kotlinie używana jest klasa sealed do statusów i konstrukcja when do ich obsługi. Przy dodawaniu nowego statusu kompilator wymaga dodania obsługi nowego przypadku.

Zalety:

  • Bezpieczna obsługa wszystkich statusów.
  • Błąd kompilacji przy pominięciu przypadku.

Wady:

  • Konieczność starannego aktualizowania klasy sealed podczas rozbudowy systemu.