Java 如何改为Kotlin(一)

重构为Kotlin

准备User类

public class User {

    private String firstName;
    private String lastName;

    public User(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

}

Java文件转换为Kotlin文件

选择XXX.java 文件,右键选择并将其转换为 Kotlin:Code -> Convert Java File to Kotlin File

声明可空性、val、var 和数据类

var 修饰可变变量

val 修饰不可变变量。val 类似于 Java 中的 final 关键字

Kotlin 文件的扩展名为 .kt

Kotlin 与 Java的一个区别在于:Kotlin 会明确指定变量能否接受 null 值。具体而言,其是通过在类型声明后附加"?"以进行此项指定

数据类

关键字 :data

data class User(var firstName: String?, var lastName: String?)

在将此类标记为 data 类后,编译器便会自动创建 getter 和 setter。此外,其还会派生 equals()hashCode()toString() 函数

data 类必须至少有一个主构造参数

多构造参数,例如:

data class User(var firstName: String, var lastName: String) {
    constructor(firstName: String) : this(firstName,"Tom") {}
}

您可在官方文档中阅读有关构造函数的更多内容

相等性

Kotlin 分为两类相等性:

  • 构成相等使用 == 运算符,并调用 equals() 来确定两个实例是否相等。
  • 引用相等使用 === 运算符,以检查两个引用是否指向同一对象
val user1 = User("Jane", "Doe")
val user2 = User("Jane", "Doe")
val structurallyEqual = user1 == user2 // true
val referentiallyEqual = user1 === user2 // false

您可在官方文档中阅读有关数据类的更多内容。

默认参数与命名参数

data class User(var firstName: String?, var lastName: String? = null)

// usage
val jane = User ("Jane") // same as User("Jane", null)
val joe = User ("John", "Doe")

默认参数 lastName 的默认值为 null,也可以这样写

val john = User (firstName = "John", lastName = "Doe") 

假如 firstNamenull 用作其默认值,而 lastName 并不如此。在此情况下,由于默认参数位于未设默认值的参数之前,因此您必须使用命名参数来调用此函数,具体如下:

data class User(var firstName: String? = null, var lastName: String?)

// usage
val jane = User (lastName = "Doe") // same as User(null, "Doe")
val john = User ("John", "Doe")

若您的函数具有多个参数,请考虑使用命名参数

对象初始化、伴生对象和单一实例

public class Repository {
    private static Repository INSTANCE = null;
    private List<User> users = null;


    public static Repository getInstance() {
        if (INSTANCE == null) {
            synchronized (Repository.class) {
                if (INSTANCE == null) {
                    INSTANCE = new Repository();
                }
            }
        }
        return INSTANCE;
    }

    public Repository() {
        User user1 = new User("Jane", "");
        User user2 = new User("Jane", null);
        User user3 = new User("Jane", "Doe");
        users = new ArrayList<>();

        users.add(user1);
        users.add(user2);
        users.add(user3);

    }

    public List<User> getUsers() {
        return users;
    }

    public List<String> getFormattedUserName() {
        List<String> userNames = new ArrayList<>(users.size());
        for (User user :
                users) {
            String name;
            if (user.getLastName() != null) {
                if (user.getFirstName() != null) {
                    name = user.getFirstName() + " " + user.getLastName();
                } else {
                    name = user.getLastName();
                }
            } else if (user.getFirstName() != null) {
                name = user.getFirstName();
            } else {
                name = "Unknown";
            }
            userNames.add(name);
        }
        return userNames;
    }
}

Repository 类转换为 Kotlin

class Repository {
    private var users: MutableList<User>? = null
    fun getUsers(): List<User>? {
        return users
    }

    val formattedUserName: List<String?>
        get() {
            val userNames: MutableList<String?> =
                ArrayList(users!!.size)
            for ((firstName, lastName) in users!!) {
                var name: String
                name = if (lastName != null) {
                    if (firstName != null) {
                        firstName + " " + lastName
                    } else {
                        lastName
                    }
                } else if (firstName != null) {
                    firstName
                } else {
                    "Unknown"
                }
                userNames.add(name)
            }
            return userNames
        }

    companion object {
        private var INSTANCE: Repository? = null
        val instance: Repository?
            get() {
                if (INSTANCE == null) {
                    synchronized(Repository::class.java) {
                        if (INSTANCE == null) {
                            INSTANCE = Repository()
                        }
                    }
                }
                return INSTANCE
            }
    }

    init {
        val user1 = User("Jane", "")
        val user2 = User("Jane", null)
        val user3 = User("Jane", "Doe")
        users = ArrayList()
        users!!.add(user1)
        users!!.add(user2)
        users!!.add(user3)
    }
}

我们来看一下自动转换器执行了哪些操作:

  • 添加了 init 代码块

  • static 字段现已加入 companion object 代码块中

  • users 列表可为 null,因为该对象在声明时并未实例化

  • getFormattedUserNames() 方法现已成为一个属性

  • 在对用户列表执行循环时,其语法与 Java 不同

    等效规则:

