美文网首页
Java过渡到Kotlin

Java过渡到Kotlin

作者: RobinYeungChn | 来源:发表于2019-01-18 16:11 被阅读0次

1.Kotlin和Java常用语法对比

1.1 打印日志

Java Kotlin
System.out.print("Java") print("Kotlin")
System.out.println("Java") println("Kotlin")

1.2 常量与变量

Java Kotlin
String name = "Java变量" var name = "Kotlin变量"
final String name = "Java常量" val name = "Kotlin常量"

1.3 Nullable声明

Java Kotlin
String otherName;
otherName = null;
var otherName : String?
otherName = null

1.4 空判断
Java :

if (text != null) {
    int length = text.length()
}

Kotlin :

text?.let {
    val length = text.length
}

// 或者

val length = text?.length

在Kotlin中,我们只使用一个问号安全调用符号就省去了Java中烦人的 if-null 判断

1.5 字符串拼接
Java :

String firstName = "Robin";
String lastName = "Yeung";
String wholeName = "My name is : " + firstName + " " + lastName

Kotlin :

val firstName = "Robin"
val lastName = "Yeung"
val wholeName = "My name is : $firstName  $lastName"

Kotlin中使用$和${}(花括号里面是表达式)占位符来实现字符串拼接,这个比在Java中每次使用加号来拼接要方便很多.

1.6 换行
Java :

String text = "First Line\n" + "Second Line\n" + "Third Line";

Kotlin :

val text = """
              First Line
              Second Line
              Third Line
              """

Kotlin的换行语法和Markdown的引用代码块语法很像

1.7 三元表达式
Java :

String text = x > 5 ? " x > 5" : "x <= 5"

Kotlin :

val text = if (x > 5) "x > 5" else "x <= 5"

1.8 操作符

Java Kotlin
final int andResult = a & b val andResult = a and b
final int orResult = a | b val orResult = a or b
final int xorResult = a ^ b val xorResult = a and b
final int rightResult = a >> 2 val rightResult = a shr 2
final int leftResult = a << 2 val rightResult = a shl 2

1.9 类型判断和转换(显式)
Java :

if (object instanceof car) {
}
Car car  = (Car) object;

Kotlin :

if (object is Car) {
}
var car = object as Car

1.10.类型判断和转换(隐式)
Java :

if (object instanceof car) {
    Car car  = (Car) object;
}

Kotlin :

if (object is Car) {
    var car = object  // kotlin智能转换
}

Kotlin的类型系统具备一定的类型推断能力,这样也省去了不少在Java中类型转换的样板式代码.

1.11 区间

Java Kotlin
if (score >= 0 && score <= 300) { } if (score in 0..300) { }

1.12 case语句
Java :

public String getGrade(int score) {
    String grade;
    switch (score) {
        case 10:
        case 9:
              grade = "A";
              break;
        case 8:
        case 7:
        case 6:
              grade = "B";
              break;
        case 5:
        case 4:
              grade = "C";
              break;
        case 3:
        case 2:
        case 1:
              grade = "D";
              break;
        default : 
            grade = "E";
    }
}

Kotlin :

fun getGrade(score: Int) : String {
    var grade = when (score) {
           9, 10 -> "A"
           in 6..8 -> "B"
           4, 5 -> "C"
           in 1..3 -> "D"
           else -> "E"
    }
   return 
}

1.13 for循环

Java Kotlin
for (int i = 1; i <= 10; i++) { } for (i in 1..10) { }
for (int i = 1; 1 < 10; i++) for (i in 1 until 10) { }
for (int i = 10; 1 >= 0; i--) for (i in 10 downto 0) { }
for (int i = 1; 1 <= 10; i+=2) for (i in 1..10 step 2) { }
for (int i = 10; 1 >= 0; i-=2) for (i in 10 downto 0 step 2) { }
for (String item : collection) { } for (item in collection) { }
for (Map.Entry<String, String> entry : map.entrySet()) {} for ((key, value) in map) { }

1.14 集合操作
Java :

