kotlin

kotlin学习

参考网址:http://www.jianshu.com/p/6063dee97eca

http://blog.csdn.net/qq562029186/article/details/72519360

一、常量、变量、特殊符号的使用

1、常量的定义 val

2、变量的定义 var

3、特殊符号的使用

1)?的含义:在kotlin中单独使用?表示可为空;
如:
kotlin代码书写格式:
    var result = str?.length
java代码书写格式:
if(str == null)
    result = null;          // 这里result为一个引用类型
else
    result = str.length;    // 这里result为Int
2)!!的含义:在kotlin中表示一定不能为空;
如:
var str : String? = null
var result : Int = str!!.length
3)?:的含义:在kotlin中表示三元操作符(即三目运算符)
如:
var str : String? = null
var result = str?.length ?: -1
//等价于
var result : Int = if(str != null) str.length else -1

二、定义类

1、属性修饰符

annotation //注解类

abstract //抽象类

final //类不可继承,默认属性

enum //枚举类

open //类可继承,类默认是final的

访问权限修饰符

private //仅在同一个文件中可见

protected //同一个文件中或子类可见

public //所有调用的地方都可见

internal //同一个模块中可见

2、构造器的定义

注:kotlin中的类定义同时也是构造函数,这个时候是不能进行操作的,所以kotlin增加了一个新的关键字init用来处理类的初始化问题,init模块中的内容可以直接使用构造函数的参数。
class Person(name:String,age:int){
    init{
        //do some thiing
    }
}
翻译成java为:
final public class Person{
    public Person(String name,int age){
        init();
    }
    private void init(){
        //do some thing
    }
}

3、java中加入final为不可继承,而kotlin中定义类默认前面带有修饰符final,所以,如果想继承该类,在最前面加上open或者abstract即可。即:

open class Person(name : String, age : int) {
    init{  
        // do some thing
    } 
}

4、如果init中没有操作,则可以省略

class Person(name : String, age : int)

5、如果连参数也没有,甚至可以这么写

class Person

6、但是当构造参数中的参数、类型变化时可能需要不只是一个构造函数,需要多组构造函数来处理不同view上的数据时,使用constructor加上参数,后面用this加上主构造函数的参数。

次级构造函数
class Person(name:String){
    var a = 1
    init{
        log("This is --> primary constructor,a = $a,name = $name")
    }
    constructor(name:String,age:Int): this(name){
        log("This is --> secondry constructor,a = ${++a}, age = $age")
    }
}

// 翻译成java

final class Person{
int a = 1;
public Person(String name){
      log("This is --> primary constructor, a=$a, name=$name")
}

 public Person(String name, int age){
      this(name);
      log("This is --> secondry constructor, a=${++a}, age=$age")
 }

}

特别注意:
1)同理,如果参数全是固定值,则kotlin会默认创建一个无参数的构造函数;
2)固定值的参数在调用该构造函数时可以不用传。
3)如果P1(name,age)双参,P2(name,age,1)三参,那么kotlin中默认会调用双参的P1来执行,不会去执行P2;

三、定义函数方法

1、求和

方式一:
带有两个 Int 参数、返回 Int 的函数
fun sum(a:Int , b :Int):Int{
    return a+b;
}

fun main(args: Array<String>){
    print("sum of 3 and 5 is")
    print(sum(3,5))
}

result:sum of 3 and 5 is 8

方式二:
将表达式作为函数体、返回值类型自动推断的函数
fun sum(a:Int,b:Int) = a + b
fun main(){
    println("sum of 19 and 23 is ${sum(19,23)}")
}

result:sum of 19 and 23 is 42

方式三:
函数返回无意义的值
fun printSum(a:Int,b:Int):Unit{
    println("sum of $a and $b is ${a+b}")
}
fun main(args:Array<String>){
    printSum(-1,8)
}

result:sum of -1 and 8 is 7

方式四:
Unit 返回类型可以省略
fun printSum(a:Int,b:Int){
    println("sum of $a and $b is ${a+b}")
}
fun main(args:Array<String>){
    printSum(-1,8)
}

2、数组

使用泛型Array代替数组
Java:
public static void main(String[] args){
    // do some thing
}

Kotlin:
fun main(args : Array<String>){
   // do some thing
}

