Search

7. Power Tools

์ƒ์„ฑ์ผ
2021/07/28 10:50
ํƒœ๊ทธ

7.2 Scope Functions

Scope functions create a temporary scope wherein you can access an object without using its name.
Scope functions exist only to make your code more concise and readable. They do not provide additional abilities.
There are five scope functions: let(), run(), with(), apply(), and also(). They are designed to work with a lambda and do not require an import. They differ in the way you access the context object, using either it or this, and in what they return. with() uses a different calling syntax than the others. Here you can see the differences:
There are multiple scope functions because they satisfy different combinations of needs:
โ€ข
Scope functions that access the context object using this(run(), with(), apply()) produce the cleanest syntax within their scope block.
โ€ข
Scope functions that access the context object using it(let() and also()) allow you to provide a named lambda argument.
โ€ข
Scope functions that produce the last expression in their lambda (let(), run(), and with()) are for creating results.
โ€ข
Scope functions that return the modified context object (apply() and also()) are for chaining expressions together.
with() is a regular function and run() is an extension function; otherwise they are are identical. Prefer run() for call chains and when the receiver is nullable.
Here's a summary of score function characteristics:
You can apply a scope function a nullable receiver using the safe access operator ?., which only calls the scope function if the receiver is not null:
In main(), if gets() produces a non-null result then let is invoked. The non-nullable of let becomes the non-nullable it inside the lambda.
Applying the safe access operator to the context object null-checks the entire scope, as seen in [1]-[4] in the following. Otherwise, each call within the scope must be individually null-checked:
When you use the safe access operator on let(), run(), apply() or also(), the entire scope is ignored for a null context object:

7.8 Lazy Initialization

์ง€๊ธˆ๊นŒ์ง€ ํ”„๋กœํผํ‹ฐ๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜๋Š” ๋‘ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์„ ๋ฐฐ์› ์Šต๋‹ˆ๋‹ค.
1.
Store the initial value at the point of definition, or in the constructor.
2.
Define a custom getter that computes the property for each access.
This atom explores a third use case: costly initialization that you might not need right away, or ever. For example:
โ€ข
Complex and time-consuming calculations
โ€ข
Network requests
โ€ข
Database access
This can produce two problems:
1.
Long application start-up time.
2.
Performing unnecessary work for a property that is never used, or that can have delayed access.
... ๋‚˜์ค‘์— ๋งˆ์ € ํ•™์Šต

7.9 Late Initialization

Sometimes you want to initialize properties of your class after it is created, but in a separate member function instead of using lazy.
For example, a framework or library might require initialization in a special function. If you extend that library class, you can provide your own implementation that special function.
Consider a Bag interface with a setUp() that initializes instances:
Suppose we want to reuse a library that creates and Bags and guarantees that setUp() is called. This library requires subclass initialization in setUp() instead fo in a constructor:
Suitcase initializes items by overriding setUp(). However, we can't just define items as a Stringโ€”if we do that, we must provide a non-null initializer in the constructor. Using a stub value such was an empty String is a bad practice because you never know whether it's actually been initialized. null indicates that it's not initialized.
Defining items as a nullable String? means we must check for null in all member functions, as in checkSocks(). However, we know that the library we're reusing initializes items by calling setUp(), so the null checks should not be necessary.
The lateinit property modifier fixes this problemโ€”here, we initialize items after creating an instance of BetterSuitcase:
Compare this version of checkSocks() with the one in Suitcase.kt. lateinit means items is safely defined as a non-nullable property.
lateinit can be used on a property inside the body of a class, a top-level property. or local var.
Limitations:
โ€ข
lateinit can only be used on a var property, not a val.
โ€ข
The property must be a non-nullable type.
โ€ข
The property cannot be a primitive type.
โ€ข
lateinit is not allowed for abstract properties in an abstract class or interface.
โ€ข
lateinit is not allowed for properties with a custom get() or set().
What happens if you forget to initialize such a property? You won't get compile-time or warnings, because he initialization logic might be complex and depend on other properties that Kotlin can't monitor:
This runtime exception has enough detail for you to easily discover and fix the problem. Tracking down an error reported by a null pointer exception is usually much more difficult.
.isInitialized will tell you whether a lateinit property been initialized. The property must be in your current scope. and is accessed using the :: operator.
Although you can create a local lateinit var, you cannot call .isInitialized on it because references to local vars or vals are not supported.