博客
关于我
Kotlin 之美
阅读量:296 次
发布时间:2019-03-01

本文共 5546 字,大约阅读时间需要 18 分钟。

Kotlin 开发者社区

Kotlin 作为后起之秀,站在巨人们的肩膀上是她得天独厚的优势,而这个巨人也包括《Effective Java》(EJ),得益于这个巨人,Kotlin 到处散发着高效的味道,这篇文章让我们一起来领略下 Kotlin 的高效之道。

在实例化对象的方式中,使用静态工厂方法相比构造器有几个好处:工厂方法拥有名字,易于开发者理解。不必在每次调用的时候都创建一个新对象,比如可以事先缓存好实例。可以返回原类型的任何子类型。Kotlin 并没有 static 关键字,也没有静态成员的概念,取而代之的是『伴生对象』,因此,对于第一条准则,Kotlin 使用伴生对象关键字 companion 来定义静态工厂方法,代码风格如下:

class User private constructor(val account:String){    companion object {        fun newWeiboUser(email:String):User{            return User(email)        }        fun newTelUser(tel:Long):User{            return User(tel.toString())        }    }}

调用方式类似 Java 中的静态方法:

val newTelUser = User.newTelUser(18888888888)val weiBoUser = User.newWeiboUser("geniusmart")

对于单例模式,Kotlin 对单例模式做了更彻底的精简,简直易如反掌,可以通过 object 关键字声明一个单例类的同时创建一个实例,例如:

object singleton {    fun action() {        println(this.hashCode())    }}

验证单例的唯一性:

@Testfun test() {    val instance1 = singleton    val instance2 = singleton    assertEquals(instance1, instance2)}

在 Java 中,单例模式通常使用私有构造器和静态初始化块:

public final class singleton {    public static final singleton INSTANCE;    private singleton() {        INSTANCE = (singleton) this;    }    static {        new singleton();    }}

Kotlin 让创建单例变得更高效。

封装(信息隐藏)是面向对象的四大特性之一,体现在具体的实现层面便是四种访问权限:privatedefaultprotectedpublic。面向对象编程,我们的代码充满着类、成员属性和成员方法,这些都是我们对外的契约。如果类和成员都是可访问的,意味着我们后续的迭代版本都必须保持兼容,这显然是一项巨大的工程。反之,充分利用好四种访问权限,将类和成员的可访问性控制到最小,更有利于程序的扩展。

Kotlin 的默认访问权限为 public,没有包级别访问权限,新增了模块可见的访问权限 internal,并支持顶层声明的类别。关于 internal,举个栗子:假设工程里有两个 module,app 和 lib,app 依赖于 lib 工程,代码层级如下:

app-- class Activitylib-- internal class StringUtils

StringUtils 仅在 lib 工程中可视,app 工程中的 Activity 无法访问该类。Kotlin 在访问权限的设计更彻底地贯彻了“使可访问性最小化”的准则。

《Effective Java》中提到,使用访问方法而非公有域。例如:

public class Point {    public double x; // 公有域    public double y; }

这样的代码直接暴露成员属性,且未来难于更改实现。Kotlin 在语法层面直接约束了这一点,默认将属性定义为私有,并提供 public 修饰的 getset 方法:

class User {    val num = 10 // 属性默认为 private,且拥有 public 的 getNum()    var nickname = "geniusmart" // 同上}@Testfun test() {    val user = User()    println(user.num) // 实际上调用的是 getNum()    user.nickname = "Mr.Geniusmart" // 实际上调用的是 setNum()    println(user.nickname)}

如果需要对属性进行更复杂的处理,可以通过 getset 方法进行扩展:

class User {    val num = 10    var nickname = "geniusmart"         get() = field.plus("@email.com")}

Kotlin 的 setget 方法完美吻合《Effective Java》中第14条准则。

《Effective Java》中提到,组合优先于继承(原书是复合优先于继承)。继承破坏了封装性,父类必须暴露更多的细节让子类知道(比如使用 protected 访问权限),同时子类依赖于父类的实现,一旦父类改变,子类都会受影响。

例如,想对 HashSet 增加『计算新增元素个数』的能力,采用继承的方式:

class CountingSet: HashSet
{ var count = 0 override fun add(element: String): Boolean { count++ return super.add(element) } override fun addAll(elements: Collection
): Boolean { count += elements.size return super.addAll(elements) }}

验证发现,父类的 addAll() 会循环调用 add(),导致计数器倍增。相反,使用组合的方式:

class CountingSetBy(val countingSet: MutableCollection
): MutableCollection
by countingSet { var count = 0 override fun add(element: String): Boolean { count++ return super.add(element) } override fun addAll(elements: Collection
): Boolean { count += elements.size return super.addAll(elements) }}

验证发现,组合的方式实现更高效且可靠。

《Effective Java》中提到,要么为继承而设计,并提供文档说明,要么就禁止继承。Kotlin 中创建的类和方法默认都是 final

class Parent {    fun action() {}}

如果经过深思熟虑,一定要提供继承和重写,可以通过 open 修饰符来实现。

《Effective Java》中提到,优先考虑静态成员类。Kotlin 在语法层面直接支持嵌套类,默认为静态成员类:

class Outer {    class Inner {    }}

如果需要非静态成员类,可以通过 inner 关键字实现:

class Outer {    inner class OtherInner {        fun action() {            // 调用外部类实例            this@Outer.toString()        }    }}

《Effective Java》中提到,使用静态成员类而非非静态成员类,Kotlin 的嵌套类设计符合这一原则。

《Effective Java》中提到,重写方法必须使用 override 注解。Kotlin 也严格执行这一规则,强制在重写方法时添加 override

Kotlin 的 DSL(领域特定语言)让代码更具表现力和想象力。以下是 Kotlin DSL 的一些有趣实现:

