Java在编程语言中占据主导地位,因此我多次看到Java开发人员在使用Kotlin时犯同样的错误。别误会,这不是说这些是bug,而是当开发人员习惯于在Java中进行开发时,在Kotlin中倾向于产生“代码异味”,没有利用Kotlin的功能。
本文将使您了解我经常看到的代码异味以及如何在“Kotlin方式”中理想地实现它们。
本系列的第1部分将涵盖:
这个主题可能很快就会消失,因为我越来越多的Java开发人员也有使用记录类的经验。尽管如此,Java记录和Kotlin数据类之间还是有一些区别。
Java方式:
<code class="language-java">public class Person { private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } // Getters, setters, ... }</code>
或者作为记录:
<code class="language-java">public record Person( String name, int age ) { }</code>
Kotlin方式:
<code class="language-kotlin">data class Person(val name: String, var age: Int)</code>
您可能需要了解Java记录和Kotlin数据类之间的一些区别。
一些示例:
在Java中复制对象
<code class="language-java">Person p2 = new Person(p1.getName(), p1.getAge());</code>
Kotlin:
<code class="language-kotlin">val p2 = p1.copy(age = 42)</code>
或者在Java中解构声明:
<code class="language-java">String name = p1.getName(); int age = p1.getAge();</code>
Kotlin:
<code class="language-kotlin">val (name, age) = p1 println(name) // "John" println(age) // 42</code>
在我看来,Kotlin中的空安全是最强大的功能之一。这是一个改变游戏规则的功能,可以节省您大量的时间和麻烦。在Kotlin中,空安全内置于类型系统中,这使得更容易避免与空相关的运行时错误。
在Kotlin中,可空类型是显式声明的。这意味着您可以拥有一个可能保存空值的变量,但您必须在声明中显式指定它。
不可空类型(默认行为)
默认情况下,Kotlin中的所有类型都是不可空的,这意味着变量不能保存空值。
<code class="language-kotlin">val name: String = "John" // 不可空 name = null // 编译错误!</code>
可空类型
要声明一个可以保存空值的变量,您必须使用?运算符。
<code class="language-kotlin">val name: String? = null // 可空</code>
一个强大的功能是安全调用运算符?.。它允许您安全地调用方法或访问属性,而不会抛出NullPointerException。
示例
<code class="language-java">public class Person { private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } // Getters, setters, ... }</code>
?.运算符检查对象是否为空,如果为空,则立即返回null,否则继续调用方法或访问属性。如果对象为空,则整个表达式计算结果为null。
Elvis运算符?:是如果运算符左侧的表达式为空则返回默认值的简写。
<code class="language-java">public record Person( String name, int age ) { }</code>
您可以使用!!运算符告诉编译器该值不为空。如果该值为null,它将抛出NullPointerException。
<code class="language-kotlin">data class Person(val name: String, var age: Int)</code>
提示: 不建议使用此!!运算符,因为它违背了空安全的目的。
定义函数时,您可以指定参数是否可以为空。在这种情况下,调用者必须处理它。
<code class="language-java">Person p2 = new Person(p1.getName(), p1.getAge());</code>
有一个安全转换运算符as?,如果转换不可行,则返回null。
<code class="language-kotlin">val p2 = p1.copy(age = 42)</code>
您还可以在lambda表达式和高阶函数中使用空安全功能:
<code class="language-java">String name = p1.getName(); int age = p1.getAge();</code>
let函数是一个作用域函数,允许您在非空对象上执行代码块。它通常用于以安全的方式在可空对象上执行代码。
示例以及默认值:
<code class="language-kotlin">val (name, age) = p1 println(name) // "John" println(age) // 42</code>
Kotlin强烈鼓励函数式编程风格!对于函数式编程风格,不可变性在避免错误方面起着至关重要的作用,尤其是在多线程应用程序中。
我现在可能要写一篇关于Kotlin或Java中函数式编程的单独文章,但现在让我们关注不可变性。
Kotlin本质上更喜欢不可变对象而不是可变对象。这导致代码更简单、更可预测,尤其是在并发环境中。
在Kotlin中,使用val关键字声明的变量默认情况下是不可变的。这与在Java中声明final变量非常接近,但有一些关键区别:
示例:
<code class="language-kotlin">val name: String = "John" // 不可空 name = null // 编译错误!</code>
与Java的区别:在Java中,我们使用final关键字来确保变量不能重新赋值,但它指向的对象仍然可以是可变的。Kotlin中的关键区别在于,不可变性默认情况下扩展到变量,这鼓励为整个应用程序设计更可预测和更安全的方案。
可变变量示例:在Kotlin中使用var关键字允许您重新赋值变量。
<code class="language-java">public class Person { private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } // Getters, setters, ... }</code>
提示: Kotlin鼓励尽可能使用val而不是var来确保不可变性。
默认情况下也鼓励使用不可变集合。不可变集合防止在创建后进行任何修改,例如,如果您使用listOf()创建List,则不能更改它,不能添加、删除或更改任何元素。
<code class="language-java">public record Person( String name, int age ) { }</code>
如果您需要修改集合,可以使用mutableListOf()或其他可变集合类型。
<code class="language-kotlin">data class Person(val name: String, var age: Int)</code>
与Java的区别:在Java中,集合(例如ArrayList)默认情况下是可变的,这意味着可以自由修改元素。
Kotlin的数据类默认情况下是不可变的。定义数据类时,属性通常声明为val,使类不可变。这使得类非常适合值对象,尤其是在处理API、数据库记录或任何其他对象状态在创建后不应更改的场景时。
<code class="language-java">Person p2 = new Person(p1.getName(), p1.getAge());</code>
<code class="language-kotlin">val p2 = p1.copy(age = 42)</code>
Kotlin的密封类也可以是不可变的,并且它们与不可变数据模型配合良好。密封类通常用于表示受限的类层次结构,例如状态或响应,并且它们的不可变性确保状态或结果不会意外更改。
<code class="language-java">String name = p1.getName(); int age = p1.getAge();</code>
以上是Java开发人员Kotlin(第1部分)的详细内容。更多信息请关注PHP中文网其他相关文章!