Kotlin Power

作者: juexingzhe | 来源:发表于2020-02-25 18:31 被阅读0次

    Android开发者都知道,Google宣布Kotlin First,并且在Android官网上的Demo代码都是Kotlin优先,之后提供的代码也是,推广的决心很大。而且Kotlin和Java能100%兼容,并且语法更简洁,后面我也会陆续写一些Kotlin的分享文章,今天先概览一下Kotlin的优势。

    1.类型推断

    // 只读变量声明(更友好) 想想final
    val a: Int = 1 // 后置类型声明
    // 一般利用类型推断,思维更加顺畅,不用再关心参数是什么类型的问题
    val a = 5
    val s = String()
    val clazz = s.getClass()
    val method = clazz.getDeclaredMethod("name", null)  
    // 可变变量声明
    var x = 5
    

    2.View初始化

    inline fun <reified TV:View> KView(context: Context, init: TV.() -> Unit) : TV {
        val constructor = TV::class.java.getConstructor(Context::class.java)
        val view : TV = constructor.newInstance(context)
        view.init()
        return view
    }
    
    >>> usage
    val view = KView<TextView>(this) {
            layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT)
            text = "Hello"
    }
    

    3.NUllPointer

    空类型和非空类型

    var age: String? = null
    // 直接调用会编译报错
    val age1 = age.toInt()
    // 正确调用
    val age1 = age?.toInt()
    
    // 不做处理返回null
    val age2 = age?.toInt()
    // age为空返回-1
    val age2 = age?.toInt() ?: -1
    // 抛出空指针异常
    val age2 = age!!.toInt()
    
    val l = s?.length // s != null, l = s.length else l = null, l: Int?
    val l = s!!.length // same as l = s.length in java, l: Int
    val l = s?.length ?: 0 //  s != null, l = s.length else l = 0, l: Int
    return myValue ?: -1
    // 链式使用:
    bob?.department?.head?.name // 任一为null不执行
    

    Attention:

    如果被Java调用,由于Java无法保证非空(除非已经使用@NonNull注解注明),从Java接收的参数必须是可空的。

    4. ? and Elvis

    // java
    if(view != null) {
      if(view.getParent() != null) {
        if(view.getParent() instanceof ViewGroup) {
          ((ViewGroup) view.getParent()).removeView(view)
        }
      }
    }
    
    // kotlin
    (view?.parent as? ViewGroup)?.removeView(view)
    

    5. when

    when(x) {
      in 1..10 -> print("x is in the range")
      !in 10..20 -> print("x is outside the range")
      is String -> print("x is a string")
      else -> print("none of the above")
    }
    
    // usage
    if(TextUtils.equals(day, today)) {
      xxx1
    } else if(TextUtils.equals(day, tomorrow)) {
      xxx2
    } else {
      xxx3
    }
    
    // kotlin
    when(day) {
      today -> xxx1
      tomorrow -> xxx2
      else -> xxx3
    }
    

    6. 扩展函数

    private fun <T> MutableList<T>.swap(index1: Int, index2: Int) {
        val tmp: T = this[index1]
        this[index1] = this[index2]
        this[index2] = tmp
    }
    
    >>> usage
    val list = mutableListOf<Int>(1, 2, 3)
    list.swap(0, 1)
    println(list)
    
    >>> out
    [2, 1, 3]
    

    7. 关键字object

    单例

    object KotlinPower {
        override fun toString(): String {
            return "KotlinPower"
        }
    }
    
    >>> usage
    println(KotlinPower.toString())
    

    对象字面量

    fun testObject() {
        val a = object {
            var x: Int = 0
            var y: Int = 0
        }
    
        println("a.x: ${a.x}, a.y: ${a.y}")
    }
    
    >>> usage
        testObject()
    
    >>> out
    a.x: 0, a.y: 0
    

    再看一个例子:

    object Test {
        fun sayMessage(msg: String) {
            println("from Kotlin $msg")
        }
    }
    
    // kotlin code
    Test.sayMessage("Hello")
    
    // java code
    Test.INSTANCE.sayMessage("hello");
    

    如果要保持java和Kotlin中的调用方式一样,可以在Kotlin中通过注解@JvmStatic方式

    object Test {
        @JvmStatic
        fun sayMessage(msg: String) {
            println("from Kotlin $msg")
        }
    }
    //这样在java中就可以直接
    Test.sayMessage("Hello")
    

    8. 属性

    引入了属性的概念,隐式的gettersetter

    var stringRepresentation: String
        get() = this.toString()
        set(value) {
            setDataFromString(value)
        }
    
    // 相当于
        
    public String getStringRepresentation() {
        return this.toString();
    }
    
    public void setStringRepresentation(String value) {
        setDataFromString(value)  
    }
    

    9.函数

    在Kotlin中函数成为了一等公民,位置不需要一定在类的内部,可以和类成为顶级函数,函数也可以作为参数传递

    • 缺省参数,命名参数

    可以简化重载,不用再使用Builder等优势

    fun reformat(str: String,
                 normalizeCase: Boolean = true,
                 upperCaseFirstLetter: Boolean = true,
                 divideByCamelHumps: Boolean = false,
                 wordSeparator: Char = ' ') {
        // do something
    }
    reformat(str)
    reformat(str, wordSeparator = ' ') // 可以使用参数的名字给缺省参数赋值
    // 可以通过@JvmOverloads注解生成Java的重载形式便于Java来调用
    
    • 扩展函数

    可以去掉Java中到处存在的XXXUtils.java类

    // Java
    // 写一个Util类,作为参数传进去
    public class ViewUtils {
        public static int findColor(View view, int resId) {
            return view.getResources().getColor(resId);
        }
    }
    ViewUtils.findColor(view, resId);
    

    使用Kotlin简化如下:

    fun View.findColor(id: Int) : Int {
        return this.resources.getColor(id)
    }
    
    view.findColor(resId)
    

    一系列这种类型的Java工具类在Kotlin中被“改造”成了扩展方法例如:

    Collection.sort(list)在Kotlin中直接list.sort()就可以了。

    可以完全取代以往的Util类。

    10.作用域函数

    • let/run

    对象作为参数传入lambdarun则作为this),返回值为lambda表达式的返回值, 常见场景:转换类型,处理nullable类型

    // if...else...写法
    private fun testIfElse(): Object? {
        return if (a !== null) {
            val b = handleA(a)
            if (b !== null) {
                handleB(b)
            } else {
                null
            }
        } else {
            null
        }
    }
     
    // ?.let写法
    private fun testLet(): Object? {
        return a?.let { handleA(it) }?.let { handleB(it) }
    }
    
    • apply

    对象作为this传入lambda, 返回值为对象本身,常见场景:初始化对象

    • also

    对象作为参数传入lambda,返回值为对象本身,常见场景:链式调用中的副作用

    // transforming data from api with intermediary variable
    val rawData = api.getData()
    Log.debug(rawData)
    rawData.map {  /** other stuff */  }
    // use 'also' to stay in the method chains
    api.getData()
        .also { Log.debug(it) }
        .map { /** other stuff */ }
    
    • takeIf/takeUnless

    对象作为参数传入lambda,返回值为对象本身或null(根据lambda中语句的true or false),常见场景:链式调用形式的条件判断

    File(url).takeIf { it.exists() }
            ?.let {
                JSONObject(NetworkUtils.postFile(20 * 1024, "http://i.snssdk.com/2/data/upload_image/", "image", url))
            }?.takeIf { it.optString("message") == "success" }
            ?.let {
                post(content, contact, it.optJSONObject("data")?.optString("web_uri"))
            } ?: mHandler.post { view?.onFail() }
    

    11.Lambda

    本质上是一个匿名方法(单方法接口)

    fun isGreaterThanZero(n: Int): Boolean {
        return n > 0
    }
    
    collection.filter(::isGreaterThanZero)
    // 使用Lambda
    collection.filter{ i: Int -> i > 0 }
    collection.filter{ i -> i > 0 }
    collection.filter{ it > 0 }
    

    单方法接口都可以传Lambda

    button.setOnClickListener(new View.OnClickListener() {
        
        public void onClick(View v) {
            showToast();
        }
    });
    
    button.setOnClickListener{ showToast() }
    

    内置常用的流处理Lambda

    names
    .filter{ it.startsWith("A") }
    .sortedBy{ it }
    .map{ it.toUpperCase() }
    .forEach{ print(it) }
    

    12.其他

    • 支持运算符重载
    • 接口可以有缺省方法
    • Data Class数据类型,自动实现`equals/hashCode/toString
    • 协程
    • 伴生对象

    Refs:

    相关文章

      网友评论

        本文标题:Kotlin Power

        本文链接:https://www.haomeiwen.com/subject/jocfchtx.html