3、条件语句

fun max(a:Int,b:Int){
    if(a > b)
        return a
    else
        return b
}
//或者简写成:
fun max(a:Int,b:Int) = if( a > b) a else b

4、循环

1)for循环
使用in关键字
fun main(args:Array<String>){
    for(arg in args)
        print(arg)

    for(i in args.indices)
        print(arg[i])

    for((index,value) in args.withIndex()){
        println("index : $index,value : $value")
    }

}
2)while循环
和JAVA使用基本一致
fun main(args : Array<String>){
    var i = 0
    while(i < args.size){
        print(args[i++])
    }

    var j = 0;
    do{
        print(args[j])
    }while(++j<args.size)
}
3)when表达式
和switch用法类似
无返回值时用法:
var x = 3
when (x){
    1 -> print(1)
    2 -> print(2)
    else -> print(5)
}
有返回值
var x = 3
var result = when(x){
    1 -> 1
    2 -> 2
    else -> 5
}
处理相同分支的简写
when(x){
    0,1 -> print("x == 0 or x == 1")
    else -> print("otherwise")
}
任意表达式做分支的条件
is 表示检查一个值
in 表示范围区间
如果有多个条件同时满足,则调用第一个满足条件的分支
when(x){
    parseInt(s) -> print("s encode x")
    else -> print("s does not encode x")
}
fun parseInt(str : String) = str.toInt()

when(x){
    in 1..10 -> print("x is in the range")
    in validNumbers -> print("x is valid")
    !in 10..20 -> print("x is outside the range")
    else -> print("none of the above")
}

//不去校验任何参数
when{
    a is Int -> log("a is Int")  // a is Int
    else -> log("unknow type")
}
4)if表达式
var a = 3
var b = 5
var max : Int
if(a > b)
    max = a
else
    max = b
log("普通 max : $max")   //普通 max : 5
也可简写成:
max = if(a > b) a else b
log("表达式 max : $max")   //表达式 max : 5
5)返回和跳转
JAVA中使用:return、break、continue
Kotlin中新增跳出循环操作:使用标识符@定义label,使用在多层循环的内层向外层跳转。
break和label结合跳转到指定循环层,即使用label1@在跳出循环层的循环操作前面,然后执行完什么操作就跳出时加入代码 break@label1
var list = arrayof(1,2,3)
var child = arrayof("a","b","c")
var result = ""
label1@ for(num in list){   // --> 第一层循环
    result +="($num)"  
    for(word in child){     // --> 第二层循环
        if(word.equals("b")){
            break@label1    // --> break + label
        }
        result += word
    }
}
log(result)   //输出 (1)a
continue和label结合跳转到指定循环层,继续下一次循环。当条件满足时跳出内层循环继续执行外层循环。
label2@ for(num in list){   // --> 第一层循环
    result += "($num)"
    for(word in child){     // --> 第二层循环
        if(word.equals("b")){
            continue@label2 // --> continue + label
        }
        result +=word
    }
}

5、继承

在java中使用的是extend,kotlin中继承变成 :
继承五步曲:
1)使用:来做继承
2)父类使用open声明类,不然默认final,无法继承
3)父类构造函数中有参数则在继承时带上
4)子类中使用constructor创建的次级构造函数初始化时使用super关键字
5)父类中的方法如果需要重写,则需要在该方法前加上open关键字,同样,子类如果需要修改或重载该方法也需要在引用处加上override关键字。
1、多级构造函数的继承
父类:
open class ParentClass(name:String){
    var a = 1
    init{
        log("This is --> primary constructor, a=$a, name=$name")
    }
}
子类:
//无次级构造函数的写法
class Child(name:String,age:Int) : ParentClass(name){
}

//有次级构造函数的写法:
class Child2 : ParentClass {
    constructor(name :String) :super(name){
        log("Child2 age : $name")
    }
    constructor(name:String,age :Int) :super(name){
    }
}
2、方法重载
//父类
open class ParentClass(name: String) {
    open fun publicMethod(){
        log("I am public")
    }
}
//子类
class Child(name: String, age : Int) : ParentClass(name){
    override fun publicMethod() {
        super.publicMethod()
    }
}
3、同名方法
当这个父类中有2个方法同名,参数相同时,kotlin中使用尖括号来进行标记父类,以示区分。
//父类
open class ParentClass(name :String){
    open fun publicMethod(){
        log("I am public from ParentClass")
    }
}
interface ParentInterface(name :String){
    fun publicMethod(){
        log("I am public from ParentInterface")
    }
}

