Make writing a habit together! This is the 13th day of my participation in the “Gold Digging Day New Plan · April More Text Challenge”. Click here for more details.

1. Tail recursive optimization

Normally we might be faced with writing recursive functions, such as:

fun test5(n: Int): Int =
    if (n == 1) {
        1
    } else
        test5(n - 1)
Copy the code

Each method corresponds to a stack frame. Recursive calls to the method will cause the stack to be too deep, and there is a risk of OOM. Kotlin provides tail-recursive features for optimization:

tailrec fun test5(n: Int): Int =
    if (n == 1) {
        1
    } else
        test5(n - 1)
Copy the code

As you can see, tail-recursive optimization is to add tailrec to a method, and the call to the recursive method should be at the end of the method. Decompile into Java code to see the effect:

You can see that the compiler optimizes recursive calls to methods.

2. Infix methodinfixThe actual combat

Infix methods add infix declarations to methods, and only one method argument can be declared, such as:

infix fun String.a(b: String) = "$this - $b"
Copy the code

Let’s explain it through a case:

We usually have one such requirement: pass in the File path String to return type File

fun makeFile(parent: String, child: String): File {
    return File(parent, child)
}
Copy the code

This is fine to write, but with infix functions we can achieve more elegant encapsulation, as follows:

infix fun String.div(child: String): File = File(this, child)
Copy the code

Use as follows:

fun makeFile(parent: String, child: String): File = parent div child
Copy the code

Parent div Child is equivalent to the implementation of File(this, child).

It’s not particularly elegant to write this way. For example, every time you have to create a File object with a div, div is too cumbersome to write and not very readable.

To solve the above two problems, we can combine the overloaded operator operator to further optimize. Let’s take a look at the common overloaded operator functions and the mapping between the corresponding operators:

expression conversion
a + b a.plus(b)
a – b a.minus(b)
a * b a.times(b)
a / b a.div(b)
a % b a.mod(b)
a.. b a.rangeTo(b)

The div function overloads the/operator, so we can change the function from String to File:

infix operator fun String.div(child: String): File = File(this, child)
Copy the code

It can then be used like this:

fun makeFile(parent: String, child: String): File = parent / child
Copy the code

As you can see, using parent/child directly creates files, and/is much more readable.