    KotlinJava
    init块构造函数
    companion object静态属性和静态方法 (static)

init块

在 Kotlin 中,主构造函数无法包含任何代码,因此初始化代码会置于 init 块中

class Repository private constructor() {
    ...
    init {

        val user1 = User("Jane", "")
        val user2 = User("John", null)
        val user3 = User("Anne", "Doe")

        users = ArrayList()
        users!!.add(user1)
        users.add(user2)
        users.add(user3)
    }

}

init 代码大都用于处理属性的初始化。这项操作也可在声明属性时完成。例如,在 Kotlin 版本的 Repository 类中,我们可以看到,users 属性已在声明时进行初始化

private val users: MutableList<User>? = null

您可在官方文档中阅读有关初始化程序块的更多内容

Kotlin 的"静态"属性与"静态"方法

在 Java 中,我们会在字段或函数中使用 static 关键字,以指出此等字段或函数属于某个类,但不属于该类的某个实例。因此,我们在 Repository 类中创建了 INSTANCE 静态字段。在 Kotlin 中,companion object 代码块与此等效。您还可在此处声明静态字段和静态函数。转换器已创建 INSTANCE 字段并将其移至此处

处理单一实例

由于只需要Repository 类的一个实例,因此我们在 Java 中使用了单一实例模式

在 Kotlin 中,通过将 class 关键字替换为 object,可以在编译器级别强制使用此模式

现在,我们可以移除私有构造函数和伴生对象(companion object

object Repository {
    private var users: MutableList<User>? = null
     fun getUsers(): List<User>? {
        return users
    }

    val formattedUserName: List<String?>
        get() {
            val userNames: MutableList<String?> =
                ArrayList(users!!.size)
            for ((firstName, lastName) in users!!) {
                var name: String?
                name = if (lastName != null) {
                    if (firstName != null) {
                        firstName + " " + lastName
                    } else {
                        lastName
                    }
                } else if (firstName != null) {
                    firstName
                } else {
                    "Unknown"
                }
                userNames.add(name)
            }
            return userNames
        }



    init {
        val user1 = User("Jane", "")
        val user2 = User("Jane", null)
        val user3 = User("Jane", "Doe")
        users = ArrayList()
        users!!.add(user1)
        users!!.add(user2)
        users!!.add(user3)
    }
}

使用 object 类时,我们直接在对象上调用函数和属性,如下所示:

val users = Repository.getUsers()

您可在官方文档中阅读有关对象和伴生对象的更多内容

解构

Kotlin 允许使用名为解构声明的语法,将对象解构为多个变量。我们可以创建多个变量,并能独立使用这些变量

例如,数据类支持解构,因此自动转换器能够将 for 循环中的 User 对象解构。如此一来,我们便可直接处理 firstNamelastName 值,具体如下:

for ((firstName, lastName) in users) {
       val name: String?

       if (lastName != null) {
          if (firstName != null) {
                name = "$firstName $lastName"
          } 
       ...

您可在官方文档中阅读有关解构声明的更多内容

处理可空性

Repository 类转换为 Kotlin 时,自动转换器已将用户列表设为可为 null,这是由于我们在声明时并未将其初始化为对象。在 users 对象的所有使用情境中,我们都使用了非 null 断言运算符 !!。该运算符可将所有变量转换为非 null 类型,并在值为 null 时抛出异常。使用 !! 时,存在运行时抛出异常的风险

建议您使用下列其中一种方法来处理可空性:

  • 执行 null 检查 (if (users != null) {...})
  • 使用 Elvis 运算符 ?:
  • 使用某些 Kotlin 标准函数

您可在官方文档中阅读有关空安全的更多内容

创建集合类实例时,您可以利用 Kotlin 所提供的多个帮助程序函数,让代码更易阅读而且更为灵活。本例中,我们将 MutableList 用于 users,具体如下:

private val users: MutableList<User>? = null

为简单起见,我们可以使用 mutableListOf() 函数,提供列表元素类型,从 init 代码块中移除 ArrayList 构造函数调用,然后移除 users 属性的显式类型声明,具体如下:

private val users = mutableListOf<User>()

作出此项更改后,users 属性现已变为非 null,我们此时亦可移除所有不必要的 !! 运算符实例

运算符:

!! 非 null 断言运算符 ,该运算符可将所有变量转换为非 null 类型,并在值为 null 时抛出异常。使用 !! 时,存在运行时抛出异常的风险

?: Elvis 运算符 若左侧表达式不为 null,则 Elvis 运算符将返回该表达式,否则便会返回右侧表达式

user.firstName 不为 null,以下代码便会返回此值。若 user.firstName 为 null,该表达式将返回右侧值 "Unknown",具体如下:

if (lastName != null) {
    ...
} else {
    name = firstName ?: "Unknown"
}

您可在官方文档中阅读有关 Elvis 运算符的更多内容

字符串模板和 if 表达式

借助字符串模板,Kotlin 将能简化 String 的处理工作。字符串模板允许在字符串声明内引用变量

使用 $ 符号直接在字符串内引用变量名称,并可将表达式置于 { } 之间

// Java
name = user.getFirstName() + " " + user.getLastName();

// Kotlin
name = "${user.firstName} ${user.lastName}"

在 Kotlin 中,ifwhenforwhile 均为表达式,它们有返回值。

我们将if 语句的最后一行将被用于赋值。如下所示,我们可以更清晰地看到,此代码块的唯一目的便是初始化 name 值:

name = if (firstName != null) {   // do something   
firstName  
}
// name = firstName 

从 if 语句中移出赋值的做法很容易遭到滥用。请确保您的 if 代码块仅具有一个角色,且不会产生其他附带后果

接下来,页面会弹出警告,提示我们可以将 name 声明与赋值合并。同样,我们继续遵照该警告进行操作。由于可以推导出名称变量的类型,因此我们可以移除显式类型声明。现在,formattedUserNames 将如下所示:

val formattedUserNames: List<String>
        get() {
            val userNames = ArrayList<String>(users.size)
            for ((firstName, lastName) in users) {
                val name = if (lastName != null) {
                    if (firstName != null) {
                        "$firstName $lastName"
                    } else {
                        lastName ?: "Unknown"
                    }
                } else {
                    firstName ?: "Unknown"
                }

                userNames.add(name)
            }
            return userNames
        }

您可在官方文档中阅读有关 ifwhenforwhile 的更多内容

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值