The power of being the author of a published library!
fun MutableList<Int>.swap(index1: Int, index2: Int) {
val tmp = this[index1] // 'this' corresponds to MutableList
this[index1] = this[index2]
this[index2] = tmp
}
val l = mutableListOf(1, 2, 3)
l.swap(0, 2) // 'this' inside 'swap()' will hold the value of 'l'open class C
class D: C()
fun C.foo() = "c"
fun D.foo() = "d"
fun printFoo(c: C) {
println(c.foo())
}
// prints "c"
printFoo(D())class C {
fun foo() { println("member") }
}
fun C.foo() { println("extension") }
fun run() {
C().foo() // prints member
}fun Any?.toString(): String {
if (this == null) return "null"
// after the null check, 'this' is autocast to a non-null type, so the toString() below
// resolves to the member function of the Any class
return toString()
}Calls the specified function block with this value as its receiver and returns its result.
inline fun <T, R> T.run(block: T.() -> R): R
// usage
"/var/output/foo".run {
File(this) // note we are using this, since we are using a receiver type T.()
}Calls the specified function block with this value as its argument and returns its result.
public inline fun <T , R > T.let
(block: (T) -> R ): R = block (this)
// usage
"/var/output/foo".let {
File(it)
}Calls the specified function block with this value as its receiver and returns this value.
public inline fun <T> T.apply(block: T .() -> Unit): T {
block(); return this
}
// usage
val person = Person().apply {
firstName = "Victor"
lastName = "Reventos"
}Calls the specified function block with this value as its argument and returns this value.
public inline fun <T> T.also(block: (T) -> Unit): T {
block(this); return this
}
// usage
val person = Person().also {
it.firstName = "Victor"
it.lastName = "Reventos"
}Creates a tuple of type Pair from this and that
infix fun <A, B> A.to(that: B): Pair<A, B> = Pair(this, that)
// usage
val m = mapOf ("foo" to "creating a" , "bar" to "map")Credits for this image: Elye Medium Post
inline fun <A> Future(executor: Executor = ForkJoinExecutor,
crossinline block: () -> A): CompletableFuture<A> =
CompletableFuture.supplyAsync(Supplier { block() }, executor)
// New API
val future: CompletableFuture<Int> = Future { 10 }
// ForkJoinExecutor its just an alias ForkJoinPool.commonPool()
val futureOnForkJoin = Future(ForkJoinExecutor) { 10 }
val myExecutor = Executors.newSingleThreadExecutor()
val futureWithCustomExecutor = Future(myExecutor) { 10 }
// Old API
val future: CompletableFuture<Int> = CompletableFuture.supplyAsync { 10 }
// ForkJoinExecutor its just an alias ForkJoinPool.commonPool()
val futureOnForkJoin = CompletableFuture.supplyAsync(Supplier { 10 }, ForkJoinExecutor)
val myExecutor = Executors.newSingleThreadExecutor()
val futureWithCustomExecutor = CompletableFuture.supplyAsync(Supplier { 10 }, myExecutor)inline fun <A, B> CompletableFuture<A>.map(executor: Executor = ForkJoinExecutor,
crossinline f: (A) -> B): CompletableFuture<B> =
thenApplyAsync(Function { f(it) }, executor)
// New API
val future: CompletableFuture<String> = Future { 10 }
.map { "Hello user with id: $it" }
// Old API
val future: CompletableFuture<String> = Future { 10 }
.thenApplyAsync(Function { userId -> "Hello user with id: $userId" },
ForkJoinExecutor)inline fun <A, B> CompletableFuture<A>.flatMap(executor: Executor = ForkJoinExecutor,
crossinline f: (A) -> CompletableFuture<B>): CompletableFuture<B> =
thenComposeAsync(Function { f(it) }, executor)
// New API
// Fetching the posts depends on fetching the User
val posts = fetchUser(1).flatMap { fetchPosts(it) }
// Fetching both the user and the posts and then combining them into one
val userPosts = fetchUser(1).flatMap { user ->
fetchPosts(user).map { UserPosts(user, it) }
}
// Old API
val posts: CompletableFuture<List<Post>> = fetchUser(1)
.thenComposeAsync(Function { fetchPosts(it) }, ForkJoinExecutor)
val userPosts: CompletableFuture<UserPosts> = fetchUser(1)
.thenComposeAsync(Function { user ->
fetchPosts(user).thenApplyAsync(Function { posts ->
UserPosts(user, posts)
}, ForkJoinExecutor)
}, ForkJoinExecutor)flatMap allows you to do sequential composition. Creating a new future dependent on another one.
inline fun <A> CompletableFuture<A>.filter(executor: Executor = ForkJoinExecutor,
crossinline predicate: (A) -> Boolean): CompletableFuture<A> =
map(executor) {
if (predicate(it)) it
else throw NoSuchElementException("CompletableFuture.filter predicate is not satisfied")
}
// New API
val future = Future { 10 }
// This future will succeed
val success = future.filter { it % 2 == 0 }
// This future will succeed
val success = future.filter { it % 2 == 0 }
// This future will throw NoSuchElementException
val failed = future.filter { it % 3 == 0 }
// Fetching both the user and the posts and then combining them into one
val userPosts = fetchUser(1).flatMap { user ->
fetchPosts(user).map { UserPosts(user, it) }
}
// Old API
// **** There is no filter method in CompletableFuturefilter will convert this future to a failed future if it doesn't match the predicate.
flatten
filter
zip
kotlin-futures: A collection of extension functions to make the JVM Future, CompletableFuture, ListenableFuture API more functional and Kotlin like.