• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    迪恩网络公众号

Mr-Skully/kotlin-quick-guide: A quick guide to Kotlin for developers.

原作者: [db:作者] 来自: 网络 收藏 邀请

开源软件名称(OpenSource Name):

Mr-Skully/kotlin-quick-guide

开源软件地址(OpenSource Url):

https://github.com/Mr-Skully/kotlin-quick-guide

开源编程语言(OpenSource Language):

Kotlin 100.0%

开源软件介绍(OpenSource Introduction):

Kotlin Quick Guide visitors license

This is a quick start guide to Kotlin for people with prior coding experience (in any other language). I compiled what I learned from different sources like Kotlin Koans and JetBrains Academy, as a quick reference while working on coding challenges or Android applications. This guide is in no way a complete reference to Kotlin, but it probably will be sufficient for new users. I've assumed you already know programming in some other language, so I have skipped explanations for concepts like mutability and lambda expressions. However, if you are new to such terms, a simple web search will definitely help you undertand them.

A sample Hello-World program has been included in the src directory to give you an idea of how Kotlin files and packages look like.

Table of Contents
Basic Facts
Values and Variables
Data Types
Type Conversion
Type Inference
Ranges
Regex
BigInteger
Null Safety
Conventions
Standard Input/Output
Functions and Lambda Expressions
Standard Library
Arrays
Control Flow Statements
Object Oriented Programming
Collections
Exceptions
Working With Files
References
Learn Kotlin

Basic Facts

  • Blocks of code are enclosed in curly braces, {...}

  • Each statement should start on a new line

  • There are three types of comments in Kotlin:

// This is a single line comment

/* This is an example of
   a multiline comment. */

/**
  * These are
  * documentation comments.
  */
  • &&, ||, ! and xor represent the logical operators - and, or, not and xor.

Values and Variables

  • val is used to declare read-only values.
val name = "Kotlin"
name = "Programming"   // won't work, as 'name' is read-only and cannot be reassigned
  • var is used to declare mutable variables. You can reassign the variables with values of the same type as the initial value.
var language = "English"
language = "Klingon"   // this is possible
language = 10   // won't work, as language is a String variable
  • The variables type is inferred by the compiler. This is called type inference.

  • The type of a variable can be specified, if required, while declaring it. The type should be specified if the variable is not initialized during declaration, as the compiler cannot automatically infer the type.

var name: String = "Kotlin"
val num: Int = 999
val foo   // won't work, as type can't be inferred
val character: Char
character = 'A'   // works as expected
  • If you create a variable and assign an object to it, the new variable can point to the same object as well. This is called copying by reference. In other words, the = sign does not copy the object itself, it only copies a reference to it.
val msg1 = "Hey"
val msg2 = msg1
// msg1 and msg2 will both point to a single object in memory, the String "Hey".
  • If the object is immutable, you cannot change it, but you can use another object and assign this new object to the same variable. When you reassign the variable, it will point to the new object and other variables will still point to the old object. Standard types such as strings or numbers are immutable, so it's safe to copy them by reference. The behavior of mutable objects is different. If you modify an object from one variable, the other assigned variables continue to point to that object, so they will also reflect the same changes.

  • If mutable types like lists or arrays are declared with the val keyword, the reference to the object is declared as read-only. However, the contents of the mutable type are still modifiable. In other words, if you declare a variable of type Array using val, you cannot reassign another Array to it, but you can change the values in the original Array.

  • The comparison operators == and != checks for structual equality, while === and !== checks for referential equality.

val blue = Box(3)
val green = blue   // object reference is copied
val red = Box(3)

println(blue == green)  // true
println(blue === green) // true, as both point (refer) to the same object
println(blue == red)   // true
println(blue === red)  // false, they point (refer) to different objects

var two = 2
var anotherTwo = 2

println(two === anotherTwo) // true, because the '===' equality check is equivalent to the '==' check for primitive types
two = two + 1
println(two === anotherTwo) // false
  • The val keyword implies an immutable reference to the object. The var keyword implies a mutable reference to a variable, so you can reassign it.

  • Kotlin supports prefix and postfix increment/decrement operators (++ and --) on variables.

