kotlin java對比

簡介

Kotlin 是一個基于 JVM 的新的編程語言浅蚪,由 JetBrains 開發(fā)拘领。于2010年首次推出意乓,次年開源。它與Java 100%互通约素,并具備諸多Java尚不支持的新特性

設計目標

創(chuàng)建一種兼容Java的語言

讓它比Java更安全届良,能夠靜態(tài)檢測常見的陷阱。如引用空指針

讓它比Java更簡潔 如高階函數(shù)圣猎、擴展函數(shù)等

變量士葫、方法、類的定義

變量常量定義

可變變量定義:

var 關(guān)鍵字

var <標識符> : <類型> = <初始化值>
var age :Int =1
var age =1

不可變變量定義:

val 關(guān)鍵字送悔,只能賦值一次的變量(類似Java中final修飾的變量)

val <標識符> : <類型> = <初始化值>

方法定義

函數(shù)定義使用關(guān)鍵字 fun慢显,參數(shù)格式為:參數(shù) : 類型

fun sum(a: Int, b: Int): Int {   // Int 參數(shù),返回值 Int
    return a + b
}

表達式類型確定的值作為函數(shù)體放祟,返回類型自動推斷

fun sum(a: Int, b: Int) = a + b
fun equals(a: Int, b: Int) = false

無返回值的函數(shù)(類似Java中的void):

fun printSum(a: Int, b: Int): Unit { 
    print(a + b)
}
// 如果是返回 Unit類型鳍怨,則可以省略:
fun printSum(a: Int, b: Int) { 
    print(a + b)
}

匿名函數(shù)

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

類的定義和實例

Kotlin 中使用關(guān)鍵字 class 聲明類呻右,后面緊跟類名:

class Foo {  // 類名為 Foo
    // 大括號內(nèi)是類體構(gòu)成
}

我們也可以定義一個空類:

class Foo

類的屬性可以用關(guān)鍵字 var 聲明為可變的跪妥,否則使用只讀關(guān)鍵字 val 聲明為不可變。

class Foo {
    var name: String = ……
    var url: String = ……
    var city: String = ……
}

屬性可以放到構(gòu)造函數(shù)里面

class Foo( var name: String , var url: String , var city: String)

數(shù)據(jù)類data class 自動獲取需要的getters声滥,setters眉撵,equals(),hashcode()落塑,toString()和copy()函數(shù)

data class Person(var name: String,var age: Int,var height: Float = 1.8f)

等同的java class

public final class Person {
    private String name;
    private int age;
    private float height;
 
    public Person(String name, int age, float height) {
        this.name = name;
        this.age = age;
        this.height = height;
    }
 
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
        this.height = 1.8f;
    }
 
    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;
    }
 
    public float getHeight() {
        return height;
    }
 
    public void setHeight(float height) {
        this.height = height;
    }
 
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", height=" + height +
                '}';
    }
 
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
 
        Person person = (Person) o;
 
        if (age != person.age) return false;
        if (Float.compare(person.height, height) != 0) return false;
        return name != null ? name.equals(person.name) : person.name == null
    }
 
    @Override
    public int hashCode() {
        int result = name != null ? name.hashCode() : 0;
        result = 31 * result + age;
        result = 31 * result + (height != +0.0f ? Float.floatToIntBits(height) : 0);
        return result;
    }   
}

實例化一個對象纽疟,不需要new關(guān)鍵字

var foo = Foo()

字符串模板

$ 表示一個變量名或者變量值

$varName 表示變量值

${varName.fun()} 表示變量的方法返回值:

val person = Person("小明",12)
val string = "person=[${person.name},${person.age}]"

對比java

Person person = new Person("小明",12);
String string = "person="+"["+person.getName()+","+person.getAge()+"]";

NULL檢查機制

Kotlin 在變量定義的時候就指定是否可空

var name:String ="小明"
var city:String?=null//用?表示可空
String name ="小明"
String city =null

在一個方法中

var length  =city.length()

在編譯期間就會報錯,這樣寫就不會編譯出錯

var length  =city?.length()

如果用java來寫

int length =city.length()

在編譯期間是無法感知異常的,有可能在項目運行時就crash了

類型檢測及自動類型轉(zhuǎn)換

fun getStringLength(obj: Any): Int? {
  if (obj is String) {
    // 做過類型判斷以后憾赁,obj會被系統(tǒng)自動轉(zhuǎn)換為String類型
    return obj.length 
  }
  return null
}

還可以這樣

fun getStringLength(obj: Any): Int? {
  // 在 `&&` 運算符的右側(cè), `obj` 的類型會被自動轉(zhuǎn)換為 `String`
  if (obj is String && obj.length > 0)
    return obj.length
  return null
}

對比java 的代碼污朽,需要將數(shù)據(jù)類型強制轉(zhuǎn)換

public Integer getStringLength(Object object) {
    if (object instanceof String) {
      //需要強轉(zhuǎn)一下
        return ((String) object).length();
    }
    return null;
}

擴展函數(shù)

相信大家項目中有很多的util類,如StringUtils

Kotlin有一個聰明的解決方案 龙考, 擴展函數(shù) 蟆肆,幫助你擺脫所有的util類一勞永逸

fun Context.toast(text: String) = Toast.makeText(this, text, Toast.LENGTH_SHORT).show()

在所有的Context子類中可以直接調(diào)用toast("somewords")

基本數(shù)據(jù)類型也可以這樣

fun Int.dp2px():Int {
    return ......
}

代碼中可以直接調(diào)用

var px =12.dp2px()

默認參數(shù)

fun Date.format(format: String = "yyyy年MM月dd日 HH:mm"): String {
    return SimpleDateFormat(format, Locale.CHINA).format(this)
}

可以在代碼中這樣使用

var dateString =Date().format()

也可以

var dateString =Date().format(“yyyy-MM-dd HH:mm”)

高階函數(shù)

什么是高階函數(shù)

高階函數(shù)就是以另一個函數(shù)作為參數(shù)或返回值的函數(shù)矾睦,Kotlin可以以lambda或參數(shù)引用作為參數(shù)或返回值,所以炎功,任何以lambda或函數(shù)引用作為參數(shù)或返回值的都是高階函數(shù)

要使用Kotlin的高階函數(shù)就必須遵循它的函數(shù)類型
先來看一個簡單的例子枚冗,這是一個簡單的函數(shù)類型申明

val sum = { x: Int, y: Int -> x + y }

之所以能這么寫得益于Kotlin的類型推導,它的顯示寫法是這樣的:

var sum:(Int,Int)-> Int = {x , y-> x + y}

高階函數(shù)的使用

將函數(shù)類型作為參數(shù)蛇损,直接看代碼

 fun getNumResult(result: (Int, Int) -> Int): Int {
        return result(1,2)                                                                                                                       
    }

//調(diào)用
var value = getNumResult({ a, b -> a + b })
//方法里面最后一個參數(shù)是函數(shù)的時候可以省略
var value = getNumResult{ a, b -> a + b }
==> value = 3

var value = getNumResult{ a, b -> a * b }
==> value = 2

android 中常用的設置點擊事件就可以簡單的寫成

view.setOnClickListener { v ->
        {
            //傲尬隆!我被點擊了  
        }
}
//淤齐,當參數(shù)只有一個lambda參數(shù)的時候 可以省略
view.setOnClickListener {
   //肮赡摇!我被點擊了  
 }

正常的java代碼

view.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
       //按膊!毁涉!我被點擊了  
    }
});

高階函數(shù)在集合中的應用

val list = arrayListOf("aaa", "bb", "c","b")
list.sortBy {
    it.length
}
val find = list.find {
    it.length == 1
}
val indexOfFirst = list.indexOfFirst { 
    it.startsWith("b")
}
val filter = list.filter {
    it.length == 1
}

等等

運算符重載和迭代器重載

運算符重載

data class Area(var width: Int, var height: Int) {
    operator fun plus(other: Area): Area {
        return Area(this.width + other.width, this.height + other.height)
    }

    operator fun compareTo(other: Area): Int {
        return this.width * this.height - other.width * other.height
    }
}
val area1 = Area(6, 3)
val area2 = Area(4, 5)
print(area1 + area2)
==> Area(width=10, height=8)
print(area1 > area2)
==>false

