前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Kotlin 语言极简教程 v0.1 (东海陈光剑)Kotlin 语言极简教程

Kotlin 语言极简教程 v0.1 (东海陈光剑)Kotlin 语言极简教程

作者头像
一个会写诗的程序员
发布2018-12-07 10:20:53
5270
发布2018-12-07 10:20:53
举报

Kotlin 语言极简教程

v0.1 (东海陈光剑)

简介

是什么

  • 基于 JVM 实现的静态语言
  • JetBrains 出品。对,就是那个创造了 Android Studio 和 IntelliJ 的公司。
  • Hello World
fun main(args: Array<String>){
    println("Hello World!")
}

极简版:

fun main(args: Array<String>) = println("Hello World!")

特性

  • 简约:帮你减少实现同一个功能的代码量。
  • 易懂:让你的代码更容易阅读,同时易于理解。
  • 安全:移除了你可能会犯错误的功能。
  • 通用:基于 JVM 和 Javascript,你可以在很多地方运行。
  • 互操作性:这就意味着 Kotlin 和 Java 可以相互调用,同时 Jetbrains 的目标是让他们 100% 兼容。

历史

  • Java 有哪些问题?
    • 空引用(Null references):连空引用的发明者Tony Hoare 都承认这是个 billion-dollar 错误。不论你费多大的功夫,你都无法避免它。因为 Java 的类型系统就是不安全的。

Speaking at a software conference called QCon London in 2009, he apologised for inventing the null reference: I call it my billion-dollar mistake. It was the invention of the null reference in 1965. At that time, I was designing the first comprehensive type system for references in an object oriented language (ALGOL W). My goal was to ensure that all use of references should be absolutely safe, with checking performed automatically by the compiler. But I couldn't resist the temptation to put in a null reference, simply because it was so easy to implement. This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years.

  • 原始类型(Raw types):我们在开发的时候总是会为了保持兼容性而卡在范型原始类型的问题上,我们都知道要努力避免 raw type 的警告,但是它们毕竟是在语言层面上的存在,这必定会造成误解和不安全因素。
  • 协变数组(Covariant arrays):你可以创建一个 string 类型的数组和一个 object 型的数组,然后把 string 数组分配给 object 数组。这样的代码可以通过编译,但是一旦你尝试在运行时分配一个数给那个数组的时候,他就会在运行时抛出异常。
  • Java 8 存在高阶方法( higher-order functions ),但是他们是通过 SAM 类型 实现的。SAM 是一个单个抽象方法,每个函数类型都需要一个对应的接口。如果你想要创建一个并不存在的 lambda 的时候或者不存着对应的函数类型的时候,你要自己去创建函数类型作为接口。
  • 泛型中的通配符:诡异的泛型总是难以操作,难以阅读,书写,以及理解。对编译器而言,异常检查也变得很困难。
  • Kotlin 新的特性
    • Lambda 表达式
    • 类型推导
      • val a = 1
    • 数据类 (Data classes)
    • 函数字面量和内联函数(Function literals & inline functions)
    • 函数扩展 (Extension functions)
    • 空安全(Null safety)
      • elvis操作符
        • Java var length = if(a!= null) a.length() else -1
        • Kotlin var length = a?.length() ?: -1
      • Java
String a  = null;
System.out.println(a.length());

在 Java 里,声明一个 string 类型,赋一个 null 给这个变量。一旦我们要打印这个字符串的时候,会在运行时曝出空指针错误,因为我们在尝试去读一个空值。 * kotlin 写法 * 我们定义一个空值,但是在我们尝试操作它之前,Kotlin 的编译器就告诉了我们问题所在:

val a:String = null

曝出的错误是:我们在尝试着给一个非空类型分配一个 null。在 Kotlin 的类型体系里,有空类型和非空类型。类型系统识别出了 string 是一个非空类型,并且阻止编译器让它以空的状态存在。想要让一个变量为空,我们需要在声明后面加一个 ? 号,同时赋值为 null。

val a: String? = null
println(a.length())

现在,我们修复了这个问题,继续向下:就像在 Java 里一样,我们尝试打印 stirng 的长度,但是我们遇到了跟 Java 一样的问题,这个字符串有可能为空,不过幸好的是:Kotlin 编译器帮助我们发现了这个问题,而不像 Java 那样,在运行时爆出这个错误。

编译器在长度输出的代码前停止了。想要让编译器编译下去,我们得在调用 length 方法的时候考虑到可能为空的情况,要么赋值给这个 string,要么用一个问号在变量名后,这样,代码执行时在读取变量的时候检查它是否为空。

val a: String? = null
println(a?.length())

如果值是空,则会返回空。如果不是空值,就返回真实的值。print 遇到 null 会输出空。

