IDE操作:将Java文件转换为Kotlin文件

如果您使用的是Android Studio,那么开始学习Kotlin的最简单方法是用Java编写测试类,然后通过Code → Convert Java File to Kotlin File从菜单栏中选择将其转换为Kotlin 。

此操作可能会问您“执行此转换后,项目其余部分的某些代码可能需要更正。您是否想要找到这样的代码并进行更正?” 我建议选择“  ”,以便您一次只关注一个文件。

尽管此操作会生成Kotlin代码,但生成的内容通常会留下改进的空间。以下各节重点介绍了我们从数十种针对此类自动生成的代码的代码回顾中收集的常见技巧。当然,Kotlin语言的功能远不止下面讨论的内容,但是为了使本指南保持重点,它仅关注我们观察到的重复出现的问题。

高级语言比较

Java和Kotlin在高层看起来非常相似。以下是用Java然后用Kotlin编写的框架测试类。

/// Java 
公共类ExampleTest {
@Test
公共 无效 testMethod1()抛出异常 {} @Test
公共 无效 testMethod2()抛出异常 {}
} //// Kotlin
类ExampleTest {
@Test
乐趣testMethod1(){} @Test
乐趣testMethod2 (){}
}

值得注意的是Kotlin中精简的内容:

  • 默认情况下,方法和类是公共的。
  • void返回类型并不需要显式声明。
  • 没有检查的异常。

分号是可选的

这是一开始可能真的感到不舒服的更改之一。在实践中,您无需太担心。只需编写代码,然后再习惯使用分号,代码仍会编译,IDE会指出。提交前只需将其全部删除即可。

不管是否选择此选项,Java都已在某些地方删除了分号,如果与C ++进行比较(在更多地方需要分号),您会注意到。

/// C ++ 
std :: thread([this] {this-> DoThreadWork(); }); /// Java
new Thread(()-> doThreadWork()); /// Kotlin
线程{doThreadWork()}

类型在末尾声明

/// Java 
int值= 10;
输入 add(字符串名称,字符串描述)/// Kotlin
var值:Int = 10
fun add(名称:String,描述:String):入口

就像可选的分号一样,如果您不习惯这种更改,您可能会很难接受。这是许多人在编程生涯中根深蒂固的相反顺序。

但是,这种语法的优点是可以在推断类型时更容易省略它们。这将在后面的“ 省略变量类型 ” 一节中进一步涉及。

此语法还更加强调变量本身,而不是其类型。我发现当大声谈论代码时,这种顺序实际上听起来更自然:

/// Java 
int结果; //一个整数,它是一个称为“结果”的变量。/// Kotlin
var结果:Int //一个名为“结果”的变量,它是一个整数。

关于此语法,我要说的最后一件事是,尽管一开始使用起来很尴尬,但随着时间的推移,您会逐渐习惯它。

没有“新”的构造函数

Kotlin 在构造函数调用之前不需要new关键字。

/// Java 
... = new SomeClass(); /// Kotlin
... = SomeClass()

起初,您可能会感觉好像正在丢失重要的信息,但实际上并不是这样-Java中的许多功能都是在后台分配内存,而您从不在乎。许多库甚至具有静态创建方法,例如:

/// Java 
Lists.newArrayList();

因此,实际上,Kotlin使得这一点更加一致。任何功能可能会或可能不会分配内存,这是副作用。

这还会清理模式,在该模式中,您分配一个临时类只是为了在其上调用一个函数而不将其分配给任何东西。

/// Java 
new Thread(...)。start(); //尴尬但有效/// Kotlin
Thread(...)。start()

可变性和不变性

默认情况下,Java中的变量是可变的,并且需要final关键字使它们不可变。相反,Kotlin没有final关键字。相反,您需要标记属性val以指示(不可变)或var指示变量(可变)。

/// Java 
私有最终 Project项目;//在初始化
私有模块activeModule 后无法重新分配;//可以在init之后重新分配//// Kotlin
private val project:Project //在init之后不能重新分配
private var activeModule:Module //在init之后可以重新分配