//子类
class Child(name :String,age :Int) :ParentClass(name),ParentInterface{
    override fun publicMethod(){
        super<ParentClass>.publicMethod()
        super<ParentInterface>.publicMethod()
    }
}
4、抽象
抽象主要是将不同的实现交给不同的子类去完成
//父类
abstract class ParentClass(name: String) { 
    abstract fun abstractMethod()
}

//子类
class Child(name: String, age : Int) : ParentClass(name){
    override fun abstractMethod() {
        //To implemented it
    }
}
5、属性声明、get、set的使用
1)访问权限
var name :String = ""
    private set     //但是不能使用private get,因为get的访问权限默认是和属性一致的
2)自定义getter和setter
var有set和get,val只有get
// 自定义get
var size: Int = 2
get() = if (field > 10) 15 else 0
// 调用
var pf = PropertiesFields()
pf.size = 5
Log.d("text", "size : ${pf.size}")
pf.size = 20
Log.d("text", "size : ${pf.size}")

// 输出
size : 0
size : 15


// 自定义set
var size: Int = 2
set(value) {
    field = if (value > 10) 15 else 0
}
// 调用和输出同上
3)后端变量
在kotlin的getter和setter是不允许本身的局部变量的,因为属性的调用也是对get的调用,因此会产生递归,造成内存溢出。
kotlin为此提供了一种我们要说的后端变量,也就是field。编译器会检查函数体,如果使用到了它,就会生成一个后端变量,否则就不会生成。我们在使用的时候,用field代替属性本身进行操作。
4)延迟初始化属性(lateinit)
延迟属性类似于JAVA中的懒汉式单例模式
//延迟初始化声明
lateinit var late : String
fun initLate(){
    late = "I am late"
}

//先调用方法,再调用属性
var pf = PropertiesFields()
pf.initLate()
Log.d("text",pf.late)

//输出
I am late
注:一定要确保属性是被初始化过的,这样再调用方法,再调用属性,否则会出现属性的NULL异常现象。

6、 接口interface

1)定义接口、方法和属性
接口属性默认是abstract,在接口中不能初始化,必须在实现类中进行初始化,并且在初始化时要加override修饰
在具体类中可以不用覆写接口中的实现方法,直接调用
interface Wing{
    fun fly(){
        Log.d("text", "Wing -> fly")    // 这里实现了接口的方法
    } 
}
//JAVA中引入接口中的方法使用implement关键字,而kotlin中使用冒号:
class InterfaceLesson : Wing{
    override fun fly(){
        super.fly()            //  在具体类中可以不用覆写接口中的实现方法,直接调用
    }
}

// 输出
Wing -> fly
2)继承和多继承重载
接口只能继承接口
a、子类中调用父类方法需要使用super方法调用接口来实现
b、接口没有实现方法,子类必须实现方法且不能调用super
c、多个接口中都有相同的方法,无论接口中是否实现,子类都必须实现该方法。如果二个接口中都没有实现,则子类不能使用super;如果有一个接口实现了,则子类可以使用super且自动调用实现的方法;如果二个接口都实现了该方法,则子类在调用super时需要使用尖括号对调用的父方法进行声明。
例1:
interface Foot{
    fun run() 
}

interface Car{
    fun run() 
}

class InterfaceLesson : Foot, Car{
    override fun run() {
    }
}
例2:
interface Foot{
    fun run()
}

interface Car{
    fun run() {
        Log.d("text", "Car -> run1")
    }
}

class InterfaceLesson : Foot, Car{
    override fun run() {
        super.run()
    }
}

// 输出
Car -> run1
例3:
interface Foot{
    fun run() {
        Log.d("text", "Foot -> run")
    }
}

interface Car{
    fun run() {
        Log.d("text", "Car -> run1")
    }
}

class InterfaceLesson : Foot, Car{
    override fun run() {
        super<Foot>.run()
    }
}

// 输出
Foot -> run