* 智能转换(Smart casts)
* 字符串模板(String templates)
* 主构造函数(Primary constructors)
* 类委托(Class delegation)
* 类型推断(Type inference)
* 单例(Singletons)
* 声明点变量(Declaration-site variance)
* 区间表达式(Range expressions)

现状&未来发展

基本类型

分支循环

if

fun main(args: Array<String>) {
    val name = if (args.isNotEmpty()) {
        args[0]
    } else {
        "World"
    }
    println("Hello, $name!")
}

val name = if (args.isNotEmpty()) args[0] else "Word"

for

enum class Language(val greeting: String) {
    EN("Hello"), ES("Hola"), FR("Bonjour")
}

class Person(var name: String, var lang: Language = Language.EN) {
    fun greet() = println("${lang.greeting}, $name!")
}



fun main(args: Array<String>) {
    val people = listOf(
       Person("Java"),
       Person("Miguel", Language.SP),
       Person("Michelle", Language.FR)
    )

    for (person in people) {
        person.greet()
    }
}

when

when(x) {
  is Int -> print(x + 1)
  is String -> print(x.length + 1)
}

数组集合类

文件 IO

面向对象编程

class Person(var name: String)

fun main(args: Array<String>) {
  val person = Person("Kotlin")
  println("Hello, $name!")
}

数据类

  • Java
  private String firstName;
  private String lastName;
  private String email;

  public String getFirstName() { return firstName; }
  public String getLastName() { return lastName; }
  public String getEmail() { return email; }

  public void setFirstName(String firstName) { this.firstName = firstName }
  public void setLastName(String lastName) { this.lastName = lastName }
  public void setEmail(String email) { this.email = email }
}
  • Kotlin
class Customer( var firstName: String ,
 var lastName: String,
 var email: String)

单例

  • object Singleton
object Logger {
  val tag = "TAG"
  fun d(message: String) {
    Log.d(tag, message)
  }
}

函数式编程

函数类型

  • (X)->Y

Lambda 表达式

  • people.forEach { it.greet() }

高阶函数

  • Java 8 函数接口
// 首先要声明一个函数接口,接受参数类型为 T,返回类型为 R。
public interface Function<T, R> {
  R call(T t);
}

public static <T> List<T> filter(Collection<T> items, Function<T, Boolean> f) {
  final List<T> filtered = new ArrayList<T>();
  for (T item : items) if (f.call(item)) filtered.add(item);
  return filtered;
}

filter(numbers, new Function<Integer, Boolean>() {
  @Override
  public Boolean call(Integer value) {
    return value % 2 == 0;
  }
});
  • 在 Kotlin 中
 fun <T> filter(items: Collection<T>, f: (T) -> Boolean): List<T> {
  val filtered = arrayListOf<T>()
  for (item in items) if (f(item)) filtered.add(item)
  return filtered
}

filter(numbers, { value -> value % 2 == 0 })

你可能发现了,我们没有定义任何的函数接口,这是因为在 Kotlin 中,函数也是一种数据类型。看到 f:(T) -> Boolean 这个语句了吗?这就是函数类型作为参数的写法,f 是函数别名,T 是函数接受参数,Boolean 是这个函数的返回值。定义完成后,我们随后就能跟调用其他函数一样调用 f。调用 filter 的时候,我们是用 lambda 表达式来传入过滤函数的,即:

{value -> value % 2 = 0}

由于函数类型参数是可以通过函数声明的签名来推导的,所以其实还有下面的一种写法,大括号内就是第二个参数的函数体:

filter(numbers) {
  it % 2 == 0
}

函数组合示例

package com.light.sword.coursera

val lengthFun = fun(s: String): Int = s.length //lengthFun is a fun variable
val isOddFun = fun(x: Int): Boolean = x % 2 != 0

fun compose(length: (String) -> Int, isOdd: (Int) -> Boolean): (String) -> Boolean {
    return { x -> isOdd(length(x)) }
}

fun main(args: Array<String>) {
    val words = listOf("Hello", "U", "Kotlin", "Java")
    val result = words.filter(compose(lengthFun, isOddFun)) // Use lengthFun directly
    println(result) // [Hello, U]
}

扩展函数

代码实例

fun String.lastChar(): Char = this.get(this.length - 1)

fun main(args: Array<String>) {
    println("Kotlin".lastChar())
}

Kotlin 语言极简教程 v0.1 (东海陈光剑).png

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018.11.07 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Kotlin 语言极简教程
    • 简介
      • 是什么
      • 特性
      • 历史
      • 现状&未来发展
    • 基本类型
      • 分支循环
        • if
        • for
        • when
      • 数组集合类
        • 文件 IO
          • 面向对象编程
            • 数据类
            • 单例
          • 函数式编程
            • 函数类型
            • Lambda 表达式
            • 高阶函数
            • 函数组合示例
          • 扩展函数
            • 代码实例
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档