3.Kotlin相比java新增语法

空指针防护

 //main函数
    fun main(args: Array<String>) {
        //getContentLength(null) //报错:Null can not be a value of a non-null type String
        getContentLength1(null)//不报错
    }

    fun getContentLength(content: String): Int {
        return content.length
    }
    fun printUpperCase(content: String?) {
        //?.表示如果不为空则执对象方法,下面是将字符串转换成大写,如果为空则不执行并返回null
        println(content?.toUpperCase())
    }
    //参数后加?表示允许赋null
    fun getContentLength1(content: String?): Int {
        //return content.length //报错Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type String?
        //return content?.length//这里用?.是不行的,因为返回值是Int非空,当返回null时会类型不匹配
        //解决办法1
        return if (content == null) 0 else content.length
        //解决办法2,?:表示优先前面表达式结果,当前面表达式结果为空是则取后面结果0
        return content?.length ?: 0
        //解决办法3,!!.强制去除非空检查,当你确信参数为非空时可以这样处理
        return content!!.length
    }

名称JavaKotlin
对象MainActivity.thisthis@MainActivity
MainActivity.classMainActivity::class.java
静态常量static final String text = “”;const val text = “”(需要注意的是要把静态变量定义在类上方)
比较类型if ("" instanceof String) {}if ("" is String) {}
比较字符串equals==(Kotlin 对字符串比较的写法进行优化了,其他类型对象对比还是要用 equals 方法)

表达式

中缀表达式

中缀表达式
只有一个参数,且嗯infix修饰的函数,则可以去掉.() 来调用
例:
class Book{infix fun on(place:String}{...}
Book() on "desk"

分支表达式

  • 每个分支的最后一行代码就是返回值
var i = if (content == null) 0 else content.length

  • 也可以和分值表达式一样,最后一行代码就是返回值
val x: Int = 3;
    val y: Int = 4
    var z = 0
    var i = try {
      z = x/y
    }catch (e: Exception){
        z = 0
        //finally无论如何都是会被执行到的
    }finally {
        println("程序执行完毕")
    }
    println(i)

扩展

  • 扩展不能真正的修改他们所扩展的类,并没有在一个类中插入新成员或者方法

扩展函数

扩展函数资料

扩展函数作用域: 分发接收者类之中

示例一:

java 中实现

public class Utils {
    public static float dp2px(int dpValue) {
        return (0.5f + dpValue * Resources.getSystem().getDisplayMetrics().density);
    }
}
float f = Utils.dp2px(100); 

kotlin 中实现

fun Int.dp2px(): Float {
    return (0.5f + this * Resources.getSystem().displayMetrics.density)
}
val dp2px = 100.dp2px()

示例二:

class Person(val name: String) {

    fun eat() {Log.i(name, "I'm going to eat")}

    fun sleep() {Log.i(name, "I'm going to sleep")}
}

新建一个文件 PersonExtensions.kt:

fun Person.cook() {Log.i("Person", "${this.name}: I'm going to cook")}
  • 这个 this 指的就是调用这个拓展方法的当前 Person 对象

Person 扩展函数转为Java代码后如下:

@Metadata(
   mv = {1, 1, 15},
   bv = {1, 0, 3},
   k = 2,
   d1 = {"\u0000\f\n\u0000\n\u0002\u0010\u0002\n\u0002\u0018\u0002\n\u0000\u001a\n\u0010\u0000\u001a\u00020\u0001*\u00020\u0002¨\u0006\u0003"},
   d2 = {"cook", "", "Lcom/chaochaowu/kotlinextension/Person;", "app_debug"}
)
public final class PersonExtensionsKt {
   public static final void cook(@NotNull Person $this$cook) {
      Intrinsics.checkParameterIsNotNull($this$cook, "$this$cook");
      Log.i("Person", $this$cook.getName() + ": I'm going to cook");
   }
}

java中调用如下:

PersonExtensionsKt.cook(new Person("Bob"));

扩展属性

  • 扩展属性和扩展函数类似
class Person(val name: String) {

    fun eat() {Log.i(name, "I'm going to eat")}

    fun sleep() {Log.i(name, "I'm going to sleep")}
}
  • 新建一个文件 PersonExtensions.kt:

const val currentYear = 2019

val Person.age: Int
    get() = currentYear - this.birthdayYear

  • 为 Person 增加年龄 age 的属性,但是不改 Person 类

lambda表达

lambda表达式简化过程