7、 扩展Extension

1)扩展方法
java中调用toast需要写成封装的工具类或者BaseActivity中实现toast方法,而kotlin中则不需要这样做,只要在需要的Activity或者Fragment中创建fun方法,实现context的扩展,增加toast方法即可。
//  对Context的扩展,增加了toast方法。为了更好的看到效果,我还加了一段log日志
fun Context.toast(msg : String){
    Toast.makeText(this,msg,Toast.LENGTH_SHORT).show()
    Log.d("text","Toast msg : $msg")
}

// Activity类,由于所有Activity都是Context的子类,所以可以直接使用扩展的toast方法
class MainActivity : AppcompatActivity(){
    override fun onCreate(savedInstanceState : Bundle?){
        ......
        toast("Hello,Extension")
    }
}

//输出
Toast msg : Hello,Extension
2)扩展属性
扩展属性也有set和get方法,并且必须要实现这2个方法,不然编译会出错。
//1、 扩展了一个属性paddingH,并给属性增加set和get方法
var View.paddingH : Int 
    get() = (paddingLeft + paddingRight) / 2
    set(value) {
        setPadding(value,paddingTop,value,paddingBottom)
    }

//2、设置值  activity中通过textview调用
text.paddingH = 100     
3)静态扩展
kotlin中的静态用关键字companion表示,它不是修饰属性或方法,而是定义一个方法块,在方法块中的所有方法和属性都是静态的,静态部分的访问和java一致,直接使用类名+静态属性/方法名就可以
//定义静态部分
class Extension {
    companion object part{
        var name = "Extension"
    }
}

//通过类名+属性名直接调用
toast("hello,${Extension.name}")

//输出
Toast msg : hello,Extension
注:companion object一起是修饰关键字,part是方法块的名称。其中,方法块名称part可以省略,如果省略的话,默认缺省名为Companion

8、数据类

保持数据或状态,在JAVA中用bean或entity或自定义model或sp保存持久等等,而kotlin中用data关键字来处理。
data class PersonData(var name : String, var age : Int)
使用data修饰的类叫做数据类,编译器自动从主构造函数定义的全部特性中得到以下成员:
equal()/hashCode()
toString 格式是 "PersonData(name = PersonData,age = 20)"
componentN()方法对应按声明顺序出现的所有属性
copy()方法
1)toString输出
// 定义数据类和普通类
data class PersonData(var name : String , var age : Int)
class PersonNormal(var name : String,val age : Int)

// 分别初始化并进行toString输出
fun test(){
    var personD = PersonData("personData",20)
    var personN = PersonNormal("personNormal",20)

    Log.d("test",personD.toString())
    Log.d("test",personN.toString())
}

//输出
PersonData(name = PersonData,age = 20)
包名.类名PersonNormal@地址(26b13e2)
2)copy
修改类中的内容(修改上面的PersonData中的内容)
var personC = personD.copy("Person Copy") //默认第一个参数
var personC = personD.copy(age = 100)     //可指定需要修改的参数
Log.d("test",personC.toString())

//输出
PersonData(name = person Copy,age = 100)
3)变量的映射
编译器自动生成的componentN()方法
var personD = PersonData("PersonData",20)
var(name,age) = personD  //多声明可翻译成如下
//var name = f1.component1()
//var age = f1.component2()

Log.d("test", "name = $name, age = $age")

//输出
name = PersonData, age = 20
4)数据的序列化
JAVA中通过Parcelable插件自动进行序列化,而kotlin中暂时只能自己实现。
data class PersonData(var name : String, var age : Int, val sex : String) : Parcelable{
    override fun writeToParcel(p0: Parcel?, p1: Int) {
        p0?.writeString(this.name)
        p0?.writeInt(this.age)
        p0?.writeString(this.sex)
    }

    override fun describeContents(): Int {
        return 0
    }

    constructor(source: Parcel) : this(source.readString(), source.readInt(), source.readString())

    companion object {
        @JvmField val CREATOR: Parcelable.Creator<PersonData> = object : Parcelable.Creator<PersonData> {
            override fun createFromParcel(source: Parcel):  PersonData {
                return PersonData(source)
            }

            override fun newArray(size: Int): Array<PersonData?> {
                return arrayOfNulls(size)
            }
        }
    }
}
##还有待追新研究下…