final List<Integer> listOfNumber = Arrays.asList(1, 2, 3, 4);

final Map<Integer, String> map = new HashMap<Integer, String>();
map.put(1, "Robin");
map.put(2, "Yeung");
map.put(3, "Coding");

Kotlin :

val listOfNumber = listOf(1, 2, 3, 4)
val map = mapOf(1 to "Robin", 2 to "Yeung", 3 to "Coding")

1.15 遍历
Java :

// Java 7
for (Car car : cars) {
    System.out.println(car.speed);
}

// Java 8+
cars.forEach(car -> System.out.println(car.speed));

// Java 7
for (Car car : cars) {
     if (car.speed > 100) {
          System.out.println(car.speed);
     }
}

// Java 8+
cars
    .stream()
    .filter(car -> car.speed > 100)
    .forEach(car -> System.out.println(car.speed));

Kotlin :

cars.forEach {
    println(it.speed)
}

cars
    .filter {
          it.speed > 100
     }
    .forEach {
          println(it.speed)
     }

1.16 构造器
Java :

public class Utils {
    private Utils() {
        // 外部无法来调用实例化
    }
    
    public static int getScore(int value) {
        return 2 * value;
    }
}

Kotlin :

class Utils private constructor() {
      companion object {         // 静态方法写在 companion object 里面
            fun getScore(value: Int): Int {
                return 2 * value
            }
      }
}

// 或者直接声明一个object对象(单例)
object Utils {
      fun getScore(value: Int): Int {
          return 2 * value
      }
}

2. Kotlin与Java互操作

2.1 Kotlin中使用反射
Kotlin中我们可以使用instance::class.java、ClassName::class.java或者instance.javaClass来进入Java的反射类java.lang.Class,之后我们就可以使用Java中的反射功能特性了.
代码实例 :

@RunWith(JUnit4::class) 
class ReflectClassTest {
      @Test
      fun testGetterSetter()  {
            val product = Product()
            val pClz = product::class.java
            println(pClz.canonicalName)
            pClz.declaredFields.forEach { println(it) }
            pClz.declaredMethods.forEach {
                  println(it.name)
                  it.parameters.forEach { println(it) }
            }
      }
}

2.1 Java调用Kotlin中单例(Singleton)静态成员或静态方法
如有一个Kotlin单例,该单例有一个静态成员和一个静态方法

// Kotlin 代码
object TestSingleton {
      val staticField = "我是单例的静态成员"
      fun void staticMethod() {
            println("调用单例的静态方法")
      }
}

则在Java端调用该单例的静态方法和静态成员的写法是 :

// Java代码
String message = TestSingleton.INSTANCE.staticField;
TestSingleton.INSTANCE.staticMethod();

Java调用Kotlin中单例的静态成员,需要使用 [单例类名].INSTANCE 来调用.

2.2 Java调用Kotlin中普通类的静态成员或静态方法
如有一个Kotlin普通类,该类有一个静态成员和一个静态方法

// Kotlin 代码
class TestNormalClass {
      companion object {
            val staticField = "我是普通类的静态成员String"
            fun void staticMethod() {
                  println("调用普通类的静态方法")
            }
      }
}

则在Java端调用该普通类的静态方法和静态成员的写法是 :

// Java代码
String message = TestNormalClass.Companion.staticField;
TestNormalClass.Companion.staticMethod();

Java调用Kotlin中普通类的静态成员,需要使用 [普通类类名].Companion 来调用.

2.3 关键字冲突的互操作
一些Kotlin关键字在Java中是有效标识符,如in、object、is等.
如果一个Java库使用了Kotlin关键字作为方法,我们可以通过反引号( ` )字符转义它来调用该方法.例如我们有个Java类,其中有个is方法:

public class MathTools {
      public boolean is(Object o) {
            return true;
      }
}

那么,我们在Kotlin代码这样调用这个is方法 :

val = MathTools().`is`(1)      // is在kotlin中是判断类型的关键字,这里用反引号(`)转义来调用java代码

3. Kotlin进阶

