What is Kotlin?

Doctor Lin island (К о т л и н) is a Russian island, about 30 kilometers, is located in the west of st Petersburg shape is long and narrow, with east-west length about 14 kilometers, about 2 km north-south width, what is the area of 16 square kilometers, guards the Russia into from waterways. Kotlin Island built on the city of Kronstadt, under the jurisdiction of St. Petersburg city.

Kotlin is a modern programming language named after the island of Kotlin. It is a new statically typed programming language for the Java platform. This focus on interoperability with Java code can be applied almost anywhere Java is used today: server-side development, Android applications, and so on. Kotlin works well with all existing Java libraries and frameworks, and its performance is on par with Java.

According to a survey conducted by the Google developer community, about 40 percent of Android developers have used Kotlin.


Kotlin brief

  • In July 2011, JetBrains launched the Kotlin project.
  • JetBrains opened the project under the Apache 2 license in February 2012.
  • On February 15, 2016, Kotlin V1.0 (the first official stable release) was released.
  • At Google I/O 2017, Kotlin was officially hired.
  • Kotlin has now been released to V1.3. kotlinlang.org/

1. Main features of Kotlin

  • Target platform: server, Android, and wherever Java runs.
  • Static type.
  • Functional programming and object orientation
  • Free and open source

1.1 Static Type

Kotlin, like Java, is a statically typed programming language that determines the type of all expressions at compile time. Unlike Java, however, Kotlin does not require the type of every declared variable to be displayed in the source code. It has a type inference feature that allows the compiler to infer the type of a variable from the context. The following

var xOld: Int = 1 
var x = 1
var yOld: String = "string"
var y = "string"
Copy the code

1.2 Functional programming and object orientation

Before we discuss functional programming in Kotlin, let’s look at the core concepts of functional programming:

  1. First-class function: Use and pass a function as a value, either by holding it in a variable, passing it as an argument to another function, or as a return value from a function.
  2. Immutable: Use immutable objects that guarantee that their state will not change after creation.
  3. No side effects: Use pure functions that output the same results when entering the same parameters and do not change the state of other variables or interact with the outside world.

Because Kotlin’s primary goal is to provide a more concise, efficient, and secure alternative to Java, it has Java’s object-oriented features. Its rich feature set also allows it to support a functional programming style. The main features are as follows:

  • Function type: Allows functions to take other functions as arguments or return other functions.
  • Lambad expressions that use minimal boilerplate code to pass code blocks while saving on performance overhead.
  • Data class, which provides a concise syntax for creating immutable value objects.
  • The standard library provides a rich set of apis that allow you to manipulate objects and collections in a functional programming style.

Sample code:

fun main(args: Array<String>) {
    var hello: () -> Unit = { print("Hello world")}test(hello)
}

fun test(f: () -> Unit) {
    f.invoke()
}

>>>
Hello world
Copy the code
fun main(args: Array<String>) {
    var square: (Int) -> Int = { it * it }
    test(10, square)
}

fun test(i: Int, f: (Int) -> Int) {
    print(f(i))
}

>>>
100
Copy the code
// Data class User(val name:String,val age:Int)Copy the code

1.3 Free and open source

Kotlin is fully open source and freely available under the Apache2 license; The development process is completely open on Github.

Recommended development tools: IntelliJ IDEA, Android Studio, Eclipse.

2. Kotlin’s design philosophy

pragmatic

Kotlin is not a philosophical, research language but a practical language. It was created to solve many problems in the current programming world, and its features are chosen according to the scenarios encountered by many developers. The Kotlin development team is confident that Kotlin’s features can help solve real-world project problems.

Nor does Kotlin impose a particular programming style and paradigm. Since it is designed by JetBrains, Kotlin’s IntelliJ IDEA plug-in and compiler are developed simultaneously, and the language features are designed with support for the tool in mind, so there is no doubt that Kotlin’s development tool is very good for developers.

As we write Kotlin, good ides discover common code patterns that can be replaced with a more concise structure, and we can apply them to our own code by studying the language features used by the IDE.

concise

Common Java code is set to be implicit in getters, setters, and assignments of constructor arguments to variables.

var name:String = ""
var name: String
    get() {
        return name
    }
    set(value) {
        name = value
    }
Copy the code
class Person(name: String){
    init {
        print(name)
    }
}

