学习Kotlin总结

版权声明:所有解释权归@A_slower_Erving https://blog.csdn.net/yeyuwei1027/article/details/81199332

一些题外话(^o^)/~
  最近学了下Kotlin,Vim和markdown,那今天就在终端打开了个黑窗口(*.md)来总结一下Kotlin,本人学习的网站为这两个菜鸟教程Kotlin语言中文站,委托和对象那一部分还没吃透,有了更深的理解就回来补充
  还有就是顺便推荐一下学习MarkDown时看的一个大神写得非常棒的文章MarkDown公式指导手册以及流程图、时序图、甘特图画法,以及推荐学习vim用的一本书叫《Practial Vim[Drew Neil著]》




目录随性^ _^哈哈(字怎么会这么小……怎么调)




选择Kotlin的理由

简洁的语法糖,安全,互操作性好,工具友好


慎用lateinit属性

由于写Java的习惯,容易犯以下错:

class xxx {
  var value: String

  fun……
}
//Error:(2, 5) Kotlin: Property must be initialized or 
//be abstract

  若把val value : String改成lateinit var value: String,会报错如下:Exception in thread “main” kotlin.UninitializedPropertyAccessException: lateinit property value has not been initialized
  kotln为了保证绝对空安全,其会抛出UninitializedPropertyAccessException异常,因此应该抛开 Java 式的写法,牢记类属性的三种初始化方式:
  
  1. 主构造函数内定义属性,使用传入的参数初始化属性
  2. 类体内定义属性,同时初始化val value : String?=null
  3. 类体内定义属性,init 块里初始化
  



Kotlin in Android