3.1 内联函数inline
kotlin中使用高阶函数造成一些运行时问题:每一个函数都是一个对象,它会持有一个闭包;即在函数体中可以访问这些变量。内存分配(包括函数对象和类)及虚拟调用都会作为运行开销。
inline和reified的应用,简洁代码 :

// reified : 英文是具体化的意思,这里用reified指明T的类型为View或者View的子类
inline fun <reified T : View> getView(resId: Int)
            = viewGroup.findViewById(resId) as? T

// 调用时指定类型
val ivTest : ImageView = getView<ImageView>(R.id.ivTest)

3.2 Kotlin委托
委托模式是软件设计模式中的一项基本技巧。在委托模式中,有两个对象参与处理同一个请求,接受请求的对象将请求委托给另一个对象来处理。

类委托
类的委托即一个类中定义的方法实际是调用另一个类的对象的方法来实现的。

以下实例中派生类 Derived 继承了接口 Base 所有方法,并且委托一个传入的 Base 类的对象来执行这些方法。

// 创建接口
interface Base {   
    fun print()
}

// 实现此接口的被委托的类
class BaseImpl(val x: Int) : Base {
    override fun print() { print(x) }
}

// 通过关键字 by 建立委托类
class Derived(b: Base) : Base by b

fun main(args: Array<String>) {
    val b = BaseImpl(10)
    Derived(b).print() // 输出 10
}

在 Derived 声明中,by 子句表示,将 b 保存在 Derived 的对象实例内部,而且编译器将会生成继承自 Base 接口的所有方法, 并将调用转发给 b。

属性委托
属性委托指的是一个类的某个属性值不是在类中直接进行定义,而是将其托付给一个代理类,从而实现对该类的属性统一管理。

属性委托语法格式:

val/var <属性名>: <类型> by <表达式>

  • var/val:属性类型(可变/只读)
  • 属性名:属性名称
  • 类型:属性的数据类型
  • 表达式:委托代理类

by 关键字之后的表达式就是委托, 属性的 get() 方法(以及set() 方法)将被委托给这个对象的 getValue() 和 setValue() 方法。属性委托不必实现任何接口, 但必须提供 getValue() 函数(对于 var属性,还需要 setValue() 函数)。

定义一个被委托的类
该类需要包含 getValue() 方法和 setValue() 方法,且参数 thisRef 为进行委托的类的对象,prop 为进行委托的属性的对象。

import kotlin.reflect.KProperty
// 定义包含属性委托的类
class Example {
    var p: String by Delegate()
}

// 委托的类
class Delegate {
    operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
        return "$thisRef, 这里委托了 ${property.name} 属性"
    }

    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
        println("$thisRef 的 ${property.name} 属性赋值为 $value")
    }
}
fun main(args: Array<String>) {
    val e = Example()
    println(e.p)     // 访问该属性,调用 getValue() 函数

    e.p = "Runoob"   // 调用 setValue() 函数
    println(e.p)
}

输出结果为 :

Example@433c675d, 这里委托了 p 属性
Example@433c675d 的 p 属性赋值为 Runoob
Example@433c675d, 这里委托了 p 属性

标准委托
Kotlin 的标准库中已经内置了很多工厂方法来实现属性的委托。
延迟属性 Lazy
lazy() 是一个函数, 接受一个 Lambda 表达式作为参数, 返回一个 Lazy <T> 实例的函数,返回的实例可以作为实现延迟属性的委托: 第一次调用 get() 会执行已传递给 lazy() 的 lamda 表达式并记录结果, 后续调用 get() 只是返回记录的结果。

val lazyValue: String by lazy {
    println("computed!")     // 第一次调用输出,第二次调用不执行
    "Hello"
}

fun main(args: Array<String>) {
    println(lazyValue)   // 第一次执行,执行两次输出表达式
    println(lazyValue)   // 第二次执行,只输出返回值
}

执行输出结果:

computed!
Hello
Hello

