Java 如何改为Kotlin(二)

Java 如何改为Kotlin(二)
针对集合的操作

Kotlin 提供各类集合转换,通过扩充 Java Collections API 的功能,加快开发速度并提升安全性。

map 函数

该函数会返回一个新列表,包含对原数组中每个元素调用指定转换函数后的结果。这样,我们就不必手动创建新列表并对用户列表进行迭代,而可以使用 map 函数,并替换 map 内部 for 循环中的逻辑. 例如:

 val formatUserNames: List<String>
        get() {
            return users!!.map { user ->
                val name = if (user.lastName != null) {
                    if (user.firstName != null) {
                        "${user.firstName} ${user.lastName}"
                    } else {
                        user.lastName ?: "Unknown"
                    }
                } else {
                    user.firstName ?: "Unknown"
                }
                name
            }
        }

为进一步简化,我们还可完全移除 name 变量

val formatUserNames: List<String>
    get() {
        return users!!.map { user ->
            if (user.lastName != null) {
                if (user.firstName != null) {
                    "${user.firstName} ${user.lastName}"
                } else {
                    user.lastName ?: "Unknown"
                }
            } else {
                user.firstName ?: "Unknown"
            }
        }
    }
属性和支持属性

示例:

Repository 类中存在可变的用户列表,该列表会在函数 getUsers 中公开,而该函数则由 Java 代码生成,具体如下:

fun getUsers(): List<User>? {    return users }

但此处存在一个问题:由于返回 users,Repository 类的任何使用者都能够修改用户列表,这并不是一种明智的做法!下面我们将使用支持属性解决这一问题。

首先,将 users 重命名为 _users。然后添加公用的不可变属性,使其返回用户列表。将其命名为 users,具体如下:

private val _users = mutableListOf<User>()
val users:List<User>
 get() = _users

进行此项更改后,私有 _users 属性将变为公用 users 属性的支持属性。在 Repository 类外部,由于该数据类的使用者只能通过 users 来访问 _users 列表,因此该列表不可变,也不可以在外部调用其add方法,如

Repositoryk.getUsers().add(...) // 该方法不可以调用
顶层函数与扩展函数及其各自属性

Kotlin 支持在任何类、对象或接口的外部声明函数和属性。例如,用于创建新 List 实例的 mutableListOf() 函数便直接在标准库内的 Collections.kt 中定义

在 Java 中,每当需要一些实用程序功能时,您大都会创建一个 Util 类,并将该功能声明为静态函数。而在 Kotlin 中,您可以声明顶层函数,无需使用类。不过,Kotlin 还支持创建扩展函数。这些函数可扩展特定类型,但在该类型外部声明。因此,它们与该类型具有亲和性

当我们缺少某个类的所有权,或由于某个类不允许继承时,我们均需扩展该类的功能。为此,Kotlin 已创建名为扩展的特殊声明。Kotlin 支持扩展函数和扩展属性。

您可使用可见性修饰符来限制扩展函数及扩展属性的可见性。这些修饰符仅向需要扩展的类开放扩展功能,且不会污染命名空间。

对于 User 类,我们可以添加一个扩展函数以计算格式化名称,或将格式化名称存放于扩展属性中。我们可以在 Repository 类的外部但位于同一文件中添加该扩展函数,具体如下:

// extension function
fun User.getFormattedName(): String {
    return if (lastName != null) {
        if (firstName != null) {
            "$firstName $lastName"
        } else {
            lastName ?: "Unknown"
        }
    } else {
        firstName ?: "Unknown"
    }
}

// extension property
val User.userFormattedName: String
    get() {
        return if (lastName != null) {
            if (firstName != null) {
                "$firstName $lastName"
            } else {
                lastName ?: "Unknown"
            }
        } else {
            firstName ?: "Unknown"
        }
    }

// usage:
val user = User(...)
val name = user.getFormattedName()
val formattedName = user.userFormattedName

然后,我们便可使用这些扩展函数和扩展属性,就如同它们是 User 类的组成部分一般

由于格式化名称是 User 的一个属性,而非 Repository 类的某项功能,因此我们应该扩展属性。Repository 文件内容现如下所示:

val User.formattedName: String
    get() {
        return if (lastName != null) {
            if (firstName != null) {
                "$firstName $lastName"
            } else {
                lastName ?: "Unknown"
            }
        } else {
            firstName ?: "Unknown"
        }
    }

object Repository {

    private val _users = mutableListOf<User>()
    val users: List<User>
      get() = _users

    val formattedUserNames: List<String>
        get() {
            return _users.map { user -> user.formattedName }
        }

    init {

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

        _users.add(user1)
        _users.add(user2)
        _users.add(user3)
    }
}

Kotlin 标准库使用扩展函数来扩展多个 Java API 的功能;IterableCollection 上的许多功能则以扩展函数的形式实现。例如,我们在上一步使用的 map 函数即为 Iterable 上的扩展函数

作用域函数:let、apply、with、run、also

为了仅在特定对象的上下文中执行代码,而无需根据名称来访问该对象,Kotlin 专门创建了 5 个作用域函数,即:letapplywithrunalso。这些函数虽简洁但功能强大,它们均具有接收器 (this),可以带有参数 (it),还有可能返回值。您可根据自己想要实现的目标,以决定使用哪个函数。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-D4b8l8XQ-1602485944287)(C:\Users\Administrator\Pictures\作用域函数.png)]

由于要在 Repository 中配置 _users 对象,我们可以使用 apply 函数,让代码更加符合使用习惯,具体如下:

init {
    val user1 = User("Jane", "")
    val user2 = User("John", null)
    val user3 = User("Anne", "Doe")
   
    _users.apply {
       // this == _users
       add(user1)
       add(user2)
       add(user3)
    }
 }

您可在官方文档中阅读有关作用域函数的更多内容

进一步优化Repository类,即直接在声明中通过用户对 _users 列表进行实例化,从而免于使用 init 块,具体如下:

private val users = mutableListOf(User("Jane", ""), User("John", null), User("Anne", "Doe"))

最后的文件如下:

User.kt

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

Repository.kt

val User.formattedName: String
    get() {
       return if (lastName != null) {
            if (firstName != null) {
                "$firstName $lastName"
            } else {
                lastName ?: "Unknown"
            }
        } else {
            firstName ?: "Unknown"
        }
    }

object Repository {

    private val _users = mutableListOf(User("Jane", ""), User("John", null), User("Anne", "Doe"))
    val users: List<User>
        get() = users

    val formattedUserNames: List<String>
        get() {
            _users.map { user -> user.formattedName }
        }
}

以下是 Java 功能及对应至 Kotlin 的概要:

JavaKotlin
final 对象val 对象
equals()==
=====
仅存放数据的类data
构造函数中的初始化init 块中的初始化
static 字段和函数companion object 中声明的字段和函数
单一实例类object

参考:Kotlin for Java