9、泛型

1)JAVA中泛型的使用
from是生产者,to是消费者。
extends关键字限定类型上限,super关键字限定类型下限。
//定义类
class Data<T>{}
//定义接口
interface Data<T>{}
//定义方法
public <T> void data(T t){}
//使用通配符
//用?表示任何类型,结合extends和super关键字可以限定类型的上限和下限
class Data<T>{} 
// extends关键字限定类型上限,表示类型必须是String或String的子类
public void dataUpper(Data<? extends String> d){}
// super关键字限定类型下限,表示类型必须是String或String的父类
public void dataLower(Data<? super String> d){}

//使用通配符解决数据调用问题
fun copy(from: Array<A>, to: Array<A>) {
    for (i in from.indices)
        to[i] = from[i]
}
2)kotlin中泛型的使用
kotlin中添加了协变注解修饰符:in和out(in对应to,out对应from)
in T:来确保Source的成员函数只能消费T类型,而不能返回T类型,我们也称in修饰的参数为“消费者”
out R:来确保Source的成员函数只能返回R类型,而不能消费R类型,我们也称out修饰的参数为“生产者”
out类似于java中的extends,用来界定类型上限,in类似于java中的super,用来界定类型下限。
//定义类
class Data<T>(var t : T)
//定义接口
interface Data<T>
//定义函数
fun <T> logic(t : T){}

//使用通配符解决数据调用问题
fun copy(from: Array<out A>, to: Array<in A>) {
    for (i in from.indices)
        to[i] = from[i]
}
另附:
kotlin中新增—–> 星号投射(还需挖掘)
interface Function

10、嵌套类、内部类

1)嵌套类
class Outter{
    class Nested{
        fun execute(){
            Log.d("test", "Nested -> execute")
        }
    }
}

// 调用
Outter.Nested().execute()

//输出
Nested -> execute
2)内部类
内部类需要使用关键字inner修饰
class Outter{
    val testVal = "test"
    inner class Inner{
        fun execute(){
            Log.d("test", "Inner -> execute : can read testVal=$testVal")
        }
    }
}

// 调用
val outter = Outter()
outter.Inner().execute()

// 输出
Inner -> execute : can read testVal=test  //可以读取到testVal的值,即外部类中的值
compare:
嵌套类中可以直接创建实例
val nested : Outter.Nested()
内部类不能直接创建实例,需要通过外部类调用
val outter = Outter()
outter.Inner().execute()
嵌套类不能引用包装类的成员,内部类会带有一个对外部包装类的对象的引用,可以访问外部类中的成员属性和成员函数(如上面例子中的testVal)。
匿名内部类(自定类,实现方法logic,然后再在新类的主程序中调用)
当然还有其他匿名内部类的实现方式,
java中的参考:http://www.cnblogs.com/nerxious/archive/2013/01/25/2876489.html
class Num{
    fun logic(a:Int,b:Int){
        println("a:$a,b:$b")
    }
}

fun main(args: Array<String>){
    val num = Num()
    num.logic(1,2)
}

//输出
a:1,b:2

11、类委托和委托属性

委托模式是最常用的设计模式的一种,在委托模式中,有两个对象参与处理同一个请求,接受请求的对象将请求委托给另一个对象来处理。
1)类委托
interface Base{
    fun print()
}

class BaseImpl(val x : Int) :Base{
    override fun print(){
        Log.d(JTAG, "BaseImpl -> ${x.string()}")
    }
}

class Printer(b : Base) : Base by b

fun test(){
    val b = BaseImpl(5)
    Printer(b).print()
}

//输出
BaseImpl -> 5
Printer没有实现接口Base的方法print(),而是通过关键字by,将实现委托给了b,而输出也和预想的一样。
2)委托属性
语法:val/var <属性名>: <类型> by <表达式>
在 by 后面的表达式是该 委托, 因为属性对应的 get()(和 set())会被委托给它的 getValue() 和 setValue() 方法。 属性的委托不必实现任何的接口,但是需要提供一个 getValue() 函数(和 setValue()——对于 var 属性)。
class Example{  //委托类
    var property : String by DelegateProperty()
}