通常在Java中,您会遇到许多本来可以final省略但又省略了关键字的字段(由于很容易忘记,很可能是偶然的)。在Kotlin中,您必须在声明的每个字段上明确说明此决定。如果不确定应该是什么,只需val在默认情况下将其标记,var然后在需求发生变化时将其更改为以后。

顺便说一句,在Java中,函数参数始终是可变的,并且可以像字段一样使用来使其不可变final。在Kotlin中,函数参数始终是不可变的-也就是说,它们隐式地标记为val

/// Java 
公共无效日志(最终的字符串消息){…} /// Kotlin
有趣的日志(消息:字符串){…} //“消息”是不可变的

可空性

Kotlin淘汰了@NotNull@Nullable注释。如果值可以为null,则只需用问号声明其类型。

/// Java 
@Nullable Project项目;
@NotNull字符串标题;/// Kotlin
Val项目:项目?
val标题:字符串

在某些情况下,如果您确定空的值将始终不为null,则可以使用!!运算符进行断言。

/// Kotlin 
//'parse'可能返回null,但是此测试用例始终有效
val result = parse(“ 123”)!!
//不需要以下行。!! 已经断言。
❌assertThat(result).isNotNull()

如果应用!!不正确,则可能导致代码抛出NullPointerException。在单元测试中,这只会导致测试失败,但是在生产代码中使用此功能时应格外小心。实际上,许多人认为!!生产代码中有潜在的代码气味(尽管这里有足够的细微差别,这一点可能需要自己的博客文章)。

在单元测试中,使用!!运算符断言特定情况有效是更可接受的,因为如果这种假设不再成立,则测试将失败,您可以对其进行修复。

如果您确定使用!!运算符是合理的,则应尽快应用它。例如,执行以下操作:

/// Kotlin 
val结果= parse(“ ...”)!!
result.doSomething()
result.doSomethingElse()

但是要这样做:

/// Kotlin(自动产生)
val结果= parse(“ ...”)
❌结果!! .doSomething()
❌结果.doSomethingElse()

省略变量类型

在Java中,您将看到很多这样的代码:

/// Java 
SomeClass instance1 = new SomeClass();
SomeGeneric <List <String >> instance2 = new SomeGeneric <>();

在Kotlin中,这些类型声明被认为是多余的,不需要编写两次:

/// Kotlin 
val instance1 = SomeClass()
val instance2 = SomeGeneric <List <String >>()

“可是等等!” 您大喊:“有时我打算声明这些类型!” 例如:

/// Java 
BaseClass实例= new ChildClass(); //例如List = new ArrayList

可以使用以下语法在Kotlin中完成:

/// Kotlin 
val实例:BaseClass = ChildClass()

无检查异常

与Java不同,Kotlin不需要其方法声明它们抛出的异常。已检查的异常和运行时异常之间不再存在差异。

/// Java 
public void readFile()抛出IOException {…} //// Kotlin
有趣的readFile(){…}

但是,为了使Java能够调用Kotlin代码,Kotlin确实支持使用@Throws注释间接声明异常。该Java → Kotlin操作很安全,并且始终包含此信息。

/// Kotlin(从Java自动转换)
@Throws(Exception :: class)
fun testSomethingImportant(){…}

但是您不必担心从Java类调用单元测试。因此,您可以保存一些行并安全地删除以下嘈杂的异常声明:

/// Kotlin 
有趣的testSomethingImportant(){…}

用lambda调用省略括号

在Kotlin中,如果要为变量分配闭包,则需要显式声明其类型:

val sumFunc:(Int,Int)-> Int = {x,y-> x + y}

但是,如果可以推断出一切,则可以将其简化为

{x,y-> x + y}

例如,