class Student{
    constructor(name: String){
        print(name)
    }
}
Copy the code

Kotlin’s rich standard library can also replace a lot of unnecessarily verbose code.

Example: Print the first item that contains the letter B, as shown in the following list. Let’s see how Java and Kotlin implement this respectively.

List<String> list = new ArrayList<>();
        list.add("a"); . list.add("a");
        list.add("ab");
Copy the code

Java

 for (String s : list) {
            if (s.contains("b")) {
                System.out.print(s);
                break; }}Copy the code

Kotlin

 print(list.find { it.contains("b")})
Copy the code

It’s just one line of code.

One more detail to remind you of, as with many modern languages, is missing in Kotlin; Number.

Cleaner code takes less time to write and, more importantly, less time to read, which increases your productivity and helps you reach your goals faster.

security

In general, we claim that a language is secure, by which we mean that it is designed to prevent certain types of errors in a program. Kotlin borrowed some design from Java to make it more secure to use.

  • In Kotlin, there is no need to specify all type declarations, the compiler will automatically infer this, and the program runtime error rate is reduced.
  • Nullable symbols are defined in Kotlin?Is used to define whether the variable isnull
   val s: String= ""// cannot be null val s1: String? = null // Can be nullCopy the code
  • Effectively avoiding ClassCastException. In Java, when we convert an object to a certain type, we need to type check it and then convert it to that type. This exception can occur if you forget to check. In Kotlin, check and transform are merged into one operation, and when you check for compliance, no additional conversions are required to call members of that type.
    if (value is String){
          print(value.toUpperCase())
    }
Copy the code

interoperability

Adding Kotlin code to a Java project does not affect any of our Java code. At the same time, we can use Java methods and libraries in Kotlin. You can inherit Java classes, implement Java interfaces, and use Java annotations on Kotlin.

In addition, Kotlin’s interoperability makes it as easy for Java code to call Kotlin code as it is to call other Java classes and methods, and you can mix Java and Kotlin anywhere in the project.

Kotlin maximizes the use of Java libraries for greater interoperability. For example,Kotlin doesn’t have its own collections library, it relies entirely on the Java standard library, and uses additional functions to extend collections to make them easier to use in Kotlin.

Kotlin’s tools also provide full support for interoperability. You can compile any mix of Java and Kotlin source code. The two source files switch freely, and refactoring in one language will get the correct update in the other.

The two languages can be spliced together at will, as natural as breathing.

3. The Kotlin basis

3.1 variable

When declaring variables in Java:

int a = 10
Copy the code

When declaring variables in Kotlin, the parameter name and type are separated by:, and the type follows:, as we will see later in function declarations.

Val a: Int = 10 // Displays the specified variable type val a = 10 // type declaration omittedCopy the code

All variables in Kotlin must have an initial value. If not, the assignment must be completed before the variable is called by lazy initialization or lazy loading.

lateinit var name: String
Copy the code
val name by lazy { "liuxi" }
Copy the code

If you are careful, you can see that there are two types of variable declaration keywords in the above example:

  • Var — (from variable) mutable reference, corresponding to Java normal variable (non-final), the value can be changed arbitrarily, the type cannot be changed.
  • Val — (from value) immutable reference, corresponding to final variables in Java. Variables declared by val cannot be reassigned after initialization. Kotlin recommends that we use it by defaultvalDeclare variables and use them as neededvarDeclare a variable

3.1.1 Handy string template

Kotlin provides a more convenient way to concatenate strings

val name = "liuxi"
fun age() = 12
val log = "name: $name age: ${age()}"

>>>
name: liuxi age: 12
Copy the code

3.2 Function definition and invocation

Let’s take a look at Hello World from Kotlin.