class DelegateProperty{  //被委托类
    var temp = "old"
    operator fun getValue(ref: Any?,p:KProperty<*>):String{
        return "DelegateProperty --> ${p.name} --> $temp"
    }
    operator fun setValue(ref: Any?, p: KProperty<*>, value: String){  //setValue方法只有委托属性为var时存在,委托属性为val时不存在该方法
        temp = value
    }
}

fun test(){
    val e = Example()
    Log.d(JTAG, e.property)
    e.property = "new"
    Log.d(JTAG, e.property)
}

// 输出
DelegateProperty --> property --> old
DelegateProperty --> property --> new
注:
1、如果委托属性是只读属性,暨val,则被委托类需要实现getValue方法
2、如果委托属性是可变属性,暨var,则被委托类需要实现getValue方法和setValue方法
3、getValue方法的返回类型必须是与委托属性相同或是其子类
4、getValue方法和setValue方法必须要用关键字operator 标记
3)委托属性
三种标准委托属性
延迟属性、可观察属性、map属性
延迟属性:
只有在第一调用的时候才会初始化,在定义的时候不进行初始化
val lazyValue: String by lazy {
    Log.d(JTAG, "Just run when first being used")
    "value"
}

fun test(){
    Log.d(JTAG, lazyValue)
    Log.d(JTAG, lazyValue)
}

// 输出
Just run when first being used
value
value
可观察属性:
可观察属性对应的是我们常用的观察者模式
class User {
    var name: Int by Delegates.observable(0) {
        prop, old, new -> Log.d(JTAG, "$old -> $new")
    }

    var gender: Int by Delegates.vetoable(0) {
        prop, old, new -> (old < new)
    }
}

fun test(){
    val user = User()
    user.name = 2    // 输出 0 -> 2        
    user.name = 1   // 输出 2 -> 1    

    user.gender = 2
    Log.d(JTAG, user.gender.string())   // 输出 2
    user.gender = 1
    Log.d(JTAG, user.gender.string())   // 输出 2
}
Delegates.observable() 接受两个参数:初始值和修改时处理程序(handler)。该方法是在被赋值且执行完set方法后才被执行;
Delegates.vetoable()该方法在set执行之前被触发,它返回一个Boolean,如果为true才会继续执行set;否则保持原值。
如上例:第一次赋值 user.gender = 2时,由于2>0,所以old
map映射:
可以使用映射实例自身作为委托来实现委托属性。
class User(val map: Map<String, Any?>) {
    val name: String by map
    val age: Int     by map
}

val user = User(mapOf(
    "name" to "John Doe",
    "age"  to 25
))

println(user.name) // Prints "John Doe"
println(user.age)  // Prints 25
这也适用于 var 属性,如果把只读的 Map 换成 MutableMap 的话:
class MutableUser(val map: MutableMap<String, Any?>) {
    var name: String by map
    var age: Int     by map
}

12、函数式编程

class Number{
    //声明函数
    fun sum(a:Int,b:Int) = a + b
    //声明方法
    fun logic(a:Int,b:Int,calc:(Int,Int) -> Int){
        println("calc : ${calc(a,b)}")
    }
}

fun main(args:Array<String>){
    val num = Number()
    num.logic(1,2,num::sum)
}

//输出
calc : 3
格式: 参数名: (参数类型,参数类型…) -> 输出类型
参数名不一定是方法名,参数类型是这个函数参数的输入类型,如果是无参函数,括号()不可省略!

返回结果用函数返回
class Number{
//声明函数
fun sum(a:Int,b:Int) = a + b
//声明方法
fun logic(a:Int,b:Int,calc:(Int,Int) -> Int){
println(“calc : ${calc(a,b)}”)
}
//调用函数方法返回结果
fun getSumMethod() = this::sum
}

fun main(args:Array<String>){
    val num = Number()
    num.logic(1, 2, num.getSumMethod())
}

//输出
calc : 3
kotlin中函数可作为一个普通的类,一个参数,一个返回,剩下一个实现方法调用

13、Lambda的使用

class Number{
    //声明方法
    fun logic(a:Int,b:Int,calc:(Int,Int) -> Int){
        println("calc : ${calc(a,b)}")
    }
}

fun main(args:Array<String>){
    val num = Number()
    num.logic(1,2,{x,y -> x+y})
}