Data Types

  • The names of Kotlin datatypes start with a capital letter.

  • Types:
    Byte: 8 bits (1 byte), Range: -128 to 127
    Short: 16 bits (2 bytes), Range: -32768 to 32767
    Int: 32 bits (4 bytes), Range: −(231) to (231)−1
    Long: 64 bits (8 bytes), Range: −(263) to (263)−1
    Float: 32 bits (4 bytes), 6-7 significant decimal digits
    Double: 64 bits (8 bytes), 15-16 significant decimal digits
    Char: 16 bits (2 bytes), represents a 16-bit Unicode character
    Boolean: size is machine-dependent
    String: size depends on the string

  • Strings are enclosed in double quotes, "...".

  • Characters are enclosed in single quotes, '_'.

  • Fractional numbers are inferred as Double by default. Explicitly specify the type, or use the suffix f or F to use Float instead.

  • Long is used by the compiler only if the value won't fit in an Int variable. To use Long with a small value, explicitly specify the type of the variable, or use the suffix l or L with the value.

  • Underscores can be used to divide the a number into blocks for easier readability. 1_000_000 is the same as 1000000.

  • Types in Kotlin are organized into a hierarchy of subtype-supertype relationships. Supertype is a type that specifies some common characteristics and rules of behavior that every subtype will follow.

  • Number is a supertype for all types that represent numeric value. For example, Int, Float and Double are subtypes of Number type.

  • The type checker of the Kotlin compiler also enforces supertype-subtype relationships. For example, to a function waiting for an argument of type Number, you can pass its subtype, Int:

fun calc(number: Number) { /*...*/ }

val number: Int = 1
calculate(number)
  • Any is a supertype for all non-nullable types in Kotlin. Any? is a supertype for Any that includes every other nullable type.

  • Unit is the equivalent of the void type found in many other programming languages. It is the return type of a function that does not return any meaningful value. If the return type of a function is not specified, it is inferred to be Unit. A return statement is not required for such functions as they are returned implicitly. Unit is also a subtype of Any.

  • Nothing is a type that has no instances, and are used in functions like fail() or expressions like throw, which doesn't return control. Any code following an expression of type Nothing is unreachable. When you call a function with a Nothing return type, the compiler won't execute any code beyond this call.

  • If you use null to initialize a value of an inferred type and there's no other information that can be used to determine a more specific type, the compiler will infer the Nothing? type:

val x = null           // type: Nothing?
val l = listOf(null, null)   // type: List<Nothing?>
  • In Kotlin, 0 is not the same as false. So you cannot assign a Int value to a Boolean variable.

  • Small errors may accumulate after operations involving Float and Double types. Generally, avoid using == in expressions involving floating-point operations.

val one = 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1
println(one) // 0.9999999999999999
// one == 1.0 will return false
  • A Char can be also created by using its hexadecimal code in the Unicode table. They are interconvertible with Int values.
val alphabet = '\u0041'     // represents 'A'
  • Int numbers can be added to characters, but the reverse is not true.
var ch = 'a'

val ch1 = ch + 1      // 'b'
val ch2 = 1 + ch      // Error

ch += 2               // 'c'
  • You can compare Char using relational operators according to their position in the Unicode table.

  • The Char class has built-in utility functions like isDigit(), isLetter(), isLetterOrDigit(), isWhitespace(), isUpperCase(), isLowerCase(), toUpperCase() and toLowerCase().

  • String has a property length that stores the number of characters in the string. Individual elements can be accessed using their indices. It also has functions like first(), last() and lastIndex() to improve readability.

val text = "Hello!"

println(text.length)      // 6
println(text.first())     // H
println(text.last())      // !
println(text.lastIndex()) // 5
  • Individual characters of a String can't be changed, because it is an immutable type.

  • String objects can be concatenated using the + operator. Values of other types can also be appended to a String using the + operator, but the expression must start with the String.

val firstName = "John"
val lastName = "Doe"
val fullName = lastName + ", " + firstName      // Doe, John
val userName = "johnny" + true + 69             // johnnytrue69
val nickname = 8 + "ball"                   // Error, as a string can't be added to an Int
  • Kotlin supports string templates. Variables can be used directly in a String by prefixing the dollar sign ($) to the variable name. Similarly, expressions can be used in a String by enclosing them in curly braces after the dollar sign.
val name = "John"