  • 日期处理
  • val yesterday = 1.days.agoval twoMonthsLater = 2.months.fromNow
    1. 单元测试
    2. val str = "kotlin"str should startWith("kot")str.length shouldBe 6
      1. HTML 构建器
      2. fun createTable() =     table {        tr {            td {}        }    }println(createTable())
        1. SQL
        2. (Users innerJoin Cities)    .slice(Users.name, Cities.name)    .select {         (Users.id.eq("andrey") or Users.name.eq("Sergey"))         and Users.id.eq("sergey")         and Users.cityId.eq(Cities.id)     }    .forEach {         println("${it[Users.name]} lives in ${it[Cities.name]}")    }
          1. Android 布局
          2. class MainActivity : AppCompatActivity() {    override fun onCreate(savedInstanceState: Bundle?) {        super.onCreate(savedInstanceState)        verticalLayout {            val name = editText()            button("Say Hello") {                onClick { toast("Hello, ${name.text}!") }            }        }    }}
            1. Gradle 构建
            2. dependencies {    compile("com.android.support:appcompat-v7:27.0.1")    compile("com.android.support.constraint:constraint-layout:1.0.2")}

              Kotlin DSL 的代码结构具有以下特点:链式调用、大括号嵌套,并且可以近似于英语句子。

              Kotlin 的实现原理包括扩展函数、lambda、中缀调用和 invoke 约定。这些特性使得 Kotlin 的代码既整洁又高效。

              扩展函数(扩展属性)让 Kotlin 拥有类似动态语言的灵活性:

              fun Int.days(): Period = Period.ofDays(this)val Int.days: Period get() = Period.ofDays(this)

              lambda 是构建整洁代码的利器:

              fun printSum(sum: (Int, Int) -> Int) {    val sum = { x: Int, y: Int -> x + y }    printSum(sum)}

              中缀调用让代码更接近英语:

              "key" to "value"

              invoke 约定让对象可以像函数一样调用:

              class Person(val name: String) {    operator fun invoke() {        println("my name is $name")    }}val person = Person("geniusmart")person()

              总结起来,Kotlin 的 DSL 代码结构具有链式调用、大括号嵌套、接近英语句子的特点。这些特性使得 Kotlin 的代码既整洁又高效。

              原文:[《Effective Java》与 Kotlin 的结合](https://mp.weixin.qq.com/s/1h8FqY Rosenberger)

    转载地址:http://gjma.baihongyu.com/

    你可能感兴趣的文章
    Objective-C实现Edmonds-Karp算法(附完整源码)
    查看>>
    Objective-C实现EEMD算法(附完整源码)
    查看>>
    Objective-C实现elgamal 密钥生成器算法(附完整源码)
    查看>>
    Objective-C实现EM算法(附完整源码)
    查看>>
    Objective-C实现EM算法(附完整源码)
    查看>>
    Objective-C实现entropy熵算法(附完整源码)
    查看>>
    Objective-C实现euclidean distance欧式距离算法(附完整源码)
    查看>>
    Objective-C实现Euclidean GCD欧几里得最大公约数算法(附完整源码)
    查看>>
    Objective-C实现euclideanDistance欧氏距离算法(附完整源码)
    查看>>
    Objective-C实现euler method欧拉法算法(附完整源码)
    查看>>
    Objective-C实现euler modified变形欧拉法算法(附完整源码)
    查看>>
    Objective-C实现eulerianPath欧拉路径算法(附完整源码)
    查看>>
    Objective-C实现Eulers TotientFunction欧拉函数算法(附完整源码)
    查看>>
    Objective-C实现eulers totient欧拉方程算法(附完整源码)
    查看>>
    Objective-C实现EulersTotient欧拉方程算法(附完整源码)
    查看>>
    Objective-C实现eval函数功能(附完整源码)
    查看>>
    Objective-C实现even_tree偶数树算法(附完整源码)
    查看>>
    Objective-C实现Exceeding words超词(差距是ascii码的距离) 算法(附完整源码)
    查看>>
    Objective-C实现exchange sort交换排序算法(附完整源码)
    查看>>
    Objective-C实现ExponentialSearch指数搜索算法(附完整源码)
    查看>>