首页 > Java > java教程 > Java开发人员Kotlin(第1部分)

Java开发人员Kotlin(第1部分)

Mary-Kate Olsen
发布: 2025-01-27 16:04:17
原创
921 人浏览过

Kotlin for Java Developers (Part 1)

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记录和Kotlin数据类都是不可变的数据载体。
  • 在Java中,字段隐式为final,在构造后无法修改,而在Kotlin中,您可以通过使用val或var来选择是否要使字段可变。
  • 另一个区别是,Java中的记录类隐式为final和sealed,这意味着它们不能被扩展,而在Kotlin中,您可以扩展数据类。
  • 在Kotlin中,您还可以覆盖equals、hashCode和toString方法,这在Java中是不可能的。
  • Kotlin开箱即用地提供了一个copy方法,这在Java中是不可用的。

一些示例:

在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数据类
  • Baeldung:Kotlin数据类

利用空安全

在我看来,Kotlin中的空安全是最强大的功能之一。这是一个改变游戏规则的功能,可以节省您大量的时间和麻烦。在Kotlin中,空安全内置于类型系统中,这使得更容易避免与空相关的运行时错误。

1. 可空类型

在Kotlin中,可空类型是显式声明的。这意味着您可以拥有一个可能保存空值的变量,但您必须在声明中显式指定它。

不可空类型(默认行为)

默认情况下,Kotlin中的所有类型都是不可空的,这意味着变量不能保存空值。

<code class="language-kotlin">val name: String = "John" // 不可空
name = null // 编译错误!</code>
登录后复制
登录后复制

可空类型

要声明一个可以保存空值的变量,您必须使用?运算符。

<code class="language-kotlin">val name: String? = null // 可空</code>
登录后复制

2. 安全调用

一个强大的功能是安全调用运算符?.。它允许您安全地调用方法或访问属性,而不会抛出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。

3. Elvis运算符(?:)

Elvis运算符?:是如果运算符左侧的表达式为空则返回默认值的简写。

<code class="language-java">public record Person(
    String name,
    int age
) {
}</code>
登录后复制
登录后复制
登录后复制

4. !!运算符(非空断言)

您可以使用!!运算符告诉编译器该值不为空。如果该值为null,它将抛出NullPointerException。

<code class="language-kotlin">data class Person(val name: String, var age: Int)</code>
登录后复制
登录后复制
登录后复制

提示: 不建议使用此!!运算符,因为它违背了空安全的目的。

5. 函数参数中的可空性

定义函数时,您可以指定参数是否可以为空。在这种情况下,调用者必须处理它。

<code class="language-java">Person p2 = new Person(p1.getName(), p1.getAge());</code>
登录后复制
登录后复制
登录后复制

6. 安全转换(as?运算符)

有一个安全转换运算符as?,如果转换不可行,则返回null。

<code class="language-kotlin">val p2 = p1.copy(age = 42)</code>
登录后复制
登录后复制
登录后复制

7. lambda表达式中的空安全

您还可以在lambda表达式和高阶函数中使用空安全功能:

<code class="language-java">String name = p1.getName();
int age = p1.getAge();</code>
登录后复制
登录后复制
登录后复制

8. 利用let函数

let函数是一个作用域函数,允许您在非空对象上执行代码块。它通常用于以安全的方式在可空对象上执行代码。

示例以及默认值:

<code class="language-kotlin">val (name, age) = p1
println(name) // "John"
println(age) // 42</code>
登录后复制
登录后复制

9. 最佳实践

  • 避免使用!!运算符
  • 使用安全调用和Elvis运算符安全地处理可空类型并提供默认值
  • 仅在必要时才使用可空类型

参考:

  • Kotlin空安全

默认情况下不可变性

Kotlin强烈鼓励函数式编程风格!对于函数式编程风格,不可变性在避免错误方面起着至关重要的作用,尤其是在多线程应用程序中。

我现在可能要写一篇关于Kotlin或Java中函数式编程的单独文章,但现在让我们关注不可变性。

Kotlin本质上更喜欢不可变对象而不是可变对象。这导致代码更简单、更可预测,尤其是在并发环境中。

1. 默认情况下不可变的变量(val)

在Kotlin中,使用val关键字声明的变量默认情况下是不可变的。这与在Java中声明final变量非常接近,但有一些关键区别:

  • Kotlin中的val变量实际上是只读的——在初始化后不能更改分配给它的值。
  • 但是,如果该值是一个对象,则仍然可以修改该对象的属性,除非这些属性本身声明为val。

示例:

<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来确保不可变性。

2. 不可变集合

默认情况下也鼓励使用不可变集合。不可变集合防止在创建后进行任何修改,例如,如果您使用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)默认情况下是可变的,这意味着可以自由修改元素。

3. 不可变数据类

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>
登录后复制
登录后复制
登录后复制

4. 密封类中的不可变性

Kotlin的密封类也可以是不可变的,并且它们与不可变数据模型配合良好。密封类通常用于表示受限的类层次结构,例如状态或响应,并且它们的不可变性确保状态或结果不会意外更改。

<code class="language-java">String name = p1.getName();
int age = p1.getAge();</code>
登录后复制
登录后复制
登录后复制

以上是Java开发人员Kotlin(第1部分)的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
作者最新文章
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板