println("My name is $name.")                      // My name is John.
println("My name has ${name.length} letters.")    // My name has 4 letters.
  • The substring() method of a String accepts startIndex and lastIndex as arguments and returns the substring that starts at the startIndex and ends right before the lastIndex. If lastIndex is omitted, the default value (length of the original string) is used.

  • The substringBefore() and substringAfter() functions of String accept a delimiter as argument and return a String before/after the first occurrence of the specified delimiter. If the String does not contain the delimiter, the entire String is returned. Similarly, the substringBeforeLast() and substringAfterLast() methods return a String before or after the last occurrence of the delimiter. If a second argument is provided to these methods, it is returned if the delimiter is not found in the String.

  • The replace() method of a String replaces all occurrences of the first argument in the String with the second argument. Similarly, replaceFirst() replaces the first occurrence of the first argument with the second, and skips the rest.

  • The toLowerCase() and toUpperCase() methods of a String returns a String with its case converted accordingly.

  • The repeat() method of String allows you to repeat a String without using loops.

print("Hey".repeat(5))      // HeyHeyHeyHeyHey
  • A CharArray can be converted to a String using String(), and a String can be converted to a CharArray using the toCharArray() method. The toTypedArray() method can be used to convert an list of String to a TypedArray.
val chars = charArrayOf('A', 'B', ' ', 'C', 'D')
val text = String(chars)                                        // "AB CD"
val charsFromString = text.toCharArray()                        // { 'A', 'B', ' ', 'C', 'D' }
val words1: List<String> =  text.split(" ")                     // { "AB", "CD" }
val words2: Array<String> = text.split(" ").toTypedArray()      // { "AB", "CD" }
  • You can iterate through a String using a range of indices, array of indices, or using the characters of the String.
val text = "Hello World"

for (i in 0 until text.length) {
    print("${text[i]} ")              // H e l l o  W o r l d
}

for (index in text.indices) {
    print("${text[index]} ")          // H e l l o  W o r l d
}

for (i in text) {
    print("$i ")                      // H e l l o  W o r l d
}

Type Conversion

  • Unlike some other programming languages, there are no implicit widening conversions for numbers in Kotlin. For example, an Int variable cannot be initialized with a Short or Byte variable. A function with a Double parameter can be called only on Double values, but not Float, Int, or other numeric values. The compiler will not perform any automatic type conversion in these cases.

  • There are methods built into the datatypes for explicit type conversion. It will not affect the type of the original variables.

  • Every number type supports the following conversions:
    toByte(), toShort(), toInt(), toLong(), toFloat(), toDouble() and toChar().

  • Numbers are converted to Char and vice versa using the Unicode Table.

  • When you convert a larger type to smaller type, the value may be truncated.

  • All datatypes can be converted to a string using toString().

  • Strings can be converted to numbers if they are in the correct format of the type.

  • If the string is "true" or "false" (case insensitive), it can be converted to a Boolean using toBoolean(). Any value other than "true" will be a false Boolean.

Type Inference

  • In expressions involving variables of different datatypes, the widest type in the expression is inferred by the compiler as the type of the result.
    Double > Float > Long > Int > (Byte, Short)

  • The result of an expression involving Byte or Short variables is of the type Int (or an even larger type), unless explicitly casted.

Ranges

  • Kotlin lets you create ranges of values using rangeTo() from the kotlin.ranges package, and its operator form ...

  • a..b is a range from a to b (inclusive), and in is a keyword used to check whether a value is within a range.

if (i in 1..5) {  // equivalent of 1 <= i && i <= 5
    print(i)
}
  • If you need to exclude the right border, you should subtract one from it:
val within = c in a..b - 1
// equivalent of a <= c && c < b
  • If you need to check that a value is not within a range, use !in:
val notWithin = 100 !in 10..99   // true
  • You can assign a range to a variable and use it later somewhere in the code:
val range = 1..5
print(3 in range)   // true
  • You can also use ranges of characters and strings (in dictionary order):
println('b' in 'a'..'c') // true
println("hello" in "he".."hi") // true
  • Integral type ranges can be iterated over using for loops:
for (i in 1..5) print(i)   // 12345
  • To iterate numbers in reverse order, use the downTo function instead of ..:
for (i in 5 downTo 1) print(i)   // 54321
  • To iterate over numbers with an arbitrary step, use the step function:
for (i in 1..10 step 2) {
    print(i)   // 13579
}
  • To iterate a number range which does not include its end element, use the until function:
for (i in 1 until 10) {   // i in [1, 10), 10 is excluded
    print(i)
}

Regex

  • A regex instance can be created using the toRegex() method of a String or by calling the Regex constructor:
