W Kotlin, jeśli nie chcesz inicjować właściwości klasy wewnątrz konstruktora lub w górnej części ciała klasy, masz w zasadzie te dwie opcje (z odwołania do języka):
lazy () to funkcja, która pobiera lambda i zwraca instancję Lazy, która może służyć jako delegat do implementacji właściwości lazy: pierwsze wywołanie get () wykonuje lambda przekazane do lazy () i zapamiętuje wynik, kolejne wywołania get () po prostu zwraca zapamiętany wynik.
Przykład
public class Hello { val myLazyString: String by lazy { "Hello" } }
Tak więc pierwsze wywołanie i wywołania podrzędne, gdziekolwiek się znajdują, myLazyString zwrócą „Cześć”
Zwykle właściwości zadeklarowane jako niepuste muszą zostać zainicjowane w konstruktorze. Jednak dość często nie jest to wygodne. Na przykład właściwości można zainicjować przez wstrzyknięcie zależności lub w metodzie konfiguracji testu jednostkowego. W takim przypadku nie można podać w konstruktorze inicjatora o wartości innej niż NULL, ale nadal należy unikać sprawdzania wartości NULL podczas odwoływania się do właściwości wewnątrz ciała klasy.
Aby obsłużyć ten przypadek, możesz oznaczyć właściwość modyfikatorem lateinit:
public class MyTest { lateinit var subject: TestSubject @SetUp fun setup() { subject = TestSubject() } @Test fun test() { subject.method() } }
Modyfikatora można używać tylko w przypadku właściwości var zadeklarowanych w treści klasy (nie w głównym konstruktorze) i tylko wtedy, gdy właściwość nie ma niestandardowego programu pobierającego ani ustawiającego. Typ właściwości musi być różny od null i nie może być typem pierwotnym.
Jak więc właściwie wybrać jedną z tych dwóch opcji, skoro obie mogą rozwiązać ten sam problem?
źródło
lateinit
ujawnia swoje pole zaplecza z widocznością setera, więc sposoby dostępu do właściwości z Kotlin i Java są różne. Z kodu Java można ustawić tę właściwość nawetnull
bez sprawdzania w Kotlin. Dlategolateinit
nie jest do leniwej inicjalizacji, ale do inicjalizacji niekoniecznie z kodu Kotlin.Lazy
+.isInitialized()
. Myślę, że nie ma prostego sposobu na sprawdzenie takiej nieruchomości zenull
względu na gwarancję, że nie możnanull
z niej uzyskać . :) Zobacz to demo .by lazy
może spowolnić czas kompilacji lub środowisko uruchomieniowe?lateinit
celu obejścia użycianull
niezainicjowanej wartości. Poza tymnull
nigdy nie należy go używać, alateinit
wartości zerowe można wyeliminować. Tak uwielbiam Kotlin :)Oprócz
hotkey
dobrej odpowiedzi, oto jak wybieram jedną z dwóch w praktyce:lateinit
służy do zewnętrznej inicjalizacji: gdy potrzebujesz zewnętrznych rzeczy do zainicjowania wartości przez wywołanie metody.np. dzwoniąc:
Podczas
lazy
gdy używa tylko zależności wewnętrznych dla twojego obiektu.źródło
Bardzo krótka i zwięzła odpowiedź
lateinit: Ostatnio inicjuje właściwości niepuste
W przeciwieństwie do opóźnionego inicjowania, lateinit pozwala kompilatorowi rozpoznać, że wartość właściwości innej niż null nie jest przechowywana na etapie konstruktora w celu normalnej kompilacji.
leniwa inicjalizacja
by lazy może być bardzo przydatny przy implementacji właściwości tylko do odczytu (val), które wykonują leniwą inicjalizację w Kotlinie.
przez lazy {...} wykonuje inicjalizator, w którym najpierw używana jest zdefiniowana właściwość, a nie deklaracja.
źródło
Lateinit vs leniwy
późno
i) Użyj go ze zmienną zmienną [var]
ii) Dozwolone tylko w przypadku typów danych, które nie mają wartości dopuszczających wartości zerowe
iii) Kompilator obiecuje, że wartość zostanie zainicjowana w przyszłości.
UWAGA : Jeśli spróbujesz uzyskać dostęp do zmiennej lateinit bez jej inicjalizacji, zgłasza wyjątek UnInitializedPropertyAccessException.
leniwy
i) Leniwa inicjalizacja została zaprojektowana w celu zapobiegania niepotrzebnej inicjalizacji obiektów.
ii) Twoja zmienna nie zostanie zainicjalizowana, dopóki jej nie użyjesz.
iii) Jest inicjowany tylko raz. Następnym razem, gdy go użyjesz, otrzymasz wartość z pamięci podręcznej.
iv) Jest bezpieczny dla wątków (jest inicjowany w wątku, w którym jest używany po raz pierwszy. Inne wątki używają tej samej wartości przechowywanej w pamięci podręcznej).
v) Zmienna może być tylko val .
vi) Zmienna może być tylko niedopuszczalna .
źródło
Oprócz wszystkich świetnych odpowiedzi istnieje koncepcja zwana leniwym ładowaniem:
Używając go poprawnie, możesz skrócić czas ładowania aplikacji. A sposób implementacji Kotlina polega na
lazy()
tym, że ładuje potrzebną wartość do twojej zmiennej, ilekroć jest potrzebna.Ale Lateinit jest używany, gdy masz pewność, że zmienna nie będzie pusta ani pusta i zostanie zainicjowana przed użyciem jej -eg w
onResume()
metodzie dla Androida- i dlatego nie chcesz deklarować jej jako typu zerowalnego.źródło
onCreateView
,onResume
a drugi zlateinit
, ale czasami nie wystąpiły błędy (ponieważ niektóre wydarzenia zaczął wcześniej). Możeby lazy
może dać odpowiedni wynik. Używamlateinit
dla zmiennych niepustych, które mogą się zmieniać podczas cyklu życia.Powyżej wszystko jest poprawne, ale jedno z faktów proste wyjaśnienie LAZY ---- Są przypadki, kiedy chcesz opóźnić utworzenie instancji swojego obiektu do jego pierwszego użycia. Ta technika jest znana jako leniwa inicjalizacja lub leniwa instancja. Głównym celem leniwej inicjalizacji jest zwiększenie wydajności i zmniejszenie zużycia pamięci. Jeśli utworzenie instancji tego typu wiąże się z dużymi kosztami obliczeniowymi, a program może w rzeczywistości z niej nie skorzystać, warto opóźnić lub nawet uniknąć marnowania cykli procesora.
źródło
Jeśli używasz kontenera Spring i chcesz zainicjować pole fasoli innej niż zerowa,
lateinit
ma wartości lepiej się nadaje.źródło
@Autowired lateinit var myBean: MyBean
Jeśli używasz niezmiennej zmiennej, lepiej zainicjować za pomocą
by lazy { ... }
lubval
. W takim przypadku możesz być pewien, że będzie on zawsze inicjowany w razie potrzeby i maksymalnie 1 raz.Jeśli potrzebujesz zmiennej innej niż null, która może zmienić jej wartość, użyj
lateinit var
. W rozwoju Android można później zainicjować w takich imprezach jakonCreate
,onResume
. Należy pamiętać, że jeśli wywołasz żądanie REST i uzyskasz dostęp do tej zmiennej, może to prowadzić do wyjątkuUninitializedPropertyAccessException: lateinit property yourVariable has not been initialized
, ponieważ żądanie może zostać wykonane szybciej niż inicjalizacja tej zmiennej.źródło