常用的重載 加減乘除、compareTo等

迭代器重載

迭代器(iterator)是java中我們非常熟悉的東西了锈死,數(shù)據(jù)結(jié)構(gòu)如List和Set都內(nèi)置了迭代器贫堰,我們可以通過它提供的方法類遍歷訪問一個聚合對象中的各個元素

data class Book(val name: String)

class Bookcase(val books: List<Book>)

operator fun Bookcase.iterator(): Iterator<Book> = books.iterator()

重載iterator方法后的類可以通過以下方法遍歷

val list =ArrayList<Book>()
val case = Bookcase(list)
for (book in case) {
    ...
}

單例

java中單例的定義

public class DataCenter {
    private static DataCenter sInstance;

    private DataCenter() {
    }

    public static DataCenter getInstance() {
        if (sInstance == null) {
            sInstance = new DataCenter();
        }
        return sInstance;
    }
}

Kotlin 單例實現(xiàn)只需要關(guān)鍵字object

object DataCenter {
   
}

object 全局聲明的對象只有一個

內(nèi)聯(lián)函數(shù)

當我們使用lambda表達式時,它會被正常地編譯成匿名類待牵。這表示每調(diào)用一次lambda表達式其屏,一個額外的類就會被創(chuàng)建,并且如果lambda捕捉了某個變量缨该,那么每次調(diào)用的時候都會創(chuàng)建一個新的對象偎行,這會帶來運行時的額外開銷,導致使用lambda比使用一個直接執(zhí)行相同代碼的函數(shù)效率更低贰拿。

如果使用inline修飾符標記一個函數(shù)蛤袒,在函數(shù)被調(diào)用的時候編譯器并不會生成函數(shù)調(diào)用的代碼,而是 使用函數(shù)實現(xiàn)的真實代碼替換每一次的函數(shù)調(diào)用膨更。

內(nèi)聯(lián)函數(shù)如何運作

當一個函數(shù)被聲明為inline時妙真,它的函數(shù)體是內(nèi)聯(lián)的,也就是說荚守,函數(shù)體會被直接替換到函數(shù)被調(diào)用地方珍德,下面我們來看一個簡單的例子,下面是我們定義的一個內(nèi)聯(lián)的函數(shù):

 fun inlineFunc(prefix : String, action : () -> Unit) {
    println("call before $prefix")
    action()
    println("call after $prefix")
}

我們用如下的方法來使用這個內(nèi)聯(lián)函數(shù):

fun main(args: Array<String>) {
    inlineFunc("inlineFunc") {
        println("HaHa")
    }
}

運行結(jié)果為:

>> call before inlineFunc
>> HaHa
>> call after inlineFunc

最終它會被編譯成下面的字節(jié)碼:

fun main(args: Array<String>) {
 
   println("call before $prefix")
   println("HaHa")
   println("call after $prefix")
   
}

lambda表達式和inlineFunc的實現(xiàn)部分都被內(nèi)聯(lián)了矗漾,由lambda生成的字節(jié)碼成了函數(shù)調(diào)用者定義的一部分锈候,而不是被包含在一個實現(xiàn)了函數(shù)接口的匿名類中。

內(nèi)聯(lián)擴展函數(shù)之let

let函數(shù)通常作用就是避免寫一些判斷null的操作敞贡。

let函數(shù)的使用的一般結(jié)構(gòu)

object.let{
   it.todo()//在函數(shù)體內(nèi)使用it替代object對象去訪問其公有的屬性和方法
   ...
}
//另一種用途 判斷object為null的操作
object?.let{//表示object不為null的條件下泵琳,才會去執(zhí)行l(wèi)et函數(shù)體
   it.todo()
}

內(nèi)聯(lián)函數(shù)之with

with函數(shù)使用的一般結(jié)構(gòu)

 with(object){
   //todo
 }

適用于調(diào)用同一個類的多個方法或成員時,可以省去類名重復,直接調(diào)用類的方法即可

val person =Person()
with(viewHolder){
    tvName.setText(person.name)
  tvAge.setText(person.age)
}