val string = "ing"
val regex1 = string.toRegex()
val regex2 = Regex("ing")
// regex1 and regex2 represent the same regular expression
  • matches() method of a string returns true if the string is full match for the regex specified:
val regex = Regex("ing")
val string1 = "ing"
val string2 = "running"

println(string1.matches(regex))   // true
println(string2.matches(regex))   // false
  • The dot character (.) can match any character except a newline. A question mark (?) denotes that the preceding character is optional. A double backslash (\\) is used to escape special characters. A single backslash (\) is used to escape double quotes (").

  • To match \, the regexp is \\\\.

BigInteger

  • The Java Class Library provides a BigInteger class for processing very large numbers, limited only by the memory available. It is immutable.
import java.math.BigInteger

val number1 = BigInteger("52955871795228763416553091")   // initialized using constructor
val number2 = BigInteger.valueOf(1000000000)   // initialized from a Long value using the valueOf() method
val number3 = 1234.toBigInteger()   // initialized from an Int value using the toBigInteger() method

// Some constants defined in the BigInteger class:
val zero = BigInteger.ZERO // 0
val one = BigInteger.ONE   // 1
val ten = BigInteger.TEN   // 10
  • The divideAndRemainder() function returns an array consisting of the result of integer division and its remainder.
val (result, remainder) = oneHundredTen.divideAndRemainder(nine) // 12 and 2
  • The abs() function returns a new BigInteger whose value is the absolute value of the initial BigInteger. The gcd() function returns the greatest common divisor of two numbers.
val number = BigInteger("-1")
println(number.abs()) // 1

val twelve = BigInteger.valueOf(12)
val fifteen = BigInteger.valueOf(15)
println(twelve.gcd(fifteen)) // 3

Null Safety

  • In Kotlin, the type system distinguishes between references that can hold null (nullable references) and those that can not (non-null references).

  • To allow nulls, we have to declare a variable as nullable by defining the type of the variable as <type>?.

var b: String? = "abc" // can be set null
  • You can generally handle operations using nullable variables in three ways:
    • You can explicitly check whether the variable is null.
    var a: String? = "abc"
    val l = if (a != null) a.length else -1
    • Use the safe call operator, ?..
    val b: String? = null
    println(b?.length)      // returns b.length if b is not null, and null otherwise
    // the type of this expression is Int?
    Safe calls are useful in chains. For example, if Bob (Employee) may be assigned to a Department, that in turn may have another Employee as a department head, then to obtain the name of Bob's department head (if any), we write:
    bob?.department?.head?.name     // returns null if any of the properties is null
    To perform an operation only for non-null values, you can use the safe call operator together with let:
    val listWithNulls: List<String?> = listOf("Kotlin", null)
    for (item in listWithNulls) {
      item?.let { println(it) } // prints Kotlin and ignores null
    }
    A safe call can also be placed on the left side of an assignment. If one of the receivers in the safe calls chain is null, the assignment is skipped, and the expression on the right is not evaluated at all:
    // If either `person` or `person.department` is null, the function is not called
    person?.department?.head = managersPool.getManager()
    We can also use the Elvis operator (?:) in place of an if-expression. The expression to the right of ?: is evaluated only if the left-hand side is null.
    val l = a?.length ?: -1
    // Equivalent to:
    // val l: Int = if (a != null) a.length else -1
    
    // Other examples:
    val parent = node.getParent() ?: return null
    val name = node.getName() ?: throw IllegalArgumentException("name expected")
    • The not-null assertion operator (!!) can be used to convert any value to a non-null type and throw an exception if the value is null.
    val l = a!!.length
  • Regular casting may result in a ClassCastException if the object is not of the target type. You can use safe casts that return null if the attempt was unsuccessful:
var a: String? = "abc"
val n: Int? = a as? Int     // null, as the String can't be casted to an Int type
  • If you have a collection of elements of a nullable type and want to filter non-null elements, you can use filterNotNull():
val nullableList: List<Int?> = listOf(1, 2, null, 4)
val intList: List<Int> = nullableList.filterNotNull()     // [1, 2, 4]

Conventions


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
thomasWeise/ustcSlides: My LaTeX slides packages.发布时间:2022-07-09
下一篇:
bennyhuo/KotlinBlogTranslation: Kotlin 官方博客翻译计划发布时间:2022-07-07
热门推荐
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap