Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

what difference 'by lazy' between '= lazy' in kotlin?

Tags:

kotlin

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

like image 444
ZungTa Avatar asked Jul 24 '19 08:07

ZungTa


People also ask

What does by lazy mean in Kotlin?

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.

What is difference between lazy and Lateinit in Kotlin?

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.

What is lazy evaluation in Kotlin?

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.

What is the purpose of Lateinit?

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.


3 Answers

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>.

like image 108
Michael Avatar answered Oct 06 '22 15:10

Michael


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 {...}

like image 40
Januson Avatar answered Oct 06 '22 14:10

Januson


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>

like image 38
P.Juni Avatar answered Oct 06 '22 14:10

P.Juni