內(nèi)聯(lián)擴展函數(shù)之a(chǎn)pply

apply函數(shù)使用的一般結(jié)構(gòu)

object.apply{
//todo
}

apply一般用于一個對象實例初始化的時候获列,需要對對象中的屬性進行賦值

val person =Person().apply{
  age =12
  name ="小明"
}

泛型及reified函數(shù)

reified 具體化的,對比java和kotlin中的實現(xiàn)

public static <T> T parseObject(String text, Class<T> cls) {
    return JSON.parseObject(text, cls);
}
inline fun <reified T> parseObject(text: String?): T {
    return JSON.parseObject(text, T::class.java)
}

結(jié)合上面的擴展函數(shù)還可以這樣

inline fun <reified T> String?.parseObject(): T {
    return JSON.parseObject(this, T::class.java)
}

調(diào)用的時候

val testJson = "{\"age\":22,\"name\":\"小明\"}"
val person: Person = testJson.parseObject()

利用這種特性還可以實現(xiàn)一個函數(shù)返回不同的數(shù)據(jù)類型

inline fun <reified T> Int.times(): T? {
    return when (T::class) {
        Int::class -> (this * 2) as T
        String::class -> ("$this$this") as T
        else -> null
    }
}
val stringValue: String = 12.times()
==> "1212"
val intValue: Int = 12.times()
==> 24

....

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末琳钉,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子蛛倦,更是在濱河造成了極大的恐慌歌懒,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,729評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件溯壶,死亡現(xiàn)場離奇詭異及皂,居然都是意外死亡,警方通過查閱死者的電腦和手機且改,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,226評論 3 399
  • 文/潘曉璐 我一進店門验烧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人又跛,你說我怎么就攤上這事碍拆。” “怎么了慨蓝?”我有些...
    開封第一講書人閱讀 169,461評論 0 362
  • 文/不壞的土叔 我叫張陵感混,是天一觀的道長。 經(jīng)常有香客問我礼烈,道長弧满,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,135評論 1 300
  • 正文 為了忘掉前任此熬,我火速辦了婚禮庭呜,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘犀忱。我一直安慰自己募谎,他們只是感情好,可當我...
    茶點故事閱讀 69,130評論 6 398
  • 文/花漫 我一把揭開白布阴汇。 她就那樣靜靜地躺著数冬,像睡著了一般。 火紅的嫁衣襯著肌膚如雪鲫寄。 梳的紋絲不亂的頭發(fā)上吉执,一...
    開封第一講書人閱讀 52,736評論 1 312
  • 那天疯淫,我揣著相機與錄音地来,去河邊找鬼。 笑死熙掺,一個胖子當著我的面吹牛未斑,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播币绩,決...
    沈念sama閱讀 41,179評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼蜡秽,長吁一口氣:“原來是場噩夢啊……” “哼府阀!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起芽突,我...
    開封第一講書人閱讀 40,124評論 0 277
  • 序言:老撾萬榮一對情侶失蹤试浙,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后寞蚌,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體田巴,經(jīng)...
    沈念sama閱讀 46,657評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,723評論 3 342
  • 正文 我和宋清朗相戀三年挟秤,在試婚紗的時候發(fā)現(xiàn)自己被綠了壹哺。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,872評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡艘刚,死狀恐怖管宵,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情攀甚,我是刑警寧澤箩朴,帶...
    沈念sama閱讀 36,533評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站秋度,受9級特大地震影響隧饼,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜静陈,卻給世界環(huán)境...
    茶點故事閱讀 42,213評論 3 336
  • 文/蒙蒙 一燕雁、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧鲸拥,春花似錦拐格、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,700評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至撞叨,卻和暖如春金踪,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背牵敷。 一陣腳步聲響...
    開封第一講書人閱讀 33,819評論 1 274
  • 我被黑心中介騙來泰國打工胡岔, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人枷餐。 一個月前我還...
    沈念sama閱讀 49,304評論 3 379
  • 正文 我出身青樓靶瘸,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子怨咪,可洞房花燭夜當晚...
    茶點故事閱讀 45,876評論 2 361