Note: the current document is a summary of Kotlin’s self-study, if there is any ambiguous meaning, please advise, thank you: -).

Contents and Keywords: - Attribute - Getter & Setter Backscene field - Classification - Backscene Property - Non-compliant backscene field - compile-time constant (const) - Top layer, object expression/object declaration, no Setter, can be used for annotations - extended property - - Late attribute (lateInit) -var, no custom accessor, non-empty and cannot be a native type - Override attribute (open → override) - Entrusted property (link: https://www.kotlincn.net/docs/reference/delegated-properties.html# by attribute) - inline attribute - function/method - ordinary function variable function - - the number of arguments Infix function (infix) - extension function spending - higher-order functions spending spending - anonymous functions - an inline function inline function (https://www.kotlincn.net/docs/reference/inline-functions.html#) - Lambda functions - Lambda functions - Lambda deconstructionCopy the code

Property with Getter&Setter accessors

Non-null type attributes must be initialized in a class construct (except lateInit).

[open/override/const/lateinit] [< access modifier >] var/val < property name > [: < property type >] [= < default property value >] [< getter accessor for property >] // var/val exists [setter accessor for property >] // val does not exist, can only be initialized in the constructorCopy the code

1. Getters & Setters and background fieldsfield

  1. The system automatically defines accessors unless custom;

  2. Accessor access modifiers can be customized;

  3. The behind-the-scenes fields are in the custom accessor and do not incur call overhead;

    var param1 : String = "1" get() = this.toString() set(value) {setDataFromString(value) // Parse the String and assign values to other attributes field = value } val param2: Int = 4 get() = this.tostring ()Copy the code

2. Attribute classification

1. Behind-the-scenes properties (prerequisite – requirements do not fit the “implicit Behind-the-scenes Field” scheme)

Accessing private properties through default getters and setters is optimized so that no function call overhead is introduced.

private var _table: Map<String, Int>? = null // private attribute public val table: Map<String, Int> get() {if (_table == null) {_table = HashMap() // Type argument inferred} return _table? : throw AssertionError("Set to null by another thread") }Copy the code

2. Compile-time constants (const)

const val SUBSYSTEM_DEPRECATED: String = "This subsystem is deprecated"
Copy the code
  1. The property is in the top layer or Object member;

  2. Class using a String or other native type value;

  3. There is no getter;

  4. Can be used in annotations;

    @deprecated (SUBSYSTEM_DEPRECATED) fun foo() {...... }Copy the code

3. Override attribute (Override)

  1. Inheritance (overrideAttribute from the base classopenattribute
  2. Can only usevarcoverval, otherwise not, cannot repeat the statementsetterFunction.

4. Delay properties (LateInit)

  1. Do not want to initialize in a construct and want to avoid null checking;
  2. Requirements: must be mutable var, have no custom getters/setters, cannot be null, and cannot be a native type;
  3. Uninitialized access throws a fixed exception;

5. Extended properties – Specify type callable, statically like properties

val <T> List<T>.lastIndex: Int
    get() = size - 1
Copy the code
  1. Extended properties have no initializers and can only be provided by getters and setters

    For example: val foo. bar:Int get() = 2 // Cannot use val foo. bar = 1Copy the code
  2. Associated objects can also have extended attributes. Call method = (Java) Calls to static functions and properties

    Class MyClass {companion object {} // will be called "companion"} fun myclass.panion.foo () {// Companion object functions //...... } val MyClass.Com panion. Bar: Int the get () = 2 / / associated MyClass object extension functions and attributes of call. The foo () MyClass. BarCopy the code

6. Delegate properties

Delegate the setter and getter of a property to set or get the value.

Grammar:

Var < attribute name >: < type > by < expression >Copy the code

Inline attribute

An inline property or its accessor uses an inline modifier to mark the accessor as an inline accessor, the same as an inline function.



Function/method

  • When a function is defined, the parameter representation is Pascal representation;

  • Unit can exist as a return type that does not need to be returned explicitly or at all;

  • The single-line function body may not be surrounded by “{}”, or the return value type may be omitted explicitly;

      fun double(x: Int): Int = x * 2
      fun double(x: Int) = x * 2
    Copy the code
  • Functions can be nested within each other, and internal functions are called local functions.

  • Function overrides: subclasses override parent **open** functions must omit parameter defaults;

  • Functions can be written in attribute format, and their data types are related to the type of the passed argument and the type of the returned value, for example :(Int,String)->Boolean;

  • Functions can use generics;

    Fun <T> singletonList(item: T): List<T> { }Copy the code

Common function

1. Variable function of parameter number (vararg)

  1. Definition:

     	java:
    
     		public <T> List<T> listOf(T ... params){
     			//T ... params ->  params[N]
     			...
     		}
    
    
     	kotlin:
    
     		fun <T> listOf(vararg ts: T): List<T> {
     			//ts is a Array
     			//vararg = variable number of arguments
     			...
     		}				
    Copy the code
  2. use

    • Pass in arguments of the same type or an array of arguments to consolidate into this array using the stretch operator *;

      Val list = listOf(1,2,3) val list = listOf(*list,5,6,7,.....) // Integrate the contents of the list into list2.Copy the code

Infix function (infix)

Using the **infix modifier, a member function or extension function with only one argument ** can be represented using infix notation.

Infix fun Int. SHL (x: Int): Int {... } // use val a = 1 //val b = a (0) val b = a (0Copy the code

Extension function

  • Specifies the type of function to be called. Specifies that the type can be null for null-handling. This inside the function calls the value of the function by default.

    // The specified type can be empty fun Any? .swap(index1:Int,index2:Int){ if (this == null){ .... } } fun MutableList<Int>.swap(index1: Int, index2: Int) {val TMP = this[index1] this[index2] this[index2] = TMP} val l = mutableListOf(1, 2, 3) l.swp (0, 2) // "this" inside "swap()" gets the value of "l"Copy the code
  • Lower priority than ordinary functions of the same type;

  • Extension functions can also be overridden by inheriting open.

  • Extension functions are statically distributed, that is, they are not virtual methods based on the receiver type. This means that the extension function called is determined by the type of the expression on which the function is called, not by the result of the expression’s run-time evaluation.

    open class D {} class D1 : D() {} open class C {//D and D1 are extension receiver open fun d.foo () {println(" d.foo in C")} open fun d1.foo () {println(" d1.foo in C")} // Call the extension function fun caller(d: d) {d.foo()} Override fun d.foo () {println(" d.foo in C1")} override fun d1.foo () {println(" d1.foo in C1")}} / / C and C1 to distribute the receiver (C). The caller (D ()) / / output "D.f oo in C" C1 (). Caller (D ()) / / output "D.f oo in C1" -- virtual parsing C () distribution of the receiver. Caller (D1 ()) / / output "D.foo in C" -- extends receiver static resolutionCopy the code
    • The class object of the extension function is called the distribution receiver, virtual resolution;

    • The specified class object of the extension function is called the extension receiver and is resolved statically;

  • An associated object can also have extension functions that are called directly using the class name as a qualifier.

    Class MyClass {companion object {} // will be called "companion"} fun myclass.panion.foo () {//...... } // call myclass.foo ()Copy the code

Higher-order functions

  1. Definition:

    • Functions called by higher-order functions (Lambda functions or anonymous functions) can access/change variables in the closure (outer scope)

    • Inside a higher-order function, you can use the referenced function with the function return value name +”()” and use the higher-order function internal arguments.

    • Advantages: Reduced function definition and function nesting, not affected by generic type judgment;

    • Disadvantages: Multiple writing of anonymous functions causes code redundancy.

      Compare () fun compare(a: String, b: String): Boolean{return a.length < B.length} fun Max (collection: Collection<String>): String? { var max: String? = null for (it in collection) if (max == null || compare(max, It)) Max = it return Max} left left left left left left left left left left down down down down down down down down down left left left left left left left left left left down down down down down down down down down left left left after change left left left left left down down down down down down down left left left left left left left left left left down down down down down down down down down left left left left left left left/left/down down down down down down down down the compare () returns a value to a Boolean, you can reference function Max () : Fun compare(a: String, b: String): Boolean = a.length < b.length //Lambda high order function fun <T> Max (collection: Collection<T>, less: (T, T) -> Boolean): T? { var max: T? = null for (it in collection) if (max == null || less(max, It)) Max = it return Max} left left left left left left left left left down down down down down down down down left left left left left left left left left left down down down down down down down down down left left left left continue to simplify left left left left down down down down down down down left left left left left left left left left left down down down down down down down down down left left left left left left left left left fun down down down down down down down down down < T > compare (a: T, b: T) : Boolean{//return a.length < b.Length restricted by function parameter type return true... } //Lambda high order function fun <T> Max (collection: collection <T>, less: (T, T) -> Boolean): T? { var max: T? = null for (it in collection) if (max == null || less(max, Max (strings, {a, b -> a.length < b.length}) {if (string, b -> a.length < b.length})Copy the code
  2. use

    • To call a member function, use :: with the function name;

        fun toBeSynchronized() = sharedResource.operation()
        
        val result = lock(lock, ::toBeSynchronized)
      Copy the code
    • Incoming Lambda expression

        lock(lock,{sharedResource -> sharedResource.operation()})
        max(strings, { a, b -> a.length < b.length })
      Copy the code
    • And you can do the same thing when the last argument is a function

        lock(lock) {sharedResource -> sharedResource.operation()}
        max(strings) {a, b -> a.length < b.length }
      Copy the code
    • Use “_” when passing arguments in Lambda expressions but not using them

        map.forEach { _, value -> println("$value!") }
      Copy the code
    • Higher-order functions have only one function argument, and the parentheses in the call can be completely omitted.

        val doubled = ints.map { value -> value * 2 }
      Copy the code
    • If a higher-order function has only one argument and the argument has only one argument, omit the declaration and ->, and use only the IT field:

        val doubled = ints.map { it * 2 }
      Copy the code

Anonymous functions

Fun [< specify receives (call) type >.] (< parameter name > 1: < type >, < 2 > parameter name: < type >,...). : > < return value type} {/ / function body fun [< specify receives (call) type >.] (< parameter name > 1: < type >, < parameter name > 2: < type >,...). :< return value type > = < short function body >Copy the code

Inline functions (deformation of higher-order functions)

When higher-order functions are used, each function is referred to as an object, which generates a closure, and variables can be accessed from within the called function. Memory allocation and virtual invocation of variables introduce runtime overhead.

An inline function

  • The overhead can be eliminated by inlining Lambda function expressions. The compiler does not create a function object for the argument and generate a call. Use the inline modifier to mark the function to inline the Lambda function expression, that is, to the call.

  • Inlining can lead to an increase in generated code, but if we use it properly (without inlining large functions), it can improve performance, especially at “megamorphic” calls in loops.

    Inline fun lock<T>(lock: lock, body: () -> T): T {//...... }Copy the code

Prohibit inline

  • The noinline modifier is used when a higher-order function passes multiple function arguments and only some do not want to be inline.

  • Warning is generated when there is no inline argument function in an inline function.

  • A naked return inside a Lambda expression is not allowed unless the function passed by the Lambda expression is inline, in which case the return is called a nonlocal return.

    Fun foo() {ordinaryFunction {return error: Fun foo() {inlineFunction {return // OK: foo() {return: foo() {return: foo() {return: foo() {return: foo() {return: foo(); The lambda expression is inline}}Copy the code
  • Some inline functions may call lambda expression arguments that are passed to them not directly from the function body, but from another execution context, such as local objects or nested functions. In this case, non-local control flow is also not allowed in the lambda expression. To identify this, the lambda expression argument needs to be marked with the Crossinline modifier:

    Inline fun f(Crossinline body: () -> Unit) {val f = object: Runnable {override fun run() = body()} //... }Copy the code

Externalized type parameters


Lambda function expression

1. Lambda function expressions

Functions that return values can be expressed as Lambda expressions to be used by higher-order functions.

In higher-order functions, functions referred to as arguments are represented as attributes.

Example 1:

fun <T> max(collection: Collection<T>, less: (T, T) -> Boolean): T? { var max: T? = null for it in the collection) if (Max = = null | | less (Max, it)) Max = it return Max} / / function: fun less (x: Int, y: Int) : Boolean {return x < y} left left left left left left left left left left left left down down down down down down down down down left deformation left left left left left left left left left down down down down down down down down left left left left left left left left left fun down down down down down down down down down less (x: Int, y: Int) : Boolean = x < y left left left left left left left left left left down down down down down down down down down left left left anonymous left left left left left left left left down down down down down down down down left left left left left left left left left left down down down down down down down down down {x: Int, y: Int - > x < y} left left left left left left left left left left left left down down down down down down down down down left to do parameter left left left left left left left down down down down down down down left left left left left left left left left val down down down down down down down down down less = {x: Int, y: Int - > x < y} left left left left left left left left left left left left down down down down down down down down down left lift type left left left left left left left down down down down down down down left left left left left left left left left val down down down down down down down down down less: (Int, Int) - > Boolean = {x, y - > x < y}Copy the code

Higher-order functions have only one function argument. You can omit the “()” wrapper for the function argument.

Example 2(reverse disassembly):

Ints. Filter {val shouldFilter = > 0 / it/using it and the single parameter, you can directly see that is the function shouldFilter} left left left left left left left left left left down down down down down down down down down left left left + type left left left left left down down down down down down down left left left left left left left left left left left down down down down down down down down down Ints.filter {val shouldFilter:(Int) -> Boolean = it > 0 return@filter shouldFilter} ↓↓↓↓↓↓↓↓↓↓↓↓↓ ↓ Lambda Ints. Filter {val shouldFilter:(Int) -> Boolean ={it -> it > 0} return@filter shouldFilter} Left left left left left left left left left left down down down down down down down down down left left left to change function left left left left left down down down down down down down left left left left left left left left left left down down down down down down down down down left ints. Filter {/ / current higher-order functions only one parameter fun shouldFilter (it: Int) : Boolean {/ / internal function? Attribute within internal function return it > 0} return @ filter shouldFilter} left left left left left left left left left left left left down down down down down down down down down left function reduction left left left left left left left down down down down down down down left left left left left left left left left fun down down down down down down down down down List < Int >. The filter ( method:(Int) -> Boolean ):Boolean{ .... }Copy the code

In a Lambda expression, a higher-order function whose arguments are not used can be named with “_”.

map.forEach { _, value -> println("$value!") }
Copy the code

2. Lambda deconstruction

You can use the destruct declaration syntax for lambda expression parameters. If lambda expressions have arguments of type Pair (or map.Entry or any other type with a corresponding componentN function), then multiple new arguments can be introduced in place of a single new argument by enclosing them in parentheses:

	map.mapValues { entry -> "${entry.value}!" }
	map.mapValues { (key, value) -> "$value!" }
Copy the code

Note the difference between declaring two parameters and declaring a destruct pair instead of a single parameter:

{a / / - >... } // a parameter {a, b //->...... } // Two parameters {(a, b) //->...... } // a pair of {(a, b), c //->... } // A deconstruction pair and other parametersCopy the code

If a component of the deconstructed argument is not used, it can be replaced with an underscore to avoid fabricating its name:

	map.mapValues { (_, value) -> "$value!" }
Copy the code

You can specify the types of arguments for the entire deconstruction or specify the types of specific components separately:

	map.mapValues { (_, value): Map.Entry<Int, String> -> "$value!" }
	
	map.mapValues { (_, value: String) -> "$value!" }
Copy the code

This article is from Kotlin Language Center