val intList = listOf(1、2、3、4、5、6)
val sum = intList.fold(0,{x,y-> x + y}

请注意,在Kotlin中,如果函数的最后一个参数是lambda调用,则可以在括号之外编写闭包。上面的内容等同于:

val sum = intList.fold(0){x,y-> x + y}

但是,仅仅因为可以,并不意味着您应该这样做。有人可能会说上面的弃牌看起来很奇怪。其他时候,这种语法可以减少一些视觉干扰,尤其是在该方法的唯一参数是闭包的情况下。假设我们要计算偶数。比较以下内容:

intList.filter({x-> x%2 == 0})。count()

intList.filter {x-> x%2 == 0} .count()

或比较:

线程({doThreadWork()})

线程{doThreadWork()}

无论您认为哪种方法是最佳方法,您都会在Kotlin代码中看到该语法,并且可以通过操作自动生成该语法Java → Kotlin,因此,请确保您了解该语法在做什么。

等于,==和===

Kotlin在相等性测试方面与Java不同。

在Java中,双等号(==)用于实例比较,这与equals方法不同。尽管从理论上讲这听起来不错,但在实践中,开发人员==在打算使用时很容易意外使用equals。这可能会引入细微的错误,并且需要数小时才能发现或调试。

在Kotlin中,==本质上与equals是相同的-唯一的区别是它还可以正确处理null情况。例如,null == x正确评估而null.equals(x)抛出NPE。

如果您需要在Kotlin中进行实例比较,则可以改用三等号(===)。此语法更难于滥用,也更容易发现。

/// Java 
Color first = new Color(255,0,255);
颜色秒=新颜色(255,0,255);
assertThat(first.equals(second))。isTrue();
assertThat(第一==第二)isFalse(); /// Kotlin
val first = Color (255,0,255
val second = Color
255,0,255)assertThat(first.equals(second))。isTrue()
assertThat(first == second)。isTrue()
assertThat(first === second)。isFalse()

大多数时候,您会想使用Kotlin代码,==因为对它的需求===相对很少。作为预防措施,Java到Kotlin的转换器将始终转换=====。出于可读性和意图,您应考虑==尽可能恢复到原来的状态。例如,这在枚举比较中很常见。

/// Java 
if(day == DayOfWeek.MONDAY){…} //// Kotlin(从Java自动转换)
❌if(day === DayOfWeek.MONDAY){…} //// Kotlin
if(day == DayOfWeek.MONDAY){…}

删除字段前缀

在Java中,通常将私有字段与公共getter和setter配对,并且许多代码库在该字段上附加一个前缀(匈牙利符号的痕迹)。

/// Java 
private String myName ;
//或私有String mName ;
//或私有String _name ;
public String getName(){…}
public void setName(String name){…}

该前缀是一个有用的标记,仅对类的实现可见,从而可以更轻松地将类本地的字段与传递给函数的参数区分开。

在Kotlin中,字段和获取器/设置器合并为一个概念。

/// Kotlin 
类User {
val id:String //代表字段和getter
var name:String //代表field,getter和setter
}

但是,当您自动转换代码时,Java前缀有时会保留下来,而曾经隐藏在类内部的详细信息可能会泄漏到其公共接口中。

/// Kotlin(从Java自动转换)
类User {
❌val myId
String❌var myName:String
}

为了防止前缀泄漏,建议养成删除前缀以保持一致性的习惯。

没有前缀的字段可能会使使用Web工具进行偶尔的代码复查变得更难阅读(例如,在类太大的函数中过长)。但是,当您在IDE中读取代码时,通过语法突出显示,可以清楚地看到哪些值是字段,哪些是参数。删除前缀还可以鼓励围绕编写更具针对性的方法和类的更好的编码习惯。


总结思想

希望本指南有助于您开始Kotlin学习。首先,您将首先编写Java并将其转换为Kotlin,然后再编写类似Java的Kotlin,最后,不久之后,您将像专家一样编写惯用的Kotlin代码!

这篇文章只是介绍了Kotlin可以做的事情。它的目的是为那些没有太多时间而只需要快速启动和运行第一次Kotlin测试的人提供最少的笔记,同时仍然为他们提供相当多的语言基础。

但是,它可能无法满足您的所有需求。为此,请考虑官方文档:

语言参考:https : //kotlinlang.org/docs/reference/
交互式教程:
https : //try.kotlinlang.org/

分类: 未分类

bayshier

愿世间每个美好的灵魂都能被温柔以待

发表评论

电子邮件地址不会被公开。 必填项已用*标注