Chapter 4
- Interfaces in Kotlin are similar to Java’s but can contain default implementations and properties.
- All declarations are
final
andpublic
by default. - To make a declaration no-
final
, mark it asopen
. internal
declarations are visible in the same module.- Nested classes aren’t inner by default. Use the keyword
inner
to store a reference to an outer class. - A
sealed
class can only have subclasses nested in its declaration. - Initializer blocks and secondary constructors provide flexibility for initializing class instances.
- You use the
field
identifier to reference a property backing field from the accessor body. - Data classes provide compile-genereated
equals()
,hashCode()
,toString()
,copy()
, and other methods. - Class delegation helps to avoid many similar delegating methods in your code.
- Object declaration is Kotlin’s way to define a singleton class.
- Companion objects(along with package-level functions and properties) replace Java’s static methods and field definitions.
- Companion objects, like other objects, can implement interfaces or have extension functions or properties.
- Object expressions are Kotlin’s replacement for Java’s anonymous inter classes, with added power such as the ability to implement multiple interfaces and to modify the variables defined in the scope where the object is created.
Chapter 5
- Lambdas allow you to pass chunks of code as parameters to methods.
- Kotlin lets you pass lambdas to methods outside of parentheses and refer to a single lambda parameter as
it
. - Code in a lambda can access and modify variables in the function containing the call to the lambda.
- You can create references to methods, constructors, and properties by prefixing the name of the function with ::, and pass such references to methods instead of lambdas.
- Most common operations with collections can be performed without manually iterating over elements, using functions such as
filter
,map
,all
,any
, and so on. - Sequences allow you to combine multiple operations on a collection without creating collections to hold intermediate results.
- You can pass lambdas as arguments to methods that take a Java functional interface ( an interface with a single abstract methods, also known as SAM interface) as a parameter.
- Lambdas with receivers are lambdas in which you can directly call methods on a special receiver object.
- The
with
standard library function allows you to call multiple methods on the same object without repeating the reference to the object.apply
lets you construct and initialize any object using a builder-style API.
Chapter 6
- Kotlin’s support of nullable types detects possible
NullPointerException
errors at compile time. - Kotlin provides tools such as safe calls(?.), the Elvis operator(?:), not-
null
assertions(!!), and thelet
function for dealing with nullable types concisely. - The
as?
operator provides an easy way to cast a value to a type and to handle the case when it has a different type. - Types coming from Java are interpreted as platform types in Kotlin, allowing the developer to treat them as either nullable or non-
null
. - Types representing basic numbers (such as
Int?
) correspond to boxed primitive types in Java(such asjava.lang.Integer
). - The
Any
type is a supertype of all other typess and is analogous to Java’sObject. Unit
is an analogue ofvoid
. - The
Nothing
type is used as a return type of functions that don’t terminate normally. - Kotlin uses the standard Java classes for collections and enhances them with a distinction between read-only and mutable collections.
- You need to carefully consider nullability and mutability of parameters when you extend Java classes or implement Java interfaces in Kotlin.
- Kotlin’s
Array
class looks like a regular generic class, but it’s compiled to a Java array. - Arrays of primitive types are represented by special classes such as
Intarray
.
Chapter 7
- Kotlin allows you to overload some of the standard operations by defining functions with the corresponding names, but you can’t define your own operators.
- Comparison operators are mapped to calls of
equals
andcompareTo
methods. - By defining functions named
get
,set
, andcontains
, you can support the[]
andin
operators to make your class similar to Kotlin collections. - Creating ranges and iterating over collections also work through conventions and arrays.
- Destructuring declarations let you initialize multiple variables by unpacking a single object, which is handy for returning multiple values from a function. They work with data classes automatically, and you can support them for your own classes by defining
functions namedcomponentN()
. - Delegated properties allow you to reuse logic controlling how property values are stored, initialized, accessed, and modified, which is a powerful tool for building frameworks.
- The
lazy
standard library function provides an easy way to implement lazily initialized properties. - The
Delegates.observable
function lets you add an observer of property changes. - Delegated properties can use any map as a property delegate, providing a flexible way to work with objects that have variable sets of attributes.
Chapter 8
- Function types allow you to declare a variable, parameter, or function return value that holds a reference to a function.
- Higher-order functions take other functions as arguments or return them. You can create such functions by using a function type as the type of a function parameter or return value.
- When an inline function is compiled, its bytecode along with the bytecode of a lambda passed to it is inserted directly into the code of the calling function, which ensures that the call happens with no overhead compared to similar code written directly.
- Higher-order functions facilitate code reuse within the parts of a single component and let you build powerful generic libraries.
- Inline functions allow you to use
non-local returns
—return expressions placed in a lambda that return from the enclosing function. - Anonymous functions provide an alternative syntax to lambda expressions with different rules for resolving the
return
expressions. You can use them if you need to write a block of code with multiple exit points.
Chapter 9
- Kotlin’s generics are fairly similar to those in Java: you declare a generic function or class in the same way.
- As in Java, type arguments for generic types only exist at compile time.
- You can’t use types with type arguments together with the
is
operator, because type arguments are erased at runtime. - Type parameters of inline functions can be marked as reified, which allows you to use them at runtime to perform
is
checks and obtainjava.lang.Class
instances. - Variance is a way to specify whether the type parameter of a type can be substitued for its subclass or superclass.
- You can declare a class as covariant on a type parameter if the parameter used only in
out
positions. - The oppsite is ture for contravariant cases: you can declare a class as contravariant on a type parameter if it’s used only in
in
positions. - The read-only interface
List
in Kotlin is declared as covariant, which meansList<String>
is a subtype ofList<Any>
. - The function interface is declared as contravariant on its first type parameter and covariant on its seconds, which makes
(Animal) -> Int
a subtype of(Cat) -> Number
. - Kotlin lets you specify variance both for a generic class as a whole (
declaration-site variance
). - The start-projection syntax can be used when the exact type arguments are unknown or unimportant.