Android官方语言:Kotlin
在今年的Google I/O上,Google正式宣布Kotlin成为Android的官方语言。这将意味着不久之后Android开发将会逐步的从Java语言转移到Kotlin,为什么Kotlin会成为Android官方语言?它的优点在哪里?接下来我将从以下几点介绍Kotlin语言的一些特性:
- 什么是Kotlin?
- Kotlin的一些特性
- Kotlin的插件安装
- Kotlin与Java的比较
- Kotlin学习资料
什么是Kotlin?
Kotlin,它是[JetBrains]开发的基于JVM的语言。JetBrains因为创造了一个强大的Java开发IDE被大家所熟知。Android Studio,官方的Android IDE,就是基于Intellij,作为一个该平台的插件。
Kotlin是使用Java开发者的思维被创建的,Intellij作为它主要的开发IDE。对于Android开发者,有两个有趣的特点:
- 对Java开发者来说,Kotlin是非常直觉化的,并且非常容易学习。语言的大部分内容都是与我们知道的非常相似,不同的地方,它的基础概念也能迅速地掌握它。
- 它与我们日常生活使用的IDE无需配置就能完全整合。Android Studio能够非常完美地理解、编译运行Kotlin代码。而且对这门语言的支持来正是自于开发了这个IDE的公司本身,所以我们Android开发者是一等公民。
但是这仅仅是开发语言和开发工具之间的整合。相比Java 7的优势到底是什么呢?
- 它更加易表现:这是它最重要的优点之一。你可以编写少得多的代码。
- 它更加安全:Kotlin是空安全的,也就是说在我们编译时期就处理了各种null的情况,避免了执行时异常。如果一个对象可以是null,则我们需要明确地指定它,然后在使用它之前检查它是否是null。你可以节约很多调试空指针异常的时间,解决掉null引发的bug。
- 它是函数式的:Kotlin是基于面向对象的语言。但是就如其他很多现代的语言那样,它使用了很多函数式编程的概念,比如,使用lambda表达式来更方便地解决问题。其中一个很棒的特性就是Collections的处理方式。
- 它可以扩展函数:这意味着我们可以扩展类的更多的特性,甚至我们没有权限去访问这个类中的代码。
- 它是高度互操作性的:你可以继续使用所有的你用Java写的代码和库,因为两个语言之间的互操作性是完美的。甚至可以在一个项目中使用Kotlin和Java两种语言混合编程。
Kotlin的一些特性
这里有一些Java中没有的特性:
易表现
通过Kotlin,可以更容易地避免模版代码因为大部分的典型情况都在语言中默认覆盖实现了。举个例子,在Java中,如果我们要典型的数据类,我们需要去编写这些代码:
public class Artist {
private long id;
private String name;
private String url;
private String mbid;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getMbid() {
return mbid;
}
public void setMbid(String mbid) {
this.mbid = mbid;
}
@Override public String toString() {
return "Artist{" +
"id=" + id +
", name='" + name + '\'' +
", url='" + url + '\'' +
", mbid='" + mbid + '\'' +
'}';
}
}
使用Kotlin,我们只需要通过数据类:
data class Artist(
var id: Long,
var name: String,
var url: String,
var mbid: String)
这个数据类,它会自动生成所有属性和它们的访问器,以及一些有用的方法,比如,toString()
空安全
当我们使用Java开发的时候,我们的代码大多是防御性的。如果我们不想遇到NullPointerException
,我们就需要在使用它之前不停地去判断它是否为null。Kotlin,如很多现代的语言,是空安全的,因为我们需要通过一个安全调用操作符
:“?”来明确地指定一个对象是否能为空。
我们可以像这样去写:
// 这里不能通过编译. Artist 不能是null
var notNullArtist: Artist = null
// Artist 可以是 null
var artist: Artist? = null
// 无法编译, artist可能是null,我们需要进行处理
artist.print()
// 只要在artist != null时才会打印
artist?.print()
// 智能转换. 如果我们在之前进行了空检查,则不需要使用安全调用操作符调用
if (artist != null) {
artist.print()
}
// 只有在确保artist不是null的情况下才能这么调用,否则它会抛出异常
artist!!.print()
// 使用Elvis操作符来给定一个在是null的情况下的替代值
val name = artist?.name ?: "empty"
扩展方法
我们可以给任何类添加函数。它比那些我们项目中典型的工具类更加具有可读性。举个例子,我们可以给fragment增加一个显示toast的函数:
fun Fragment.toast(message: CharSequence, duration: Int = Toast.LENGTH_SHORT) {
Toast.makeText(getActivity(), message, duration).show()
}
我们现在可以这么做:
fragment.toast("Hello world!")
函数式支持(Lambdas)
每次我们去声明一个点击所触发的事件,可以只需要定义我们需要做些什么,而不是不得不去实现一个内部类?我们确实可以这么做,这个(或者其它更多我们感兴趣的事件)我们需要感谢lambda:
view.setOnClickListener { toast("Hello world!") }
Kotlin插件的安装
Kotlin团队创建了一系列强大的插件让我们更轻松地实现。前往Android Studio的Preferences
中Plugin
栏,然后安装如下两个插件:
- Kotlin:这是一个基础的插件。它能让Android Studio懂得Kotlin代码。它会每次在新的Kotlin语言版本发布的时候发布新的插件版本,这样我们可以通过它发现新版本特性和弃用的警告。这是你要使用Kotlin编写Android应用唯一的插件。但是我们现在还需要另外一个。
- Kotlin Android Extensions:Kotlin团队还为Android开发发布了另外一个有趣的插件。这个Android Extensions可以让你自动地从XML中注入所有的View到Activity中,举个例子,你不需要使用
findViewById()
。你将会立即得到一个从属性转换过来的view。你将需要安装这个插件来使用这个特性。
1、在Android Studio中打开Settings,选择Plugins选项,点击Browse Repositories,在打开的窗口中搜索Kotlin,点击Install。如图:
下载安装完成后会提示你重启Android Studio,重启之后,就可以使用了
Kotlin与Java的比较
接下来是Kotlin与Java在代码上的一些比较,这样更能直观的看到两种语言的不同点:
Java
System.out.print("Amit Shekhar");
System.out.println("Amit Shekhar");
Kotlin
print("Amit Shekhar")
println("Amit Shekhar")
Java
String name = "Amit Shekhar";
final String name = "Amit Shekhar";
Kotlin
var name = "Amit Shekhar"
val name = "Amit Shekhar"
Java
String otherName;
otherName = null;
Kotlin
var otherName : String?
otherName = null
Java
if (text != null) {
int length = text.length();
}
Kotlin
text?.let {
val length = text.length
}
// or simple
val length = text?.length
Java
String firstName = "Amit";
String lastName = "Shekhar";
String message = "My name is: " + firstName + " " + lastName;
Kotlin
val firstName = "Amit"
val lastName = "Shekhar"
val message = "My name is: $firstName $lastName"
Java
String text = "First Line\n" +
"Second Line\n" +
"Third Line";
Kotlin
val text = """
|First Line
|Second Line
|Third Line
""".trimMargin()
Java
String text = x > 5 ? "x > 5" : "x <= 5";
String message = null;
log(message != null ? message : "");
Kotlin
val text = if (x > 5)
"x > 5"
else "x <= 5"
val message: String? = null
log(message ?: "")
java
final int andResult = a & b;
final int orResult = a | b;
final int xorResult = a ^ b;
final int rightShift = a >> 2;
final int leftShift = a << 2;
Kotlin
val andResult = a and b
val orResult = a or b
val xorResult = a xor b
val rightShift = a shr 2
val leftShift = a shl 2
Java
if (object instanceof Car) {
}
Car car = (Car) object;
Kotlin
if (object is Car) {
}
var car = object as Car
Java
if (object instanceof Car) {
Car car = (Car) object;
}
Kotlin
if (object is Car) {
var car = object // smart casting
}
Java
if (score >= 0 && score <= 300) { }
Kotlin
if (score in 0..300) { }
Java
int score = // some score;
String grade;
switch (score) {
case 10:
case 9:
grade = "Excellent";
break;
case 8:
case 7:
case 6:
grade = "Good";
break;
case 5:
case 4:
grade = "Ok";
break;
case 3:
case 2:
case 1:
grade = "Fail";
break;
default:
grade = "Fail";
}
Kotlin
var score = // some score
var grade = when (score) {
9, 10 -> "Excellent"
in 6..8 -> "Good"
4, 5 -> "Ok"
in 1..3 -> "Fail"
else -> "Fail"
}
Java
for (int i = 1; i <= 10 ; i++) { }
for (int i = 1; i < 10 ; i++) { }
for (int i = 10; i >= 0 ; i--) { }
for (int i = 1; i <= 10 ; i+=2) { }
for (int i = 10; i >= 0 ; i-=2) { }
for (String item : collection) { }
for (Map.Entry<String, String> entry: map.entrySet()) { }
Kotlin
for (i in 1..10) { }
for (i in 1 until 10) { }
for (i in 10 downTo 0) { }
for (i in 1..10 step 2) { }
for (i in 10 downTo 1 step 2) { }
for (item in collection) { }
for ((key, value) in map) { }
Java
final List<Integer> listOfNumber = Arrays.asList(1, 2, 3, 4);
final Map<Integer, String> keyValue = new HashMap<Integer, String>();
map.put(1, "Amit");
map.put(2, "Ali");
map.put(3, "Mindorks");
// Java 9
final List<Integer> listOfNumber = List.of(1, 2, 3, 4);
final Map<Integer, String> keyValue = Map.of(1, "Amit",
2, "Ali",
3, "Mindorks");
Kotlin
val listOfNumber = listOf(1, 2, 3, 4)
val keyValue = mapOf(1 to "Amit",
2 to "Ali",
3 to "Mindorks")
Java
// Java 7 and below
for (Car car : cars) {
System.out.println(car.speed);
}
// Java 8+
cars.forEach(car -> System.out.println(car.speed));
// Java 7 and below
for (Car car : cars) {
if (car.speed > 100) {
System.out.println(car.speed);
}
}
// Java 8+
cars.stream().filter(car -> car.speed > 100).forEach(car -> System.out.println(car.speed));
Kotlin
cars.forEach {
println(it.speed)
}
cars.filter { it.speed > 100 }
.forEach { println(it.speed)}
Java
void doSomething() {
// logic here
}
Kotlin
fun doSomething() {
// logic here
}
Java
void doSomething(int... numbers) {
// logic here
}
Kotlin
fun doSomething(vararg numbers: Int) {
// logic here
}
Java
int getScore() {
// logic here
return score;
}
Kotlin
fun getScore(): Int {
// logic here
return score
}
// as a single-expression function
fun getScore(): Int = score
Java
int getScore(int value) {
// logic here
return 2 * value;
}
Kotlin
fun getScore(value: Int): Int {
// logic here
return 2 * value
}
// as a single-expression function
fun getScore(value: Int): Int = 2 * value
Java
public class Utils {
private Utils() {
// This utility class is not publicly instantiable
}
public static int getScore(int value) {
return 2 * value;
}
}
Kotlin
class Utils private constructor() {
companion object {
fun getScore(value: Int): Int {
return 2 * value
}
}
}
// other way is also there
object Utils {
fun getScore(value: Int): Int {
return 2 * value
}
}
Java
public class Developer {
private String name;
private int age;
public Developer(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Developer developer = (Developer) o;
if (age != developer.age) return false;
return name != null ? name.equals(developer.name) : developer.name == null;
}
@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + age;
return result;
}
@Override
public String toString() {
return "Developer{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
Kotlin
data class Developer(var name: String, var age: Int)
Java
public class Developer implements Cloneable {
private String name;
private int age;
public Developer(String name, int age) {
this.name = name;
this.age = age;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return (Developer)super.clone();
}
}
// cloning or copying
Developer dev = new Developer("Max", 30);
try {
Developer dev2 = (Developer) dev.clone();
} catch (CloneNotSupportedException e) {
// Handle Exception
}
Kotlin
data class Developer(var name: String, var age: Int)
// cloning or copying
val dev = Developer("Max", 30)
val dev2 = dev.copy()
// in case you only want to copy selected properties
val dev2 = dev.copy(age = 25)
Java
public class Utils {
private Utils() {
// This utility class is not publicly instantiable
}
public static int triple(int value) {
return 3 * value;
}
}
int result = Utils.triple(3);
Kotlin
fun Int.triple(): Int {
return this * 3
}
var result = 3.triple()
Kotlin学习资料
接下来给大家一些关于Kotlin的学习资料:
1.kotlin官方中文翻译文档网址:
https://www.kotlincn.net/docs/reference/
2.Kotlin官网
http://kotlinlang.org/
3.kotlin中文官网
https://www.kotlincn.net/
4.kotlin的gitbook网址
https://www.gitbook.com/book/hltj/kotlin-reference-chinese/details
有了Google的支持,Kotlin转Android相信在不久的将来就会全面展开。篡改Python的一句名言“人生苦短,我用Kotlin”,这样一个高效实用的语言应该会被越来越多的团队所接受,并应用到开发生产中。当然也希望在国内环境下大放异彩。