Introduction of language
Programming languages can be broadly divided into two categories: compiled and interpreted.
Compiled languages are characterized by the fact that the compiler will compile the source code we write once into a binary file that the computer can recognize, and then the computer executes it directly. C/C++ are all compiled languages.
Interpreted languages are usually less efficient because they have an interpreter that reads our source code line by line as the program runs and then interprets it in real time into binary data that the computer can read. Languages like Python and JavaScript are interpreted.
Java is an interpreted language. Instead of a computer-readable binary, Java code is compiled to produce a special class file that only the Java Virtual machine (or ART in Android) can recognize. The Java virtual machine acts as an interpreter, interpreting the compiled class files into computer-readable binary data before executing the program.
Kotlin also works on top of the Java virtual machine, because the JVM recognizes class files that conform to the specification, so Kotlin only needs to compile the code into class files of the same specification using his own compiler.
Kotlin’s advantages include a cleaner syntax, less code, more advanced syntax, improved security (such as virtually eliminating null Pointers), and full Java compatibility.
Variables and functions
package com.example.myhelper
/** * File is usually used to write Kotlin top-level functions and extension functions. * man function, the entry function of the program. * /
fun main(a){
println("Hello Kotlin")}Copy the code
variable
Because Kotlin has an excellent type derivation mechanism, there are only two keywords: val and var.
- Val (short for value) : Used to declare an immutable variable that cannot be reassigned after initial assignment.
- Var (short for variable) : Declares a mutable variable that can be reassigned after the initial assignment.
// Unlike Java, semicolons are not required
fun main(a){
val a = 10
println("a = " + a)
// In some cases, such as delayed assignment of a variable, the type inference mechanism does not work properly and requires an explicit declaration of the variable type
Int represents a class, which has its own methods and inheritance structure, and is an object data type. Unlike Java, where int is a basic data type, int is a keyword.
val b : Int = 20
println("b = " + b)
}
Copy the code
In Java, it is a good programming practice to add the final keyword to a variable unless it is explicitly allowed to be modified. In Kotlin, val can always be used first to declare a variable, and var can be used when val fails to meet the requirements.
function
A function is a vehicle for running code. For functions and methods, it’s the same concept. It’s just that the way methods are called in Java is more common, and the way functions are called in Kotlin is more common.
// fun(short for function) defines the keyword of the function.
// the param parameter name can be omitted.
// The last Int represents what type of data the function returns. If no, no data is returned.
fun methodName(param1: Int,param2: Int): Int{
/ / the function body
// AS code completion will automatically guide the package.
return max(param1,param2)
}
Copy the code
Syntactic sugar
/ / syntactic sugar
// If there is only one line of code in a function, write it directly at the end of the function definition
fun largerNumber(num1: Int,num2: Int): Int = max(num1,num2)
// Because of the type inference mechanism, it is not necessary to explicitly declare the return value type.
fun largerNumber2(num1: Int,num2: Int) = max(num1,num2)
Copy the code
Logic control
Conditional statements in Kotlin are implemented in two main ways: if and when.
If conditional statement
fun largerNumber3(num1: Int,num2: Int): Int {
In contrast to Java, the if statement can have a return value.
// Since there is no reassignment involved, the val keyword can be used.
// val value = if (num1 > num2){
// num1
// }else{
// num2
/ /}
// return value
return if (num1 > num2){
num1
}else{
num2
}
}
fun largerNumber4(num1: Int,num2: Int): Int = if (num1 > num2){
num1
}else{
num2
}
fun largerNumber5(num1: Int,num2: Int): Int = if (num1 > num2) num1 else num2
Copy the code
When statement
Similar to the Switch statement in Java, but more flexible.
fun getScore(name: String) = if (name == "Tom") {86
}else if (name == "Jim") {77
}else if (name == "Jack") {95
}else if (name == "Lily") {100
}else{
0
}
The /** * when statement allows you to pass in any type of argument. * Then define a series of conditions in the structure in the form: * Match values -> {execute logic} * {} can be omitted when the execute logic has only one line of code. * /
fun getScore2(name: String) = when(name){
"Tom" -> 86
"Jim" -> 77
"Jack" -> 95
"Lily" -> 100
else -> 0
}
In addition to exact matching, type matching is allowed with the * is keyword equivalent to the Java instanceof keyword */
fun checkNumber(num: Number){
when(num){
is Int -> println("number is Int")
is Double -> println("number is Double")
else -> println("number is support")}}/** * when is not used. * /
fun checkNumber(name: String) = when{
// Everything that begins with Tom is 86
name.startsWith("Tom") - >86
// In Kotlin, you can use the == keyword to determine whether strings or objects are equal
name == "Jim" -> 77
name == "Jack" -> 95
name == "Lily" -> 100
else -> 0
}
Copy the code
Looping statements
Kotlin provides while and for loops. The use of while is consistent with Java. (While condition can’t perform assignment?)
fun main(a){
/ / the for - in circulation
// Interval concept:.. Is the key to create a closed interval at both ends
// var range = 0.. 10 is the closed interval between 0 and 10.
// the printed result: 0,1,2,3,4,5,6,7,8,9,10
for (i in 0.10.) {// sout quick println()
println(i)
}
// Until indicates the interval between left and right
// More commonly used, such as arrays of length 10, whose subscripts range from 0 to 9.
// the printed result: 0,1,2,3,4,5,6,7,8,9
for (i in 0 until 10){
println(i)
}
// step keyword: increments the range by 2 each time the loop is executed
// this is equivalent to the effect of I = I + 2 in the Java for-i loop
// print the result: 0,2,4,6,8
for (i in 0 until 10 step 2){
println(i)
}
// downTo: closed interval at both ends in descending order
// the printed result: 10,9,8,7,6,5,4,3,2,1,0
for (i in 10 downTo 0){
println(i)
}
}
Copy the code
Object-oriented programming
Unlike procedural languages such as C, object-oriented languages can be used to create classes. Class is a kind of encapsulation of things, everything is an object, can be encapsulated. Classes also include class names (common nouns), fields (common nouns), functions (common verbs), etc., representing the name of the class, the properties it owns, and what actions it has.
Classes and objects
class Person {
/** * We use the var keyword because we need to specify the value after the object is created. * After the val keyword is used, it cannot be reassigned after initialization. * /
var name = ""
var age = 0
fun eat(a){
println(name + " is eating。He is " + age + "Years old.")}}Copy the code
fun main(a){
// Kotlin has eliminated unnecessary syntactic constructs such as new and end-of-line semicolons, following the simplest design principles.
// Assign the instantiated class to the p variable
// p can be called either an instance of the Person class or an object.
val p = Person()
p.name = "Jack"
p.age = 19
p.eat()
}
Copy the code
inheritance
/** * Any non-abstract class in Kotlin is not inherited by default, for much the same reason as the val keyword. * An abstract class cannot create an instance by itself. It must be inherited by subclasses to create an instance, so it must be inheritable to make sense. The * * open keyword means that the class is designed specifically for inheritance. * /
open class Person {}Copy the code
The Person class uses the open keyword. The Student class uses the colon. The primary and secondary constructors are inherited */
class Student : Person() {
var sno = ""
var grade = 0
}
Copy the code
The constructor
Kotlin divides constructors into two types: primary constructors and secondary constructors.
By default, each class has a primary constructor that takes no arguments. The primary constructor has no function body and is defined directly after the class name.
class Student(val sno: String,val grade: Int) : Person() {
init {
// The logic of the main constructor}}Copy the code
fun main(a){
val student = Student("a123".5)}Copy the code
Referring to the inheritance feature in Java, constructors in a subclass must call constructors in a parent class.
In Kotlin, too, parentheses () are used to specify which constructor of the parent class to call. For example, Person() refers to calling the no-argument constructor of parent Persion.
open class Person(val name:String,val age:Int) {}Copy the code
/** * where name and age are not declared with keywords. * Since the arguments declaring val or var in the primary constructor automatically become fields of the class, this will cause conflicts with the name and age fields of the same name in the parent class. * Therefore, there is no need to add any keywords, so that its scope is limited to the main constructor. * /
class Student(val sno: String,val grade: Int,name:String,age:Int) : Person(name,age) {
}
Copy the code
fun main(a){
val student = Student("a123".5."Jack".19)}Copy the code
The secondary constructor is rarely used, and Kotlin provides a function that sets default values for parameters of functions, basically replacing the role of the secondary constructor.
Any class can have only one primary constructor, but can have more than one secondary constructor. The secondary constructor can also be used to instantiate a class, differing from the primary constructor in that it has a body.
Kotlin states that when a class has both primary and secondary constructors, all secondary constructors must call the primary constructor (including indirect calls).
The constructor keyword defines the subconstructor */
class Student(val sno: String,val grade: Int,name:String,age:Int) : Person(name,age) {
/** * Calls the primary constructor * with this keyword and assigns the sno and grade arguments to their initial values */
constructor(name: String,age: Int) :this("".0,name,age){
}
/** * calls the first subconstructor defined above with this keyword and assigns name and age to initial values. * Since this subconstructor indirectly calls the primary constructor, it is also a valid subconstructor. * /
constructor() :this("".0) {}}Copy the code
fun main(a){
val student1 = Student()
val student2 = Student("Jack".19)
val student3 = Student("a123".5."Jack".19)}Copy the code
A very special case where a class has only a secondary constructor and no primary constructor.
/** * A class does not have a primary constructor when it does not explicitly define a primary constructor and when it defines a secondary constructor. * Also, since there is no main constructor, there is no need to add parentheses when inheriting from the Person class. * /
class Student : Person {
/** * Since there is no primary constructor, the secondary constructor can only call the parent constructor directly, * so this keyword is replaced with the super keyword */
constructor(name:String,age:Int) :super(name,age){
}
}
Copy the code
interface
Interfaces are an important part of implementing polymorphic programming. Like Java, the Kotlin class has a single-inheritance, multi-interface structure.
A set of abstract behaviors can be defined in an interface and then implemented by concrete classes.
/** * Interface functions do not require a function body */
interface Study {
fun readBooks(a)
fun doHomework(a)
* If a function in an interface has a function body, the contents of that function body are its default implementation. * This function is not enforced by the concrete class and can be optionally implemented. If it is not implemented, the default implementation logic is automatically used. * /
fun eat(a){
println("eat")}}Copy the code
/** * In Kotlin, inheritance and interfaces are separated by a colon and a comma. * You do not use parentheses after an interface because it has no constructor to call. * /
class Student(name:String, age:Int) : Person(name,age), Study {
/** * Override a function in a parent class or implementation interface using the override keyword. * /
override fun readBooks(a) {
println(name + "is reading.")}override fun doHomework(a) {
println(name + "is doing homework.")}}Copy the code
fun main(a){
val student = Student("Jack".19)
// Polymorphic programming features
// Since the Student class implements the Study interface, instances of the Student class can be passed to this function.
doStudy(student)
}
fun doStudy(study: Study){
study.readBooks()
study.doHomework()
study.eat()
}
Copy the code
The visibility modifier of a function
The modifier | Java | Kotlin |
---|---|---|
public | All classes visible | All classes visible (default) |
private | Current class visible | Current class visible |
protected | The current class, subclass, and class under the same package path are visible | The current class and subclass are visible |
default | Classes visible under the same package path (default) | There is no |
internal | There is no | Classes in the same module are visible |
Data classes
Declaring the data keyword before a class indicates that the class is a data class. Kotlin automatically generates equals(), hashCode(), toString() and other fixed methods with no real logical meaning based on the arguments in the main constructor.
Note: equals() is used to determine whether two data classes are equal. HashCode (), a companion method to equals(), also needs to be overridden to prevent HashMap, HashSet, and other hash related system classes from working properly. ToString () is used to provide a clearer input log, otherwise a data class defaults to printing a line of memory addresses.
/** * When there is no code in the class, the trailing braces can be omitted. * /
data class Cellphone(val brand:String,val price:Double)
Copy the code
fun main(a){
val cellphone1 = Cellphone("Samsuing".1299.99)
val cellphone2 = Cellphone("Samsuing".1299.99)
println(cellphone1)
println("cellphone1 equals cellphone2 "+(cellphone1 == cellphone2))
// Result with data keyword:
/ / Cellphone (brand = Samsuing, price = 1299.99)
// cellphone1 equals cellphone2 true
// Result without data keyword:
// com.example.myhelper.Cellphone@5e2de80c
// cellphone1 equals cellphone2 false
}
Copy the code
Singleton class
/** * In Kotlin, just replace the class keyword with the object keyword. * This completes a singleton class. * /
object Singleton {
fun singletonTest(a){
println("singletonTest is called")}}Copy the code
fun main(a){
// Call a function in a singleton class
// It looks like a static method call, but in fact it automatically creates an instance for us and makes it globally unique.
Singleton.singletonTest()
}
Copy the code
Lambda programming
Collection creation and traversal
fun main(a){
// About the usage of List:
// More verbose
val list = ArrayList<String>()
list.add("Apple")
list.add("Orange")
// Kotlin provides a built-in listOf() function to simplify the way to initialize collections
The listOf() function creates an immutable collection that can only be read.
val list2 = listOf("Apple"."Orange")
// Use a for-in loop to iterate over the collection
for (fruit in list2){
println(fruit)
}
The mutableListOf() function creates a mutable collection
val list3 = mutableListOf("Apple"."Banana")
list3.add("Pear")
for (fruit in list3){
println(fruit)
}
SetOf() and mutableSetOf().
// The hash mapping mechanism is used at the bottom of the Set to store the data, so the elements in the Set cannot be guaranteed to be ordered.
// About Map usage:
// More broadly, maps are key-value data structures that can also be considered collections.
// Traditional usage
val map = HashMap<String,Int>()
map.put("Apple".1)
map.put("Pear".2)
// Kotlin does not recommend using put() and get() to manipulate data, but rather an array-like subscript syntax.
map["Banana"] = 3
// Read data
val number = map["Banana"]
println(number)
// Kotlin provides simpler functions
// To is not a keyword, but an infix function.
val map2 = mapOf("Apple" to 1."Banana" to 2)
// Declare the Map key-value variables in a pair of parentheses
for ((fruit,number) in map2){
println("fruit is " + fruit + ", number is " + number)
}
}
Copy the code
The functional API for collections
The functional API for collections is an excellent example for getting started with Lambda programming.
In plain English, a Lambda is a small piece of code that can be passed as an argument. Kotlin has no limit on the amount of code that can be passed, but it is generally not recommended to write too long code in expressions because it might affect the readability of the code. The most complete syntax for a Lambda expression is defined as follows:
{parameter 1: parameter type, parameter 2: parameter type -> function body}
The outermost layer is a brace, if there are parameters passed to the expression of words, also need to declare the parameter list, at the end of the argument list to use a – > symbol, said the end of the parameter list and the beginning of the function body, the body of the function can be written in any line of code (though long code) is not recommended, and the last line of code automatically as the return value of the expression.
fun main(a){
// The most complete syntax structure for a Lambda expression
// {parameter 1: parameter type, parameter 2: parameter type -> function body}
val list2 = listOf("Apple"."Orange")
val lambda = {fruit: String -> fruit.length}
val maxLengthFruit3 = list2.maxBy(lambda)
// Simplification 1: You don't have to define a variable
val maxLengthFruit4 = list2.maxBy({fruit: String -> fruit.length})
// Simplification two: Kotlin states that when a Lambda argument is the last argument to a function, the expression can be moved outside the function's parentheses
val maxLengthFruit5 = list2.maxBy(){fruit: String -> fruit.length}
// Simplification 3: If the Lambda argument is the only argument to the function, omit the parentheses of the function.
val maxLengthFruit6 = list2.maxBy{fruit: String -> fruit.length}
// Simplification 4: Because of the type inference mechanism, parameter lists in expressions do not have to declare parameter types in most cases.
val maxLengthFruit7 = list2.maxBy{fruit -> fruit.length}
// Simplify 5: When the expression has only one parameter in the parameter list, it is not necessary to declare the parameter name.
val maxLengthFruit8 = list2.maxBy{it.length}
}
Copy the code
fun main(a){
// Find the longest word in the set
val list = listOf("Apple"."Orange"."Banana"."Pear"."Grape"."Watermelon")
var maxLengthFruit = ""
for (fruit in list) {
if (fruit.length > maxLengthFruit.length){
maxLengthFruit = fruit
}
}
println("max length fruit is " + maxLengthFruit)
// Use the collection's functional API to simplify the code
// maxBy() is a normal function that takes a Lambda argument,
// And passes the value of each iteration as an argument to the Lambda expression as the collection is traversed.
// maxBy() works by iterating through the collection based on the passed condition to find the maximum value for that condition.
val maxLengthFruit2 = list.maxBy { it.length }
println("max length fruit is " + maxLengthFruit)
The map function is one of the most commonly used functional apis
// It is used to map each element in the collection to another value,
// The rules of the mapping are specified in the Lambda representation, which eventually generates a new collection.
// For example, uppercase
val newList = list.map { it.toUpperCase() }
for (fruit in newList){
println(fruit)
}
println("-- -- -- -- -- -")
// The filter function is used to filter data in a collection. It can be used alone or in conjunction with the map function.
// Pay attention to the order of function calls. Filter first and then map, which will improve efficiency.
// Only those with length less than 5 are reserved
val newList2 = list.filter { it.length <= 5 }.map { it.toUpperCase() }
for (fruit in newList2){
println(fruit)
}
println("-- -- -- -- -- -")
The any function determines whether there is at least one element in the collection that meets the specified condition
The all function is used to determine whether all elements in a collection meet the specified criteria
val anyResult = list.any{it.length <= 5}
val allResult = list.all{it.length <= 5}
println("anyResult is " + anyResult + ",allResult is " + allResult)
/ /...
}
Copy the code
Use of Java functional apis You can also use the functional API when calling Java methods in Kotlin, but with some limitations.
Call a Java method in kotlin code that can use a functional API if it accepts only a single Java abstract method interface argument. A single abstract method interface is one in which only one method is to be implemented, such as the Runnable interface, which has only one run() method to be implemented. So for any Java method that accepts the Runnable argument, you can use the functional API.
fun main(a){
Create and execute a child thread using an anonymous class in Kotlin.
Thread(object : Runnable{
override fun run(a) {
println("Thread is running")
}
}).start()
// A simplified way to write functional apis
Since there is only one method to implement in the Runnable class, we can do this without overwriting run() explicitly
Thread(Runnable { println("Thread is running") }).start()
// If more than one Java single abstract method interface parameter does not exist in the argument list of a Java method, the interface name can be omitted.
// Erratum: We can also omit the interface name if there is only one Java single abstract method interface parameter in the argument list of a Java method
Thread({ println("Thread is running")}).start()
// When a Lambda expression is the last argument to a method, the expression can be moved out of parentheses,
// Also, the expression is the only argument to the method, and parentheses can be omitted
Thread{ println("Thread is running")}.start()
}
Copy the code
Null pointer check
Kotlin uses a compile-time null-checking mechanism to almost eliminate null-pointer exceptions.
Nullable type system
fun main(a){
doStudy(null)}/** * Kotlin by default, all parameters and variables cannot be empty * so the Study parameter passed here must not be empty ** If you want an empty parameter or variable, put a question mark after the class name. * /
fun doStudy(study: Study?). {
// Because Study can be empty, it needs to be processed
if(study ! =null){
study.readBooks()
study.doHomework()
}
}
Copy the code
Void detection AIDS
fun doStudy(study: Study?). {
// Use the question mark? The operator
// means that the corresponding method is called normally when the object is not empty, and nothing is done when the object is empty.study? .readBooks() study? .doHomework()/ / use? : operator
// This operator accepts an expression on both sides, and returns the left side if the left side is not empty.
// Otherwise return the result of the expression on the right.
getTextLength(null)
// Non-empty assertion tool, after the object!!
// Indicates that the object is absolutely certain that it will not be null, so no null pointer check is required.
// There are cases where the compiler does not know that null-pointer exceptions have been logically handled.
// Use caution.study!! .readBooks()Use let, which is a function.
// The let function of the obj object is called, and the code in the Lambda expression is immediately executed,
// And the obj object itself is passed as a parameter to the expression. Here obj and obj2 are actually the same object.
study.let { stu ->
stu.readBooks()
stu.doHomework()
}
// If there is only one parameter in the parameter list of the expression, use the it keyword instead of the parameter name.
// The let function can handle nulling of global variables,
// The value of a global variable can be modified by other threads at any time.
study.let {
it.readBooks()
it.doHomework()
}
}
/** * gets a text length */
fun getTextLength(text:String?).= text? .length ? :0
Copy the code
note
References:
The first line of code (version 3) official Chinese translation site
Welcome to follow wechat official account:No reason also