i want to know what difference 'by lazy' between '= lazy' in kotlin
val host by lazy { ... }
val host = lazy { ... }
in my android code
val host by lazy {
supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
}
has succeed
but this code
val host = lazy {
supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
}
has failed
For efficient memory management, Kotlin has introduced a new feature called as Lazy initialization. When the lazy keyword is used, the object will be created only when it is called, otherwise there will be no object creation.
In the above code, you can see that the object of the HeavyClass is created only when it is accessed and also the same object is there all over the main() function. Lazy is mainly used when you want to access some read-only property because the same object is accessed throughout.
The concept of lazy evaluation is all about evaluating expressions only if and when it becomes necessary at runtime. This is in contrast to eager evaluation, where every expression is eagerly evaluated even if the result or part of it is never used.
The lateinit keyword allows you to avoid initializing a property when an object is constructed. If your property is referenced before being initialized, Kotlin throws an UninitializedPropertyAccessException , so be sure to initialize your property as soon as possible.
The lazy { ... }
part specifies a function that returns a Lazy<T>
.
If you just say val foo = lazy { "bar" }
, then any get or set operation will operate on the Lazy<String>
instance.
When you use val foo by lazy { "bar" }
, you're telling the compiler to delegate any get or set operation on foo
to the String
.
If we have this:
class Test {
val usingAssign = lazy {
"bar"
}
val usingBy by lazy {
"bar"
}
}
and we look at the corresponding Java code it will look something like this:
private final Lazy usingAssign;
private final Lazy usingBy$delegate;
public final Lazy getUsingAssign() {
return this.usingAssign;
}
public final String getUsingBy() {
Lazy var1 = this.usingBy$delegate;
KProperty var3 = $$delegatedProperties[0];
return (String)var1.getValue();
}
public Test() {
this.usingAssign = LazyKt.lazy((Function0)null.INSTANCE);
this.usingBy$delegate = LazyKt.lazy((Function0)null.INSTANCE);
}
So any attempt to read usingBy
would give us a String
, which we then could e.g. assign to another String
variable. You can't do that with usingAssign
, because its type is Lazy<String>
.
val host by lazy { ... }
This means that host property is a property enhanced by Kotlin's lazy delegate. Its value will be calculated only once when it is first accessed. Following calls only return cached result of the first call.
val host = lazy { ... }
This on the other hand means that instead of host property being enhanced by delegate it contains a lazy delegate. Since it contains the delegate object, you can access its methods such as isInitialized() or access value of the delegate which will trigger its computation.
Consider following example:
val host = lazy {
println("computed!")
"Hello"
}
fun main() {
println(host)
println(host.value)
println(host)
}
Here we have a lazy delegate host
. If you try to print its value you will get: "Lazy value not initialized yet.". But once you access its value it behaves the same as with by lazy {...}
by lazy
means, that the logic will be executed upon the first use
lazy properties: the value gets computed only upon first access
when you use
val host = lazy {
supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
}
you basically assign lazy property to the host variable. So it becomes Lazy<Something>
, from which you can take value or check if its initialized.
by lazy {"test"}
-> gives String
= lazy { "test" }
-> gives Lazy<String>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With