<think>我们之前已经提供了Python服务端和Android客户端(Kotlin)的UDP测试代码。现在用户要求将Android客户端的Kotlin代码改为Java代码。 注意:XML布局文件和Python服务端代码保持不变,只需将Kotlin的MainActivity转换为Java。 步骤: 1.Kotlin代码转换为Java代码,保持相同的逻辑。 2. 注意Java中网络操作需要在子线程中执行,使用Thread或AsyncTask(但AsyncTask已过时,推荐使用Thread+Handler)。 3. 更新UI需要使用Handler从后台线程切换到主线程。 以下提供转换后的Java代码: </think>### 将Android UDP客户端从Kotlin转为Java实现 以下是将原Kotlin实现的UDP客户端转换为Java版本的完整解决方案: #### XML布局文件 (保持不变) ```xml <!-- res/layout/activity_main.xml --> <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="16dp"> <EditText android:id="@+id/etMessage" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="输入测试消息"/> <Button android:id="@+id/btnSend" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="发送UDP消息"/> <TextView android:id="@+id/tvResponse" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="服务器响应将显示在这里" android:paddingTop="16dp"/> </LinearLayout> ``` #### Java客户端实现 (MainActivity.java) ```java import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; import androidx.appcompat.app.AppCompatActivity; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; public class MainActivity extends AppCompatActivity { private Button btnSend; private EditText etMessage; private TextView tvResponse; private Handler handler; private static final String SERVER_IP = "192.168.x.x"; // 替换为实际IP private static final int SERVER_PORT = 12345; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 初始化UI组件 btnSend = findViewById(R.id.btnSend); etMessage = findViewById(R.id.etMessage); tvResponse = findViewById(R.id.tvResponse); handler = new Handler(Looper.getMainLooper()); // 主线程Handler[^2] // 设置发送按钮点击事件 btnSend.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { new Thread(new Runnable() { @Override public void run() { sendUdpMessage(etMessage.getText().toString()); } }).start(); } }); } private void sendUdpMessage(String message) { try { // 创建UDP套接字和数据包 DatagramSocket socket = new DatagramSocket(); byte[] sendData = message.getBytes("UTF-8"); InetAddress serverAddress = InetAddress.getByName(SERVER_IP); // 发送数据包 DatagramPacket sendPacket = new DatagramPacket( sendData, sendData.length, serverAddress, SERVER_PORT ); socket.send(sendPacket); // 接收响应 byte[] receiveBuffer = new byte[1024]; DatagramPacket receivePacket = new DatagramPacket( receiveBuffer, receiveBuffer.length ); socket.receive(receivePacket); // 解析响应 String response = new String( receivePacket.getData(), 0, receivePacket.getLength(), "UTF-8" ); // 更新UI handler.post(new Runnable() { @Override public void run() { tvResponse.setText("服务器响应: " + response); } }); socket.close(); } catch (Exception e) { e.printStackTrace(); handler.post(new Runnable() { @Override public void run() { tvResponse.setText("错误: " + e.getMessage()); } }); } } } ``` #### AndroidManifest.xml 权限添加 ```xml <!-- 添加网络权限 --> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> ``` ### 关键修改说明 1. **线程处理**: ```java new Thread(new Runnable() { @Override public void run() { // 网络操作 } }).start(); ``` Java使用显式线程代替Kotlin的线程简写语法,确保网络操作在子线程执行[^2] 2. **Handler机制**: ```java handler = new Handler(Looper.getMainLooper()); handler.post(new Runnable() { ... }); // UI更新 ``` 确保UI更新在主线程执行,避免`NetworkOnMainThreadException` 3. **类型转换**: ```java // Kotlin中:etMessage.text.toString() // Java中:etMessage.getText().toString() ``` Java使用getter方法访问视图属性 4. **异常处理**: Java要求更严格的异常捕获,所有网络操作需包裹在`try-catch`中 ### 部署流程 1. **服务端部署**: ```bash $ python udp_server.py UDP服务器已启动,等待客户端消息... ``` 2. **客户端配置**: ```java private static final String SERVER_IP = "192.168.1.100"; // 实际电脑IP ``` 3. **网络要求**: - 确保手机与电脑在同一局域网 - 关闭防火墙或开放UDP 12345端口 - 电脑IP不能是`127.0.0.1`或`localhost` 4. **通信流程**: $$ \begin{cases} \text{Android} & \xrightarrow{\text{UDP数据报}} \text{Python服务端} \\ \text{Python服务端} & \xrightarrow{\text{响应数据报}} \text{Android} \end{cases} $$ ### 性能优化建议 1. **超时设置**: ```java socket.setSoTimeout(3000); // 设置3秒接收超时 ``` 2. **缓冲区复用**: ```java // 避免每次创建新数组 private final byte[] buffer = new byte[1024]; ``` 3. **连接保持**: ```java // 重用Socket替代每次创建 if (socket == null) { socket = new DatagramSocket(); } ``` ### UDP协议特性 UDP协议提供无连接通信,其报文传输延时$D$可表示为: $$ D = T_{\text{proc}} + T_{\text{trans}} + T_{\text{prop}} + T_{\text{queue}} $$ 其中$T_{\text{proc}}$为处理延时,$T_{\text{trans}}$为传输延时,$T_{\text{prop}}$为传播延时,$T_{\text{queue}}$为排队延时。UDP省去了TCP的连接建立开销,在局域网环境通常能达到$D < 50ms$的延迟[^2]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值