PK - Chapter 4 Flashcards
# *_Define a function_* "foo" with an Int parameter and an Int return of the parameter squared.
fun foo(pInt: Int) = pInt * pInt
- the Int return value is inferred by the compiler
- can only be inferred for a single expression
# Define a function "foo" with a String parameter and a String return of the parameter contatenated with "Hello World".
fun foo(pString: String) = “${pString} and Hello World”
What is a single expression function ?
- Only has a single expression
- does not need braces
- does not need to specify the return type
- uses the “=” sign rather than the “return” keyword
Describe member functions.
- defined inside a class, object or interface
- invoked using the name of the containing class,
or object, with a dot notation - member functions can reference other functions
in the object or class, with no additional syntax - member functions can access and modify member
variables of the class
What is the DRY principle ?
Don’t Repeat Yourself
Describe Local Functions.
- also called nested functions
- declared inside other functions
- can be nested several times
- not accessible to code outside the containing function
- can access parameters and variables in the outer scope
- does not need to define the parameters or variables in the outer scope
Use local functions inside a for loop
and when clause.
fun fizzBuzz(start: Int, end: Int) { for (k in start..end) { fun isFizz() = k % 3 == 0 fun isBuzz() = k % 5 == 0 when ( isFizz() && isBuzz() -\> println("Fizz Buzz") isFizz() -\> println("Fizz") isBuzz() -\> println("Buzz") } } }
Explain top-level functions.
- defined outside any class, object or interface
- used to create standalone functions that do
not belong to any object
What are the 4 types of functions ?
- member functions
- extension functions (special case of member function)
- local functions
- top-level functions
Explain named parameters.
- when calling a function, the parameters can be named
- explicit naming makes the intent clear
- minimizes errors
- not all parameters need to be names
- once a parameter has been named, all subsequent
parameters in the signature must be named - named parameters allow the order of parameters to
be changed - cannot be used on Java-defined functions
Explain default parameters.
- can be used to define functions and constructors
- specified in the signature with the “=” sign
- can omit parameters with a default
- once a parameter is omitted, all subsequent
parameters must be omitted, unless the
parameters are named - default parameters, used with named parameters,
is very powerful and eliminates bolierplate code
for overrides - when overriding a function with default parameters,
we must keep the same function signature
Explain extension functions.
- enables you to create a new method on a class,
without extending or wrapping it - you cannot override a function in the underlying class
that has the same signature (name, parameters,
order, return) - when defined as a top-level function in another file,
it must be imported
Why create an extension function ?
* frequently used to add a function to a final class, or a class in an SDK that you do not want to extend * avoids creating subclasses, or wrappers, which would require code changes to use the new class
# Define extension function "bar{}" for class "Foo".
fun Foo.bar() = “Foo Bar !”
Explain extension function precedence.
Extension function are resolved in the following order:
- look for the method signature in the current receiver
- look in the superclass(es)
- look at the extension imports that are in scope
Create an extension function that handles nulls.
fun Any?.safeEquals(other: Any?): Boolean {
if (this == null && other == null) return true
if (this == null return false
return this.equals(other)
}
What is a member extension function ?
Extension functions are usually declared at the top level.
A member extension function is defined inside a class.
Its scope is limited and no import is required.
Give an example of a mapping receiver
versus an extension receiver.
Extension receiver is an object of the class on which the extension was defined and called.
A method in a class is called the dispatch receiver.
When there is shadowing of names, the extension receiver
will take precedence, so you must qualify the dispatch receiver.
private fun String.stringAdd() {
map.put(this@ContainerClass.hashCode(), this)
}
Create a companion object extension.
fun Int.Companion.random() : Int {
val random = Random()
return random.nextInt()
}
val int = Int.random()
Explain the types; Pair and Triple.
These contain 2 and 3 identical types, respectively.
An example of Pair…
fun getPair() = Pair(getSomeInt(), getAnotherInt())
val (firstInt, secondInt) = getPair()
val myPair = “London” to “Paris”
Explain an infix function .
- a function that is placed between 2 operands or arguments,
so can only operate on 2 arguments - first argument is the instance that the function
is invoked on - the second argument is an explicit parameter
to the function
infix fun concat(other: String) = this + other
val myConcat = “Hello “ concat “World!”
Explain operator overloading .
- the ability to define functions that use operators
- operators can only be defined as member functions
or extension functions - can also be referenced with the dot notation and
english label - can act on a different class than they are defined in
- there is a fixed list of operators that can be used as
functions, each with an English equivalent name
What is the list of basic operators
that can be overloaded ?
plus
minus
times
div
mod
rangeTo
unaryPlus
unaryMinus
not
What is the list of advanced operators
that can be overloaded ?
contains ( in )
get / set ( [] )
invoke (makes a class look like a function)
compareTo ( <, >, <=, >= )
What is the list of assignment operators
that can be overloaded ?
These are a more restrictive operators that cannot
be used in conjunction with the basic operators:
plusAssign ( += )
minusAssign ( -= )
timesAssign ( *= )
divAssign ( /= )
modAssign ( %= )
Explain functional literals.
- a variable (or val) can contain a function
- the variable can be called just like a function,
with the arguments in parenthesis - the assignment is made by enclosing the
code in braces
val printMessage = { message: String -> println(message) }
…or since there is only a single parameter…
val printMessage = { println(it) }
printMessage(“Hello World!”)
Explain tail recursive functions.
A tail recursive function can be created if:
- an invocation of a recursive function is the last operation
- the result is simply to return the call
fun fact(k: Int) : Int { tailrec fun factTail(m: Int, n: Int) : Int { if (m == 0) return n else return factTail(m - 1, m \* n) } return factTail(k, 1) }
Explain varargs.
- pass a comma-separated list of arguments, which
is wrapped into an array - use the vararg argument before the parameter name
- can only be one vararg per signature
- must be the last argument, unless subsequent
arguments are passed in using named parameters
Explain the spread operator.
If a function takes a vararg,
and you already have an array,
use the spread operator *
val strings = arrayOf(“a”, “b”, “c”)
doSomething(“First Arg”, *strings)
Future versions of Kotlin will support
collections other than arrays.
Name some of the more
common standard library functions.
- apply
- let
- with
- run
- lazy
- use
- repeat
- require / assert / check
What is a closure ?
A functional programming concept.
A function that has access to variables and
parameters defined in an outer scope.
It is said that they “close over” the variables
in the outer scope, hence the term closure.
Explain Any.apply.
- accepts a lambda
- the instance that the apply is called on
is the lambda’s receiver - used to create a builder pattern with an object
- a standard library function, not a method of Any
val task = Runnable { println(“Running!”) }
Thread(task).apply { setDaemon(true) }.start()
Describe Any.apply( ?
- Calls the specified lambda with
this
value - *as its receiver and returns
this
value.** - Use it to create a builder pattern with any object.
val task = Runnable { println(“Running”) }
Thread(task).apply { setDaemon(true) }.start()
Describe Any.let ?
- Calls the specified closure as its argument
- *and returns its result.**
- Creates a temporary variable “it” that can
- *be used in the closure**
- Can still access the outer scope with “this”
- A standard library function, not a method of Any
// need a better example
PrintWriter(“myDocument.txt”).let {
it.append(“$someVariable and some text\n”)
it.close()
}
What is the source code for Any.let ?
public inline fun T.let(block: (T) -\> R): R { contract { callsInPlace(block, InvocationKind.EXACTLY\_ONCE) } return block(this) }
What is the source code for Any.apply ?
public inline fun T.apply(block: T.() -> Unit): T {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
block()
return this
}
Describe Any.with(someObject).
- Calls the specified closure with its argument
as the current receiver - Enables you to call multiple functions on an
object without repeating the receiver each time - A standard library function, not a method of Any
val g2: Graphics2D = …
with(g2) {
stroke = BasicStroke(10F)
background = Color.BLACK
…
}
Describe Any.run .
- combines the use cases of with and let
- a closure is passed to run, which has the instance
as its current receiver - the return value of the closure is the return value of run
- a standard library function, not a method of Any
val outputPath = Paths.get(“/usr/home”).run {
val path = resolve(“output”)
path.toFile().createNewFile()
path
}
Explain “it” versus “this”.
- “this” refers to the current receiver
- “it” refers to a tighter scope temporary variable
- used by Any.also and Any.let amoung others
- used to reference a lambda’s single, unnamed parameter
- can use “it” in LINQ-style code:
strings.filter { it.length == 5 }.sortedBy { it }.map { it.toUpperCase() }
What is a higher-order function ?
A function that takes functions as
parameters, or returns a function.
interface Lock { … }
fun <t> lock(lock: Lock, body: () -> T) : T {<br></br> lock.lock()<br></br> try {<br></br> return body()<br></br> }<br></br> finally {<br></br> lock.unlock()<br></br> }<br></br>}</t>
Explain the lazy keyword.
- Wraps an expensive function call to be
invoked once, when first required - synchronization is taken care of, eliminating
race conditions or multiple requests
val lazyString = lazy { readStringFromDatabase() }
Explain the use of _underscore “_” in lambdas_.
Indicates an unused lambda parameter.
map. forEach { _, value -> println(“$value”) }
map. mapValues { (_, value) -> println(“$value”) }
Note the use of destructuring declaratios syntax
of the Pair in the second example
Explain the use keyword.
A more concise way of handling closeable
resources in simple cases.
- an extension on an instance of closeable
- accepts a function literal that operates on closeable
- will safely invoke the function, closing down the
resource afterward; whether or not the function
completed successfully
val input = Files.newInputStream(Paths.get("input.txt")) val byte = input.use( { input.read() } ) // the stream will be closed after the read
Explain the repeat keyword.
- accepts a function literal and an integer
- function will be invoked k times
repeat(howMany(), { println(“Hello”) } )
What are the
design by contract
keywords ?
Used to validate state at runtime
- require
assure arguments meet conditions
throws IllegalArgumentException if not met - assert
assure some logical condition
throws AssertionException if not met
can be disabled at runtime - check
assure that internal state meets conditions
throws IllegalStateException
Define a generic function “foo”.
fun <t> printRepeat(whatToPrint: T, repeatCount: Int) {<br></br> for (x in 0..repeatCount) {<br></br> println(whatToPrint)<br></br> }<br></br>}</t>
Note that this could have been achieved with:
repeat(repeatCount, { println(whatToPrint) } )
Define a pure function.
- deterministic (same output for same input)
- does not create any side effects
Advantages:
- can be cached
- can be parallelized
- can be tested in isolation
How does Kotlin leverage
Single Abstract Methods (SAMs)
implemented in Java.
- SAM is a Java interface that defines a single method
- there are many of these in the Java standard library
- Kotlin can convert a function literal into a SAM
val threadPool = Executors.newThreadPool(4) threadPool.submit { println("Hello World!") }
How do you handle keyword conflicts
between Java and Kotlin ?
Wrap the conflicting keyword in backticks.
var myDate: Date = …
myDate.when
(“2016”)
How does Kotlin handle
checked methods in Java ?
Kotlin does not have checked exceptions.
Java methods with checked exceptions are
treated the same as methods that do not.
How are Java void methods
handled in Kotlin ?
Treated as a function
returning Unit.
How do you use
top-level functions from Java ?
* The functions are defined as Java static methods in a class with the name of the package by default * the *@file:JvmName("MyClassName")* annotation will instead create a class named MyClassName for top-level functions in this file * the *@file:JvmMultifileClass("MyClassName")* annotation can create a class that is used for all top-level functions in the package
@file:JvmName("MyUtils") package com.company.somepackage fun cube(n: Int) : Int = n \* n \* n
How can Java use a Kotlin
function with default parameters ?
Use the @JvmOverloads annotation to
generate all the overloaded methods for Java.
@JvmOverloads fun foo(firstArg: String = “Hello”, secondArg: String = “World”) { }
Explain Any.takeIf and Any.takeUnless.
-
takeif
Returnsthis
value if it satisfies the given [predicate] elsenull
- takeUnless
Returnsthis
value if it does NOT satisfy the given [predicate] elsenull
- called on the object, so good for chaining
- standard library functions, not methods on Any
someObject?.takeIf{ booleanPredicate }?.apply { doThis() }
Summarize the following
standard library functions:
- apply
- also
- run
- let
Defining attributes:
- current receiver
- builder / mapper

What is a
Single Abstract Method (SAM) ?
- an interface that defines a
single method - only for interfaces implemented
in Java - SAMs occur frequently in the
Java standard library - you can pass a function literal
where a SAM is expected
val threadPool = Executors.newFixedThreadPool(4) threadPool.submit { println("Working hard!") }
Create a
named companion object
named “Foo” and call
its methods from Java
and Kotlin.
- often used to create singletons
- can use @JvmStatic to make the
someMethod() static
object Foo { fun someMethod() { doSomething() } }
// from Java Foo.INSTANCE.someMethod()
// from Kotlin Foo.someMethod()
How do you throw an exception
from Kotlin to Java ?
- Java only catches checked exceptions,
but there are no checked exceptions in
Kotlin - use the @Throws annotation to add the
exception to the JVM method signature
for Java
@Throws(IOException::class) fun createDirectory(file: File) { // throw IOException }