Fun main(args: Array<String>){//main is the function name, () is the argument list, {} is the function bodyprint("Hello world")}Copy the code

Kotlin uses the fun keyword to define functions.

Let’s look at functions with return types:

fun max(a: Int,b: Int): Int{
    retun if (a > b) a else b 
}
Copy the code

The return type of a function is defined after:

If in Kotlin is an expression with a result value, not a statement, and is used to replace the ternary operator (Boolean) in Java. Expression 1 :(expression 2).

The difference between an expression and a statement is that an expression has a value and can be used as part of another expression.

3.2.1 Expression function body

If the body of a function consists of a single expression, the function can remove the parentheses {} and return, and use = between the function declaration and the expression.

fun max(a: Int,b: Int) = if(a > b) a elseThe content after b //= can be called the expression bodyCopy the code

Thanks to Kotlin’s excellent type derivation, we also omit the declaration of function return types in the above example.


From Kotlin to Java, many of the concepts are similar. In order to make the function more concise and readable, Kotlin borrowed from Java and made a number of changes, basically as follows:

  • Defines the syntax for named parameters, default parameter values, and infix calls.
  • Extend functions and properties to fit Java libraries.
  • Top-level functions, local functions, and attribute schema code are used.

Let’s first look at the use of named parameters, default parameter values, in Kotlin

3.2.2 Named Parameters and Default Parameter Values

Named parameters refer to the names of parameters that can be displayed when calling Kotlin’s defined function. Of course, if a function consists of multiple arguments, to avoid confusion, after you give one of the arguments a name, all subsequent arguments need to be named.

fun createAccount(account: String,password: String,desc: String){
    ...
}

create("liuxi"."123456"."cool"// Create ()"liuxi",password = "123456", desc = "cool"// call with named argumentsCopy the code

The default parameter value, as the name implies, is a parameter that supports the declaration of default values, used to avoid overloading functions.

For example, if desc is a non-essential parameter in createAccount(), we can set it to a default value.

fun createAccount(account: String,password: String,desc: String = ""){
    ...
}

createAccount("liuxi"."123456"."cool")

createAccount("liuxi"."123456"// If the user does not want to enter this parameter, we can simply omit the last parameter.Copy the code

Of course, writing default parameter values is not supported in Java, and you still need to explicitly specify all parameters when calling this method. To make this method easy to use in Java, we annotate this method with @jvmoverloads. This automatically generates an overloaded method for the method in Java.

3.2.3 Top-level functions and attributes

Top-level functions and properties were created to eliminate static utility classes from Java. The various Util utility classes in Java.

In Kotlin, we can write functions and attributes (whose function type makes them difficult to be assigned to a specific class) directly at the top of the code file (.kt), without belonging to any class. These functions and properties are still members of the package. If you want to access it from outside the package, you need an Import. Let’s create a log.kt file

package com.liuxi.fun

val KEY = "123456"

fun log(MSG :String){log.d (MSG :String){"liuxi_test", msg) 
}
Copy the code

It is convenient to use this method in Kotlin:

log("Test the top-level function")
Copy the code

In Java, the file is compiled into a class named after the file name, and the top-level functions are compiled into static functions of that class. We can also use the @jVMName annotation to customize the name of the class.

/*Java*/
package com.liuxi.fun

public class LogKt{
    
    public static final String KEY = "123456"
    
    public static void log(String msg){
        Log.d("liuxi_test", msg) 
    }
}
Copy the code

3.2.4 Extend functions and attributes

One of Kotlin’s features is smooth integration with existing code. When we encounter a mix of Java and Kotlin in a project, we can optimize it using extension functions to make it easier to use java-based features.

In theory, extension functions are member functions of a class, but they are defined outside the class. Let’s look at a TextView extension function that assigns text containing an Image to the TextView with SpannableString:

/* spanhelper.kt */ ** * replace the target String with Image ** @param mainBody * @param targetBody * @param drawableRes * @return*/ fun TextView.setTextWithImageSpan(mainBody: String? , targetBody: String? , drawableRes: Int) {if (mainBody.isNullOrEmpty() || targetBody.isNullOrEmpty() || drawableRes <= 0) {
        return
    }
    val spannableStr = SpannableString(mainBody)
    val start = mainBody.indexOf(targetBody)
    val end = start + targetBody.length
    spannableStr.setSpan(ImageSpan(context, drawableRes), start, end, Spanned.SPAN_EXCLUSIVE_INCLUSIVE)
    text = spannableStr
}
Copy the code

Example of a call to this extension method:

textView.setTextWithImageSpan("Cool"."Cool", R.drawable.icon_diamond_small)
Copy the code

In a very short line of code, we’ve set our TextView to a text containing an image. This feature is really cool

Next, let’s look at how to call extension functions in Java.

SpanHelperKt.setTextWithImageSpan(textView, "Cool"."Cool", R.drawable.icon_diamond_small)
Copy the code

Because this function is declared as a top-level function, it is compiled as a static function. TextView is used as the first argument to a static function.

There is no overwriting of extension functions; Kotlin treats them as static functions.

Let’s look at extended attributes:

Square: Int get() = toInt() * toInt() fun main(args:Array<String>){intutil.kt val Int.print(5.square)
}

>>> 25
Copy the code

Like extension functions, an extension property is like an ordinary member property of the receiver. But you must define the getter function. There is no default getter because there are no supported fields. Similarly, there’s no place to store it, so you can’t initialize it. I feel that extension attributes are similar to extension functions, but not as easy to use as extension functions.

Intutilkt.getsquare (5) >>> 25Copy the code

3.2.5 Local functions

A syntax that supports defining another function inside a function:

fun createAccount(name:String,password:String){

    fun lengthNotEnough(string:String) = string.length > 10
    
    if(lengthNotEnough(name) return
    if(lengthNotEnough(password) return
}
Copy the code

The purpose of this feature is to solve the problem of code duplication, keep the code structure as clear as possible, and improve readability.

Tip: Local functions can access arguments of outer functions.

3.3 Collection support: variable parameters, infix call, library support

3.3.1 Variable Parameters

Here is a method in collections.kt

public fun <T> listOf(vararg elements: T): List<T> = if (elements.size > 0) elements.asList() else emptyList()
Copy the code

The vararg modifier is used in Kotlin to declare that any number of parameters can be accepted.

3.3.2 Infix Invocation

A very interesting grammar candy. Here’s an example I wrote off

infix fun TextView.copy(view: TextView) {
    this.text = view.text
} 
Copy the code

We use infix to add in front of a function that takes only one argument. The above example adds infix in front of an extension function. Examples are as follows:

val textView1 = ... val textView2 = ... TextView1 copy textView2 // infix invocation, so that the contents of textView2 are copied into textView1. TextView1. Copy (textView2)// Regular writing, equivalent to infix invocation.Copy the code

Infix calls are special function calls in which no additional delimiters are added and the function name (copy) is placed directly between the target object and the argument.

3.3.3 Collection library support

The collections in Kotlin are the same as Java classes, but there are a number of API extensions to extension functions, inline functions, and so on that I won’t cover here.

Class 4.

Kotlin uses the keyword class to declare classes, just as in Java

class Person{
    
}
Copy the code

If a class does not have a class body, the curly braces above can be omitted

class Person
Copy the code

One other thing to note is that public is missing from the class declaration in Kotlin. In Kotlin, classes default to public and final

4.1 Construction method

As you know, in Java, a class can declare one or more constructors, and the same is true in Kotlin. Kotlin, however, made some changes to the constructor, introducing the primary constructor (declared outside the class for concise initialization operations) and the slave constructor (similar to Java constructors, declared inside the class body) and adding the keywords init and constructor to that effect.

The constructor keyword is used to declare a constructor.

Here is a Person class written with Java-like ideas and a new syntax defined by Kotlin

class Person{
    val name: String 
    constructor(name: String){
        this.name = name
    }
}
Copy the code

Next we introduce the concept of a primary constructor and the init keyword:

Class Person constructor(name: String){// This. Name = name}}Copy the code

As shown in the code above, init is used to indicate the block of initialization statements to be executed when the class is created, or with the main constructor h function. A class can also declare multiple blocks of initialization statements, which are executed in the order they appear in the class body.

Next, let’s simplify the Person class:

class Person constructor(name: String){
    val name: String = name
}
Copy the code

The main constructor argument can also be declared with var or val (the constructor cannot). We can further simplify our class’s property definition by using the following:

Class Person constructor(val name: String) class Person constructor(val name: String)Copy the code

If the main constructor does not have an annotation or visibility modifier, we can omit constructor.

class Person (val name: String)
Copy the code

A class in Kotlin can have a primary constructor and one or more slave constructors. The this keyword is used when a class has a master constructor and the slave constructor declared in the body of the class needs to be directly or indirectly delegated to the master constructor.

class Person(val name: String = "liuxi"){
    constructor(name: String,age: Int): this(name)
    constructor(name: String,age: Int,gender:String): this(name, age)
}
Copy the code

If you want your class not to be instantiated by other code, you can add the visible modifier private to the constructor.

class Person private constructor()
Copy the code
  • Create an instance of the class
val p = Person("liuxi")
Copy the code

Note: Kotlin does not require the new keyword to declare objects

4.2 Class inheritance structure

Let’s start with a few basic concepts:

Interface: Defined using Inerface

interface OnClickListener{
    fun onClick()
    fun test(){// a method with a default method bodyprint("Hello")}}Copy the code

Abstract classes: Use the abstract modifier

abstract class Game{
  abstract fun play()
  
  open fun record(){// The keyword open is used to indicate that the method can be overridden, and open can also be used to modify classes.print("score")
  }
  
  fun test() {print("test")}}Copy the code

Now let’s show how to inherit an abstract class. Okay

class A: Game(){
    override fun play() = print("Go play")
    
    override fun record(){super.record() // the super keyword is used to indicate a reference to the default method body of a parent class or interface, similar to Java}}Copy the code

Class A implements the interface OnClickListener:

class A: Game(), OnClickListener{
    override fun play() = print("Go play")
    
    override fun record(){super.record() //super is a reference to the default method body of a parent class or interface, similar to Java} override fun onClick() Override funtest(){
       super.test()
   }
}

Copy the code

As shown above, we implement both inheritance and implementation interfaces with: instead of using extends and implements in Java.

It is also important to note that the following class inheritance, and interface implementation is different, the name of the inherited class followed by (), which is worth class constructor. If your class declares a main constructor and has parameters, subclasses are also required to implement the main constructor. A Java-like subclass with this definition must implement the superclass constructor and pass in the parameters required for the superclass construction.

Open class A(name:String) // If A class is not abstract, it is final by default and cannot be inherited. class B(name: String): A(name)Copy the code

Open and final are two mutually exclusive definitions of keywords.

There is one more detail to note: when you override methods of the parent class or interface, they are open by default, and final is required if you don’t want your subclasses to modify them

class A: Game(), OnClickListener{
    final override fun play() = print("Go play")... }Copy the code

4.3 Data Class, Inner Class, Nested Class, and Sealed Class

Data classes

data class Person(val name)
Copy the code

Inner and nested classes

Java:

class A{
        public String name = "liuxi";

       static class B{
            void test(){ System.out.print(name); }} class C{voidtest(){ System.out.print(name); }}}Copy the code

Kotlin:

class A{
    var name = "liuxi"
    
    class B{
        fun test(){// for nested classes //printStatic class B}} inner class C{fun} static class B} inner class C{funtest(){// is a nested classprint(name) // Holds an instance of the external class}}}Copy the code

Sealed class: Defines a restricted class inheritance structure. This is a solution to the problem that the WHEN structure must implement an else branch (similar to default in the Java Switch Case). Add the sealed modifier to the parent class and all direct subclasses must be nested within the parent class.

sealed class Children{
    class Boy: Children()
    class Girl:Children()
}
Copy the code

4.4 objectThe keyword

The object keyword has three main usage scenarios in Kotlin. The core idea is that object defines a class and creates an instance of it. Next, take a look at what each of the three scenarios looks like:

  1. Use object declarations to create singletons in Kotlin: importobjectKeyword, which defines a class and its variables in one sentence. During compilation, the variable is always namedINSTANCE.
Object Utils{// Classes are not allowed to have constructors because their variables are created immediately when they are defined. Otherwise, they are just like normal classes. funtest(){
        ...
    }
    val TEST = "test"
}
Copy the code

Instead of a singleton pattern written in various styles in Java, Kotlin is easy to do with a single line of code.

Kotlin calls as follows:

Utils.test()
Utils.TEST
Copy the code

Call as follows in Java:

Utils.INSTANCE.test()
Utils.INSTANCE.TEST
Copy the code

The method in the object declaration needs to be referenced via.instance, similar to the mInstance we are used to creating in the Java singleton pattern

  1. Use of companion objects in Kotlin

Kotlin does not retain the static keyword in Java. To complement static functions and properties, Kotlin proposes companion objects, top-level functions and properties (also known as packing-level functions and properties). We’ll start with companion objects, which will be covered later.

An associated object is a common object declared in a class that can have a name, implement an interface, or have extension functions or attributes.

class Person(val name: String){
    
    companion object Loader{
        fun test(){
           ... 
        }
        
        val type:String = "simple"}}Copy the code

As shown in the example above: the companion keyword is used to mark companion objects, whose names can be omitted. A simple way to write it is as follows:

class Person{ companion object{ ... }}Copy the code

We can think of an associated object as a static object in Java. Once it is defined as an associated object, we can get calls to the object by the name of the container class. The following is an example:

Person.companion.test()
Copy the code
  1. withobjectTo implement anonymous inner classes

Object is inside the class body and can be used to declare anonymous objects (instead of the anonymous inner class usage in Java).

Common usage scenarios include declaring an interface or abstract class as an anonymous object.

Declare the common OnClikListener as an anonymous object:

view.setOnClickListener(object: OnClickListener{
    override onClick(v:View){
        
    }
})
Copy the code

5. Some cool grammar

5.1 the when

Java uses the SWICH statement to handle different situations that can occur with a value. In Kotlin we use when. It has more usage scenarios than Switch, is more powerful, is used more frequently, and works perfectly with Smart Conversion.

When, like if, is an expression that can have a return value.

For example, there is a requirement to return different drawable for ImageView depending on the VIP level.

    val imageView: ImageView = ...
    val level: Int = ...
    var imageView = imageView.setImageResource(
    when (level) {
        1 -> R.drawable.icon_level_1
        2 -> R.drawable.icon_level_2
        3 -> R.drawable.icon_level_3
        4 -> R.drawable.icon_level_4
        5 -> R.drawable.icon_level_5
        else -> {
            R.drawable.icon_level_default
        }
    })
Copy the code

The when statement returns values on different branches to setImageResource() for different levels.

It is worth mentioning that when allows multiple options to be merged on a branch. For example, we modified the example above to define 1 and 2 as up, 3 as middle, and 4 and 5 as down. We wrote the following code using when:

. When (level) {1,2 -> r.rawable. icon_level_top 3 -> r.rawable. icon_level_middle 4,5 -> r.rawable. icon_level_bottomelse -> {
            R.drawable.icon_level_default
        }
    }
Copy the code

The power of when over Switch is that it allows you to use any object as a branching condition, even no arguments. But the latter must use enumerated constants, strings, or numeric literals.

open class BaseActivity{
  ...  
}

class MainActivity: BaseActivity(){
    ...
    fun mainPrint() {print("main")
    }
}

class SettingActivity: BaseActivity(){
    ...
}

Copy the code
fun getTitle(activity: BaseActivity):String = when(activity){
    is MainActivity -> {
        activity.mainPrint()
        "main"        //ifBoth when and when can use a code block as a branch body. In the example case, the last expression in the code block is the result returned.} is SettingActivity ->"Setting"
     
     else- > {""}}Copy the code

Is: this function is used to check whether a variable is of a certain type. After checking, the compiler automatically converts the variable to the checked type. You can directly call the methods and variables under the type. It dispenses with Java’s instanceOf check casting, and the combination of type determination and casting makes our code more secure. Of course, if you still need explicit type conversions, Kotlin provides as to represent display conversions to specific types.

var a = activity as Maintivity
Copy the code

Let’s look at an example of the no-parameter notation for when.

We need to give a type definition according to the gender of the members of the two-person group. If all the members are male, it is called a boy group, if all the members are female, it is called a girl group, and if both men and women are mixed, it is called a errenzhuan.

/* const val BOY = 0 const val GIRL = 1 const val BOY_GROUP ="-"
const val GIRL_GROUP = And the women, ""
const val MIX_GROUP = "Two-renzhuan"
Copy the code

Let’s start with the if statement:

fun getGroupName(gender1: Int, gender2: Int) =
        if(gender1 ! = gender2) { MIX_GROUP }else if (gender1 == BOY) {
            BOY_GROUP
        } else {
            GIRL_GROUP
        }
Copy the code

Let’s start with the when statement:

fun getGroupName2(gender1: Int, gender2: Int) = when { gender1 ! = gender2 -> MIX_GROUP gender1 == BOY -> BOY_GROUPelse -> GIRL_GROUP
        }
Copy the code

The WHEN statement is particularly rich, similar to switch in Java but more powerful.

5.2 Kotlin’s cavitation

NullPointerException is a feature of the Kotlin type system that helps you avoid NullPointerException errors.

In Java. We meet too many too many Java lang. NullPointerException, Kotlin the method to solve such problems is to runtime exception into abnormal at compile time. By supporting controllability as part of a typology system, the compiler can detect many potential errors at compile time, reducing the likelihood of null-pointer exceptions being thrown at run time.

Here is a method to get the length of a string

fun getLength(str: String?) {// We need to mark arguments that may be null with a question markif(str == null){
        return0}return str.length
}
Copy the code

The question mark? Can be appended to any type to indicate that variables of that type can store null references. Instead of being?

Tagged variables cannot store null references. Can not be a value of a non-NULL type if you assign a value to a parameter that does not receive a null reference.

Kotlin makes a strict distinction between nullable and non-nullable types. Once your variable is nullable, operations on it are limited and you cannot call its methods unless you can prove that it is not null; Nor can it be assigned to a variable of a non-null type. Nor can you pass arguments of nullable types to functions that have arguments of non-nullable types.

So what can we do with nullable type parameters? The most important thing we can do with nullable type parameters is to compare them to NULL. Once you do the comparison, the compiler remembers it. And treat the value as non-null in the scope in which the comparison takes place (so we can call arguments and functions of non-null types), as in the example above.

Nullable and non-nullable objects are indistinguishable at run time. A nullable type is not a wrapper for a non-null type. All checks take place at the compiler. That is, nullable types using Kotlin incur no additional overhead at runtime.

5.2.1 Secure Call Operators:? .

Safe call operator? . Allows a null check and a method call to be combined into one operation.

str? .toUpperCase()if(str ! = null) str.toUpperCase()elseNull // equivalent to STR? .toUpperCase()Copy the code

The security operator calls only non-null-valued methods. The result type of the security caller is also nullable. In the example above the return type is String?

5.2.2 Elvis operator? :

The introduction of nullability means that Kotlin has many nullable types that default to NULL. To avoid the trouble of default weinull, Kotlin provides the Elvis operator? : (null merge operator)

Here’s how it works:

fun toStr(s: String?) { val str = s ? :""// If s is null, the value is assigned to""var length = s? .length ? : 0 // Common usage scenarios, used with the security call operator}Copy the code

5.2.3 Non-null assertions!!!!!

A very violent grammar! Non-null assertions are the simplest and most straightforward tool for dealing with nullable types. It USES!!!!! Double exclamation mark indicates.

var length = s!! .lengthCopy the code

When a variable that uses a non-null assertion is null, an explicit null-pointer exception is thrown. Don’t use this tool unless you are confident in your logic. A common use of non-null assertions is when you make a non-null assertion when you use a value in one function and don’t want to repeat the non-null assertion when you use the value in another function.

5.2.3 requiresletfunction

The let function makes handling nullable expressions much easier. It turns the object calling it into a lambda expression.

When used with the security call operator, the it in lambda is the non-null value of the object, nothing happens if the object is null, and the lambda expression is executed if the object is not null

str? .let{print(it.length)} /* The following is a simple format for readability */ STR? .let{ it->print(it.length)} /* The regular equivalent */if(str ! = null){print(it.length)
}
Copy the code

The it in the lambda statement generated by the let represents the non-null value of the calling object

6. Summary

This is the end of this article. The main purpose of this article is to let more developers who are interested in Kotlin, people who are entangled in Kotlin and Java, as well as those who have different ideas about Kotlin, have a brief understanding of Kotlin, and stimulate their interest in learning Kotlin. And put aside your prejudice against Kotlin. After reading this article, you should be able to use Kotlin easily

The definition of the article is the introduction, so many places are not perfect, not detailed enough. It is hoped that those who are interested in Kotlin can systematically learn the basic knowledge and advanced grammar of Kotlin in the process of learning Kotlin. The vast majority of knowledge points refer to “Kotlin combat”, recommend entry scholars read.

Some knowledge points that I wanted to write but did not add into the article (some of them are because I am not familiar with them, for fear of inaccurate description, and some of them are based on length, for fear that writing too long will scare off newcomers)

  1. Lambda expressions in Kotlin, this section is very rich in content, as well as a lot of simple and convenient syntax sugar.
  2. Kotlin basic data type, a little lazy did not write, hope you can read by yourself.
  3. Collections and arrays in Kotlin, and iteration knowledge (for, interval, sequence, map iteration, in keyword).
  4. Kotlin’s higher-order functions and generics.
  5. Coroutines are officially released in Kotlin version 1.3, so be sure to learn ~

Welcome everyone to discuss more, speak obscure or describe the problem place also requests everyone to correct, progress together ~~~~// (^v^)\~~~