(参考LRH1993

  • findViewById说再见
    Kotlin 为 Android 的开发提供了一个扩展包, 这个扩展包可以简化很多的 Android 代码, 他会自动将 xml布局文件中 带有id的控件映射为对应名字的控件变量, 这样就不再需要我们手动去 findViewById()了:

    activity_main.xml 布局文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk
    /res/android"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="match_parent">
    <TextView
        android:id="@+id/helloText"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</LinearLayout>

我们可以直接使用xml中对应的id,并且import对应的文件,不需要findViewById
`

例如:

//layout.xml中
<Button
        android:id="@+id/button_send"
             ……/>
//activity.kt中,不用import,直接用自己设置的id即可完成点击事件的响应
//在onCreate中调用即可
button_send.setOnClickListener {  
 Toast.makeText(this,"send_test",Toast.LENGTH_SHORT).show()
        }


  • 延迟加载
    延迟加载有几个好处。首先由于加载时机推迟到了变量被访问时,因此它可以提高应用的启动速度。其次,这样的延迟加载也有更高的内存效率。
val mModel: FindDetailModel by lazy {
        FindDetailModel()
    }
当第一次使用mModle的时候进行初始化

lateinit var mAdapter: DownloadAdapter
在任何想进行初始化的位置进行初始化


  • Lambdas 表达式
    Lambdas 表达式在减少源文件中代码的总行数的同时,也支持函数式编程。

使用 lambdas 表示式时,onClickListener的用法如下:

holder?.itemView?.setOnClickListener {
            var keyWord = list?.get(position)
::class.java)
            intent.putExtra("keyWord",keyWord)
            context?.startActivity(intent)
            mDialogListener?.onDismiss()
        }


  • 数据类
    数据类简化了类的定义,自动为类添加equals(),hashCode(),copy() 和toString() 方法。它明确定义了 model 类的意图,以及应该包含什么内容,同时将纯数据与业务逻辑分离开来。
data class VideoBean(var feed:String?,var title:String?,var description:String?,
                     var duration: Long?,var playUrl: String?,var category: String?,
                     var blurred : String?,var collect:Int?,var share:Int?,var reply:Int?,var time:Long) : Parcelable,Serializable {}
//就是如此简单,对比以前动辄几百行的数据类,简洁了太多。如果想实现序列化Parcelable,可以下载支持kotlin序列化的插件,一键实现,非常方便。


  • 集合过滤
    通过使用 Kotlin 的集合过滤功能,我们可以使代码变得更清晰简洁。
bean.issueList!!
                .flatMap { it.itemList!! }
                .filter { it.type.equals("video") }
                .forEach { mList.add(it) }

通过以上过滤,便可以得到我们想要的内容。

  • 扩展
    扩展的好处在于它允许我们为一个类添加功能同时无需继承它。例如,你是否曾经希望 Context 有某些方法,比如 showToast()?使用扩展,你可以很容易实现这个功能:
fun Context.showToast(message: String) : Toast {
    var toast : Toast = Toast.makeText(this,message,
    Toast.LENGTH_SHORT)
    toast.setGravity(Gravity.CENTER,0,0)
    toast.show()
    return toast
}


  • 其他特性
    字符串

Kotlin在字符串之中可以使用变量,相对与在Java中的字符串拼接,更让人感觉到舒服。

holder?.tv_detail?.text = "发布于 
$category / $realMinute:$realSecond"
when

Kotlin中when的出现替代了switch,但其功能更加强大。

 override fun onClick(v: View?) {
        when(v?.id){
            R.id.tv_watch ->{
                var intent = Intent(activity,WatchActivity
                ::class.java)
                startActivity(intent)
            }
            R.id.tv_advise ->{
                ::class.java)
                startActivity(intent)
            }
            R.id.tv_save ->{
                var intent = Intent(activity,CacheActivity
                ::class.java)
                startActivity(intent)
            }
        }
    }

当然Kotlin的特性不止如此,还有更多高阶的特性如:高阶函数, Anko等,这些特性还需进一步学习应用


(参考Kejin
// java

view.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        v.post(new Runnable() {
            @Override
            public void run() {
                //
            }
        });
    }
});

// kotlin, lambda, 虽然 Java 8 也支持 lambda 了, 但是 Android 不支持 Java8 …

view.setOnClickListener {
    it.post {
        // run
    }
}

// java, 这里如果 view 为 null, 则会抛出Null异常
void invisibleView(View view) {
    view.setVisibility(View.INVISIBLE);
}

// kotlin, 这是不允许传入null, 所以不会出现 Null 异常
fun invisibleView(view: View) {
    view.visibility = View.INVISIBLE
}
// 即使允许传入 null, kotlin 也可以很轻松的避免 Null 异常
fun invisibleView(view: View?) {
    view?.visibility = View.INVISIBLE
}




Grammar in Kotlin and Java


  • 接口
    两者都是用interface来声明接口的,接口里的函数可实现可不实现,Java中实现接口的类用implement来说明,Kotlin直接用(跟继承一样)


  • 类与构造函数
    写Java的时候总是有个习惯,在构造函数中对属性进行初始化后,会写几个get和set的构造器,来返回和设置属性,下面看看Kotlin的简洁之处
例:Java
public class Fruit {
    private String name;
    private int imageId;

    public Fruit(String name, int imageId) {
        this.name = name;
        this.imageId = imageId;
    }

    public String getName() {
        return name;
    }

    public int getImageId() {
        return imageId;
    }
例:Kotlin
class fruit(private val name:String,private val imageId:Int)
//只需要这一行就可以了,需要调用它属性的时候直接用类名即可

另外

  • 类的open修饰符

Kotlin 默认会为每个变量和方法添加final修饰符。这么做的目的是为了程序运行的性能,为每个类加了final即,在 Kotlin 中默认每个类都是不可被继承的。如果你这个类是会被 继承的 ,那么你需要给这个类添加 open 修饰符。

  • internal 修饰符

Java 有三种访问修饰符public/private/protected,还有一个默认的包级别访问权限没有修饰符(default)。

在 Kotlin 中,默认的访问权限是public,也就是说不加访问权限修饰符的就是 public 的。而多增加了一种访问修饰符叫internal。它是模块级别的访问权限。
何为模块(module),我们称被一起编译的一系列 Kotlin 文件为一个模块。在 IDEA 中可以很明确的看到一个 module 就是一个模块,当跨 module 的时候就无法访问另一个module 的 internal 变量或方法。




(参考dub)

  • 一般情况下常量和变量都不用写类型,编译器会自动推断类型,且可以省略分号,更加简洁

  • lambda(匿名函数)表达式使用实例:

fun main(args: Array<String>) {
    val sumLambda: (Int, Int) -> Int = {x,y -> x+y}
    println(sumLambda(1,2))  // 输出 3
}


  • Kotlin中的空是Unit表示相当于void

  • extends用“冒号”代替 MainActivity extends Activity

      现在是 MaiActivity :Activity()
      

  • interface中的属性只能是抽象的,不允许初始化值,实现时务必重写属性

interface MyInterface{
    var name:String //name 属性, 抽象的
}

class MyImpl:MyInterface{
    override var name: String = "runoob" //重载属性,override不注解
}
 


- override 不再作为注解,而是用在方法的修饰符前面          

  这样写 override fun onCreate(saveInstanceState:Bundle?)
  
- 装箱与拆箱

val a: Int = 100
println(a === a) // true,值相等,对象地址相等

//经过了装箱,创建了两个不同的对象
val boxedA: Int? = a
val anotherBoxedA: Int? = a

//虽然经过了装箱,但是值是相等的,都是100
println(boxedA === anotherBoxedA) //  true,值相等,128 之前对象地址一样
println(boxedA == anotherBoxedA) // true,值相等
这里我把 a 的值换成 100,这里应该跟 Java 中是一样的,在范围是 [-128, 127] 之间并不会创建新的对象,比较输出的都是 true,从 128 开始,比较的结果才为 false


  • 创建数组新方式有两个:
     //[1,2,3]
    val a = arrayOf(1, 2, 3)
    //[0,2,4]
    val b = Array(3, { i -> (i * 2) })


  • 没有switch case了,现在用when()->
when (x) {
    1 -> print("x == 1")
    2 -> print("x == 2")
    else -> { // 注意这个块
        print("x 不是 1 ,也不是 2")
    }
}

//Sometimes it uses like "if else"
    when {  
    x.isOdd() -> print("x is odd")
    x.isEven() -> print("x is even")
    else -> print("x is funny")
     }


  • kotlin没有object类      
class Example // 从 Any 隐式继承
//Any 默认提供了三个函数:
equals()
hashCode()
toString()
//注意:Any 不是 java.lang.Object。               

现在是Any()没有Object(), Kotlin中所有类都继承该Any类,它是所有类的超类,对于没有超类型声明的类是默认超类,一个类要被继承,可用open进行修饰

  • 跟java一样不能继承final类                   

      继承open abstract类,并且默认是open,必须要写修饰符,如果一个类要被继承,可以使用open关键字进行修饰


  • 返回值void变为Unit,可省略
    fun Unit(x: Any, y: Any) {
    fun Unit(x: Any, y: Any): Int{
    返回值可以用一个表达式写fun add(x: Int,y: Int) : Int = x + y


  • 一个类可有主构造函数和次构造函数,Kotlin创建对象不用new
class Runoob  constructor(name: String) {  // 类名为 Runoob
    // 大括号内是类体构成
    var url: String = "http://www.runoob.com"
    var country: String = "CN"
    var siteName = name

    init {
        println("初始化网站名: ${name}")
    }
    // 次构造函数
    constructor (name: String, alexa: Int) : this(name) {
        println("Alexa 排名 $alexa")
    }

    fun printTest() {
        println("我是类的函数")
    }
}

fun main(args: Array<String>) {
    val runoob =  Runoob("菜鸟教程", 10000)
    println(runoob.siteName)
    println(runoob.url)
    println(runoob.country)
    runoob.printTest()
}

  注意:在 JVM 虚拟机中,如果主构造函数的所有参数都有默认值,编译器会生成一个附加的无参的构造函数,这个构造函数会直接使用默认值。这使得 Kotlin 可以更简单的使用像 Jackson 或者 JPA 这样使用无参构造函数来创建类实例的库。


  • 在kotlin里,控件可直接赋值,通过导入package
import kotlinx.android.synthetic.main.demo.*
  text1.text = "hello world kotlin" 

//这样就创建了"hello world kotlin"的一个输入框


  • for循环也不一样了 在java中是这样写的for(int i = ; i < 10; i++) {...}   
      Kotlin是这样写的for (i in 0..99){...}

  • 在 Kotlin 中,三个等号 ===表示比较对象地址,两个 ==表示比较两个值大小

  • NULL检查机制
    Kotlin的空安全设计对于声明可为空的参数,在使用时要进行空判断处理,有两种处理方式,字段后加!!像Java一样抛出空异常,另一种字段后加?可不做处理返回值为 null或配合?:做空判断处理
//类型后面加?表示可为空
var age: String? = "23" 
//抛出空指针异常
val ages = age!!.toInt()
//不做处理返回 null
val ages1 = age?.toInt()
//age为空返回-1
val ages2 = age?.toInt() ?: -1
  • 调用方法的不同,除了调用set..Listener 还是原来的方法,其它的都改变了

java :

  main_srl.setOnRefreshListener()
  main_srl.setRefreshing(false)

kotlin :

 main_srl!!.isRefreshing = false   //抛出空异常
  main_srl!!.setOnRefreshListener {...
  • ->的用法
    Java :
        recyclerViewAdapter.setOnItemClickedListener(new 
        HeaderRecyclerViewAdapter.onItemClickedListener() {
            @Override
            public void onItemClick(View view, int position) {
                Toast.makeText(MainActivity.this, "position " 
                + position, Toast.LENGTH_SHORT).show();
            }
        });

Kotlin :

  recyclerViewAdapter.setOnItemClickedListener { view, position
position, Toast.LENGTH_SHORT).show() }


  • | & 或 和 和 改为了 or 和 and
      var testOr = Flag or Flags
      var testAnd = Flag and Flags


  • Kotlin 更加安全,Kotlin似乎比较想消灭空引用,在Java中,调用一个null对象会抛出NullPointException,在Kotlin中,不能为空的对象,例如String对象,会写成
var a: String? = "abc"
这个时候只有变量为非空的时候才会调用方法
  • 属性 kotlin没有get,set方法,直接赋值,直接使用

  • 三元表达式
     java中(condition ? then : else)
      
     kotlin中

  if (a > b) a else b
  fun main(args: Array<String>) {
    println(args[0].toInt())
    println(args[1].toInt())
    println(max(args[0].toInt(), args[1].toInt()))
  }
  • switch case
      java中
   switch(){
    case:
      breaak;
    }

  kotlin 中

when() ->
   fun main(args: Array<String>) {
    val language = if (args.size == 0) "EN" else args[0]
    println(when (language) {
        "EN" -> "Hello!"
        "FR" -> "Salut!"
        "IT" -> "Ciao!"
        "DU" -> "dub is a very excellent boy"
        else -> "Sorry, I can't greet you in $language yet"
    })
}
  • 项目中用到的高级写法
  for (Iterator<String> iterator = 
  map.keySet().iterator(); iterator.hasNext(); ) {
      StringBuffer sb = new StringBuffer();
      String key = iterator.next();
      sb.append("[").append(key).append("]");
      for (int k = map.get(key); k < 4; k++) {
      // 初使化;循环体;循环条件
          sb.append(k + ",");
      }
  }
fun main(args: Array<String>) {
    val numbers = listOf(1, 2, 3)
    println(numbers.filter(::isOdd))//是这样写的 
}
fun isOdd(x: Int) = x % 2 == 0


  • 定义变量
    Java 定义变量的写法:String string = "hello"
    基本等价的 Kotlin 定义变量的写法:var string :String = "hello"

  • Java 定义 final 变量的写法:
    Java中这么写 final String string = "hello"
    Kotlin 当中应该这么写 const val string:String = "hello"

  • 定义函数
    Java 当中如何定义函数,也就是方法,需要定义到一个类当中
    public boolean testString(String name){...
    等价的 Kotlin 写法:
    fun testString(name:String) :Boolean{...

  • 定义数组
    Java 的数组非常简单,当然也有些抽象,毕竟是编译期生成的类:
    String[] names = new String[]{"a","b",}
    Kotlin 的数组其实更真实一些,看上去更让人容易理解:
    val name:Array<String> = arrayOf{"a","b"}//避免byte short 拆箱,装箱 写法为XArray,例如 Int 的定制版数组为val ints = intArrayOf(1,2,3)
    val emptyStrings :Array<String?> = arrayOfNulls(10)//Array T即数组元素的类型。另外,String? 表示可以为 nullString类型

  • 变长参数
    Java 的变长参数写法如下:
    void holle(String...names){...
    Kotlin 的变长参数写法如下:
    fun hello(vararg names:String){...

  • 三元运算符
    Java 可以写三元运算符:
    int code = isSuccessfully?200:400;
    Kotlin 该怎么写呢?
    int code = if(isSuccessfully) 200 else 400

  • 实例化类对象
     Java中:
     Dub dub = new Dub();
     Kotlin中:
     val dub = Dub();
     

  • 如何写 Getter 和 Setter 方法
    Java 的 Getter 和 Setter 是一种约定俗称,而不是语法特性,所以定义起来相对自由:

    public class SetAndGet{
      private int x = 0;
      publc Int getX(){
        return x;
      public void setX(int x){
        this.x = x;
      Kotlin 是有属性的:
      class kotlinSetAndGet{
      var x:Int = 0
      set(value) {field = value}
      get() = field


  • 延迟初始化成员变量
    Java 定义的类成员变量如果不初始化,那么基本类型被初始化为其默认值 int 0;boolean false; String null;
    public class Hello{
      private String name;

    Kotlin 当中直译为:
    class Hello{
      private var name:String? = null
    ;//如果不使用可控类型,需要加 lateinit 关键字
    class Hello{
      private lateinit var name:String
    //lateinit 是用来告诉编译器,name 这个变量后续会妥善处置的。
      

  • 如果我要想定义一个可以延迟到一定实际再使用并初始化的 final 变量,这在 Java 中是做不到的
    Kotlin 有办法,使用 lazy 这个 delegate 即可:
    class Hello{
      private val name by lazy{
        NameProvider.getName()


  • 成员变量的写法

      companion object {
        private val TAG = FirstActivity::class.java.simpleName
      }
    //写在compaintion里
      

  • 在Kotlin中写上下文不再是类名点this了而是

hsMain!!.OnSelectList { text -> Toast.makeText(this@MainActivity, text, Toast.LENGTH_SHORT).show()





——————————————END————————————————————
水平有限,错误疏漏在所难免,望路过大神不吝批评指点。
                    
                    A slower never walks backwards.

猜你喜欢

转载自blog.csdn.net/yeyuwei1027/article/details/81199332