可观察属性 Observable
observable 可以用于实现观察者模式。
Delegates.observable() 函数接受两个参数: 第一个是初始化值, 第二个是属性值变化事件的响应器(handler)。
在属性赋值后会执行事件的响应器(handler),它有三个参数:被赋值的属性、旧值和新值:

import kotlin.properties.Delegates

class User {
    var name: String by Delegates.observable("初始值") {
        prop, old, new ->
        println("旧值:$old -> 新值:$new")
    }
}

fun main(args: Array<String>) {
    val user = User()
    user.name = "第一次赋值"
    user.name = "第二次赋值"
}

执行输出结果:

旧值:初始值 -> 新值:第一次赋值
旧值:第一次赋值 -> 新值:第二次赋值

把属性储存在映射中
一个常见的用例是在一个映射(map)里存储属性的值。 这经常出现在像解析 JSON 或者做其他"动态"事情的应用中。 在这种情况下,你可以使用映射实例自身作为委托来实现委托属性。

class Site(val map: Map<String, Any?>) {
    val name: String by map
    val url: String  by map
}

fun main(args: Array<String>) {
    // 构造函数接受一个映射参数
    val site = Site(mapOf(
        "name" to "菜鸟教程",
        "url"  to "www.runoob.com"
    ))
    
    // 读取映射值
    println(site.name)
    println(site.url)
}

执行输出结果:

菜鸟教程
www.runoob.com

如果使用 var 属性,需要把 Map 换成 MutableMap:

class Site(val map: MutableMap<String, Any?>) {
    var name: String by map
    var url: String by map
}

fun main(args: Array<String>) {

    var map:MutableMap<String, Any?> = mutableMapOf(
            "name" to "菜鸟教程",
            "url" to "www.runoob.com"
    )

    val site = Site(map)

    println(site.name)
    println(site.url)

    println("--------------")
    map.put("name", "Google")
    map.put("url", "www.google.com")

    println(site.name)
    println(site.url)
}

执行输出结果:

菜鸟教程
www.runoob.com
--------------
Google
www.google.com

局部委托属性
你可以将局部变量声明为委托属性。 例如,你可以使一个局部变量惰性初始化:

fun example(computeFoo: () -> Foo) {
    val memoizedFoo by lazy(computeFoo)

    if (someCondition && memoizedFoo.isValid()) {
        memoizedFoo.doSomething()
    }
}

memoizedFoo 变量只会在第一次访问时计算。 如果 someCondition 失败,那么该变量根本不会计算。

4.Kotlin函数式编程

5. Kotlin扩展库的使用

5.1 LayoutContainer的使用,和findViewId()方法彻底说Bye Bye.

在Java中,Activity通过findViewById()方法得到XML布局文件里控件的引用,如果XML里面有很多控件,就要写一大堆findViewById()方法,是不是觉得很烦.幸好在Kotlin里已经帮我们做了这些操作.

// Using R.layout.activity_main from the 'main' source set
import kotlinx.android.synthetic.main.activity_main.*    // 这段代码就是导入activity_main里面的所有控件引用,导入后就可以直接使用

class MyActivity : Activity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        // Instead of using findViewById<TextView>(R.id.tvMessage)
        tvMessage.setText("Hello, world!")       // 通过xml的ResourceID直接使用控件
    }
}

在Activity和Fragment中,Kotlin自动帮我们导入了这些控件引用,但是在一些自定义控件和ViewHolder里面,Kotlin不会自动导入,这时我们就需要为这些自定义控件或者ViewHolder实现LayoutContainer接口.

import kotlinx.android.extensions.LayoutContainer

class ViewHolder(override val containerView: View) : ViewHolder(containerView), 
                  LayoutContainer {    // 实现LayoutContainer接口
    fun setup(title: String) {
        itemTitle.tvMessage = "Hello World!"      // 通过xml的ResourceID直接使用控件
    }
}

5.2 Coroutines的使用,彻底告别Handler和AsyncTask
详细用法跳转到(www.jianshu.com/p/04f28bbc66dc)

相关文章

网友评论

      本文标题:Java过渡到Kotlin

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