Kotlin编程禅与计算机程序设计艺术Java

Kotlin Power

2020-02-25  本文已影响0人  juexingzhe

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.作用域函数

对象作为参数传入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) }
}

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

对象作为参数传入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 */ }

对象作为参数传入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.其他

Refs:

上一篇下一篇

猜你喜欢

热点阅读