//输出
calc : 3
Lambda方式:num.logic(1, 2, {x,y -> x+y})
注:
  1. Lambda表达式总是被大括号{}包围着
  2. 函数体跟在 -> 右边,左侧是参数,多个参数用逗号,分割
当函数数字面值只有一个参数,它的声明可以省略(连同 ->),名称为it;而当函数是无参函数时,主程序中调用时也可省略 ->
单参函数:
fun oneParams(one : (Int) -> Int){
    println("oneParams : ${one(5)}")
}
fun main(args : Array<String>){
    val num = Num()
    num.oneParams({it*2})
}

//输出
oneParams : 10
无参函数:
fun empty(emptyM : () -> Unit){
    emptyM()
}
fun main(args : Array<String>){
    val num = Num()
    num.empty({println("empty method")})
}

//输出
empty method
当函数中有某个参数没有用到,可以使用下划线_代替。
fun unusedParams(unused : (Int,Int) -> Int){
    println("unusedParams : ${unused(5,10)}")
}
fun main(args : Array<String>){
    val num = Num()
    num.unusedParams{ _,used -> used*2 }
}

//输出
unusedParams : 20
当函数中最后一个参数是一个函数时,可以把它放在括号()外面
class Num {
    fun logic(a: Int, b: Int, calc: (Int, Int) -> Int){
        println("calc : ${calc(a,b)}")
    }
    fun sum(a: Int, b: Int) = a + b
}

fun main(args : Array<String>){
    val num = Num()
    // 写法1
    num.logic(1, 2, {x : Int,y : Int -> x+y})
    // 写法2
    num.logic(1, 2){x : Int,y : Int -> x+y}
    // 写法3
    num.logic(1, 2){x,y -> x+y}
}

//如果有多行数据时:
num.logic(1, 2, {x,y ->
    println("extra line")
    x+y
})

num.logic(1, 2){x,y ->
    println("extra line")
    x+y
}
匿名函数
fun(x: Int, y: Int): Int = x + y

fun(x: Int, y: Int): Int {return x + y}
Lambda 表达式或者匿名函数(以及局部函数和对象表达式) 可以访问其 闭包 ,即在外部作用域中声明的变量。 与 Java 不同的是可以修改闭包中捕获的变量:
var sum = 0
ints.filter { it > 0 }.forEach {
    sum += it
}
print(sum)
还有待持久性的学习巩固最新知识,更多高级应用期待你们的分享。
  • 7
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
其基础编译器(他们将其改为kompiler——开创了一系列以K字打头的用语——甚至连 contributors这类词他们也用改成了kontributors)可以被独立出来并嵌入到 Maven、Ant 或 Gradle 工具链中。这使得在 IDE 中开发的代码能够利用已有的机制来构建,从而尽可能的减少了在新环境中使用所受的干预,哪怕与那些没有安装 Kotlin 插件的开发人员一起合作项目也没有问题。 The IntelliJ Kotlin 插件扩展了 Java 编译器使得 Kotlin 代码能够得以编写、编译和调试。除此之外,关于基本的 Java 集合,已经有编写好的帮助函数,可以更顺畅地衔接将在 Java 8 中出现的集合扩展。 有两篇文章对 Kotlin 与 Java 以及 Kotlin 与 Scala 分别进行了比较,对各自特性和异同进行了对比。即便 Scala 可能还是更为强大些,Kotlin 还是尝试着提供比 Java 更好的函数、模式匹配、空指针预防和泛型。该语言同时也支持特征(traits)和模式匹配。 Kotlin 插件在当前版本的 IntelliJ 和 Eclipse 中均已能使用。 [4] Kotlin,类似 Xtend 一样,旨在提供一种更好的 Java 而非重建整个新平台。这两种语言都向下编译为字节码(虽然 Xtend 是首先转换成相应的 Java 代码,再让 Java 编译器完成繁重的工作),而且两者都引入了函数和扩展函数(在某个有限范围内静态地增加一个新方法到某个已有类型的能力)。Xtend 是基于 Eclipse 的,而 Kotlin 是基于 IntelliJ 的,两者都提供无界面构建。能够首先演变到其他 IDE 的语言有可能成为最后的赢家。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值