  1. 常规lambda表达式
button.setOnClickListener({v: View? -> println("")})
  1. lambda表达式是函数调用的 最后一个实参可以放到括号的外边
button.setOnClickListener(){v: View? -> println("")}
  1. lambda是函数 唯一的实参,还可以 去掉调用代码中的空括号对
button.setOnClickListener{v: View? -> println("")}
  1. 和局部变量一样,如果lambda参数的类型可以被推倒出来,不需要显示地指定
button.setOnClickListener{v -> println("")}
  1. 如果当前上下文期望的是 只有一个参数的 lambda ,并且这个参数的类型可以推断出来
button.setOnClickListener{println("")}
  • 当形参和需要调用函数一致时
button.setOnClickListener{mainActivity::abc}

fun abc(v:View){}

button.setOnClickListener{::abc}//当在同一个类中其类名还可以省略

有形参和无形参的区别

//实现方法有形参:则不需要写接口名,且it代为实现方法形参
textView.setOnClickListener { it.viewTreeObserver}

// 无形参:需要注明实现接口
Thread(Runnable {})

Lambda表达式与函数

Lambda表达式释义

(Int, String) -> Unit
  • Int, String 是形参
  • Unit是函数返回类型,Unit代表返回的是空

Lambda表达作为变量

显示声明:

//有两个 Int 型参数和 Int 型返回值的函数
val sum : (Int, Int) -> Int = {x, y -> x + y}
//没有参数和返回值的函数
val action : () -> Unit = { println(42) }

当编译器可以推导出类型,可以隐式声明:

val sum = { x : Int, y : Int -> x + y }
val action = { println(42) }

Lambda表达的空类型

声明变量时的空类型

返回值为空

var canReturnNull : (Int, Int) -> Int? = { null }

变量为可空变量

// 将整个函数类型的定义包含在括号内并在括号后添加一个问号
var funOrNull : ((Int, Int) -> Int)? = null
函数形参的空类型

显示地检查 null:

fun foo(callback : (() -> Unit)?) {
    if (callback != null) {
        callback()
    }
}

通过安全调用语法调用:

callback?.invoke() ?: /* 默认实现 */

Lambda 作为形参

示例一:

fun twoAndThree(operation: (Int, Int) -> Int) {
    val result = operation(2, 3)
    println("The result is $result")
}

fun main(args: Array<String>) {
    twoAndThree { a, b -> a + b }
    twoAndThree { a, b -> a * b }
}
//运行结果为:
>> The result is 5
>> The result is 6

示例二:

//过滤字符:
fun String.filter(predicate: (Char) -> Boolean): String {
    val sb = StringBuilder()
    for (index in 0 until length) {
        val element = get(index)
        if (predicate(element)) sb.append(element)
    }
    return sb.toString()
}
fun main(args: Array<String>) {
    println("ab1c".filter { it in 'a'..'z' })
    
    //println("ab1c".filter ({ c :Char ->  c in 'a'..'z' }))
    //println("ab1c".filter { c :Char ->  c in 'a'..'z' })
    //println("ab1c".filter { c  ->  c in 'a'..'z' })
    //println("ab1c".filter { it in 'a'..'z' })
}
//运行结果:
>> abc

Lambda 作为形参的默认值

fun <T> Collection<T>.joinToString(
        separator: String = ", ",
        prefix: String = "",
        postfix: String = "",
        //为函数类型的参数提供默认值。
        transform: (T) -> String = { it.toString() }
): String {
    val result = StringBuilder(prefix)

    for ((index, element) in this.withIndex()) {
        if (index > 0) result.append(separator)
        //调用传入的函数。
        result.append(transform(element))
    }

    result.append(postfix)
    return result.toString()
}

fun main(args: Array<String>) {
    val letters = listOf("Alpha", "Beta")
    println(letters.joinToString())
    println(letters.joinToString { it.toLowerCase() })
    println(letters.joinToString(separator = "! ", postfix = "! ",
           transform = { it.toUpperCase() }))
}
//运行结果为:
>> Alpha, Beta
>> alpha, beta
>> ALPHA! BETA! 

Lambda 作为函数返回值

    //声明一个枚举类型。
    enum class Delivery { STANDARD, EXPIRED }

    class Order(val itemCount : Int)

    //返回的函数类型为:形参为 Order 类,返回类型为 Double。
    fun getShippingCalculator(delivery : Delivery) : (Order) -> Double {
        if (delivery == Delivery.EXPIRED) {
            return { order -> 6 + 2.1 * order.itemCount }
        }
        // Lamabda实现方式
        return { order -> 1.2 * order.itemCount }
        // 匿名函数实现方式
        //        return fun(order:Order):Double{return 1.2 * order.itemCount}
    }

    fun main(args: Array<String>) {
        val calculator = getShippingCalculator(Delivery.EXPIRED)
        println("cost ${calculator(Order(3))}")
    }

Lambda 作为形参在java中使用

kotlin函数:

fun twoAndThree(operation: (Int, Int) -> Int) {
    val result = operation(2, 3)
    println("The result is $result")
}

在java中实现:

Customer.asd asd = new Customer.asd();
asd.twoAndThree(new Function2<Integer, Integer, Integer>() {
            @Override
            public Integer invoke(Integer integer, Integer integer2) {
                return integer+integer2;
            }
        });

简化写法:

Customer.asd asd = new Customer.asd();
asd.twoAndThree((integer, integer2) -> integer+integer2);

注:在java中就通过Function实现,分别有Function,Function2,Function3分别代表一个形参,两个形参,三个形参,每个的最后一个为返回类型

扩展函数在Java中使用

List<String> list = new ArrayList();
list.add("42");
CollectionsKt.forEach(list, s -> {
    System.out.println(s);
    retrun Unit.INSTANCE;
});

Lambda表达式for循环中局部返回

使用标签返回
  • 类似于for循环中的break表达式
data class Person(val name: String, val age: Int)

val people = listOf(Person("Alice", 29), Person("Bob", 31))

fun lookForAlice(people: List<Person>) {
    people.forEach label@{
        if (it.name == "Alice") return@label
    }
    println("Alice might be somewhere")
}

fun main(args: Array<String>) {
    lookForAlice(people)
}
运行结果为:

>> Alice might be somewhere
匿名函数方式局部返回
data class Person(val name: String, val age: Int)

val people = listOf(Person("Alice", 29), Person("Bob", 31))

fun lookForAlice(people: List<Person>) {//这种方式是在forEach后面的括号里
    people.forEach(fun (person) {
        if (person.name == "Alice") return
        println("${person.name} is not Alice")
    })
}

fun main(args: Array<String>) {
    lookForAlice(people)
}
运行结果为:

>> Bob is not Alice
  • 匿名函数和普通函数有相同的指定返回值类型的规则,代码块匿名函数 需要显示地指定返回类型,如果使用 表达式函数体,就可以省略返回类型。

注意:

  • lambda表达式没有使用fun关键字,所以lambda中的return从最外层的函数返回。
  • 匿名函数使用了fun,因此return表达式从匿名函数返回。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值