当前位置:   article > 正文

10天学会kotlin DAY1 kotlin 和 Java 的不同之处_kotlin java 差异 快速学习kotlin

kotlin java 差异 快速学习kotlin


kotlin 简介

Kotlin 是一个基于 JVM 的新的编程语言,由 JetBrains 开发。
Kotlin 可以编译成Java字节码,也可以编译成JavaScript,方便在没有JVM的设备上运行。

Kotlin兼容Java语言, 能够直接调用Java代码,但比Java更安全,更简洁。

JetBrains在Apache 2许可证下,开源了Kotlin,开放了以下项目代码:

Kompiler:Kotlin编译器
基础Java增强库:针对JDK collections和其他框架的实用程序
构建工具:集成Ant和Maven
IntelliJ IDEA插件:Kotlin本地IDE
2017-05-17,kotlin 成为 Android 开发的一级语言。


提示:以下是本篇文章正文内容,下面案例可供参考

一、Kotlin与Java的异同

1.函数

kotlin:

fun main(args: Array<String>) {
    println("Hello, world!")
}
  • 1
  • 2
  • 3
  • 关键字 fun 用来声明一个函数。
  • 参数的类型写在它的名称后面。
  • 函数可以定义在文件的最外层,不需要把它放在类中。
  • 数组就是类。
  • 使用 println 代替了 System.out.println。
  • 和许多其他现代语言一样,可以省略每行代码结尾的分号。

表达式函数体:

fun max(a: Int, b: Int): Int = if (a > b) a else b
  • 1

语句和表达式:

在 Kotlin 中,if 是表达式,而不是语句。语句和表达式的区别在于,表达式有值,并且能作为另一个表达式的一部分使用;而语句总是包围着它的的代码块中的顶层元素,并且没有自己的值。
在Java 中,所有的控制结构都是语句。
而在Kotlin中,除了循环(for 、while、和 do/while)以外大多数控制结构都是表达式。这种结构控制结构和其他表达式的能力让你可以简明扼要地表示许多常见的模式。

另一方面,Java中的赋值操作是表达式,在Kotlin中反而变成了语句。这有助于避免比较和赋值之间的混淆,而这种混淆是常见的错误来源。

Java:

public void main(String[] args) {
    System.out.println("Hello, world!");
}
  • 1
  • 2
  • 3

2. 变量

变量类型

Kotlin:

val a = 5 //可以不显示声明变量类型
val a: Int = 5 //也可以显示声明变量类型
  • 1
  • 2

Java:

int a = 5;  //必须显示声明变量类型
  • 1

可变变量

Kotlin:

var answer = 0
answer = 1
  • 1
  • 2

1
2
var : 可变引用。这种变量的值可以被改变。这种声明对应的是普通(非 final)的 Java 变量。

Java:

int answer = 0
answer = 1
  • 1
  • 2

非 final 修饰即可。

不可变变量

Kotlin:

val answer = 0
  • 1

val: 不可变引用。使用 val 声明 的变量不能在初始化之后再次赋值。它对应的是 Java 的 final 变量。

默认情况下,应该尽可能地使用 val 关键字 来声明所有的 Kotlin 变量,仅在必要的时候换成var。使用不可变引用、不可变对象及无副作用的函数让代码更接近函数式编程风格。

在定义了 val 变量的代码块执行期间, val 变量只能进行唯一一次初始化。但是,如果编译器能确保只有唯一一条初始化语句被执行,可以根据条件使用不同的值来初始化它

val message: String
if (canPerformOperation()) {
    message = "Success"
} else {
    message = "Failed"
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

尽管 val 引用自身是不可变的,但是它指向的对象可能是可变的。

val languages = arrayListOf("Java")
languages.add("Kotlin")
  • 1
  • 2

Java:

  final int answer = 0
  • 1

final 修饰即可。

3. 类和属性

有参数的构造方法

Kotlin:

class Person(val name: String)
  • 1

Java:

public class Person {
    private final String name;

    public Person(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

setter 和 getter

Kotlin:

class Person {

    val name: String //只读属性:生成一个字段和一个简单的getter

    var isMarried: Boolean // 可写属性:一个字段、一个getter 和 一个setter

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

访问属性:

val person = Person()
person.name //只读,不可以修改值
person.isMarried //可读写
  • 1
  • 2
  • 3

自定义getter:

class Person(val age: Int) {

    val name: String? = null

    var isMarried: Boolean = false


    val isOld: Boolean
        get() {
            return age > 60
        }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

访问isOld:

val person = Person(50)
person.name = "小明"
person.isMarried = true
person.isOld
  • 1
  • 2
  • 3
  • 4

Java:

public class Person {

    private int age;

    private final String name;

    private boolean isMarried;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public boolean isMarried() {
        return isMarried;
    }

    public void setMarried(boolean married) {
        isMarried = married;
    }

    public boolean isOld() {
        return this.age > 50;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

4. 枚举和"when"

枚举

Kotlin:

enum class Color(val r: Int, val g: Int, val b: Int) {
    RED(255, 0, 0),
    ORANGE(255, 165, 0),
    YELLOW(255, 255, 0),
    GREEN(0, 255, 0),
    BLUE(0, 0, 255),
    INDIGO(75, 0, 130),
    VIOLET(238, 130, 238)
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

Kotlin 用了一个enum class 两个关键字,而 Java 只有 enum 一个关键字。

Java:

public enum Color {
    RED(255, 0, 0),
    ORANGE(255, 165, 0),
    YELLOW(255, 255, 0),
    GREEN(0, 255, 0),
    BLUE(0, 0, 255),
    INDIGO(75, 0, 130),
    VIOLET(238, 130, 238);

    private int r;
    private int g;
    private int b;

    Color(int r, int g, int b) {
        this.r = r;
        this.g = g;
        this.b = b;
    }

    public int getR() {
        return r;
    }

    public int getG() {
        return g;
    }

    public int getB() {
        return b;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

when (是一个表达式,可以有返回值)

Kotlin:

fun getWarmth(color: Color): String {
    when (color) {
        Color.RED, Color.ORANGE, Color.YELLOW -> return "warm"
        Color.GREEN -> return "neutral"
        Color.BLUE, Color.INDIGO, Color.VIOLET -> return "cold"
        else -> return ""
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

Kotlin 中的when结构对应Java 中的switch语句。

Java:

 public String getWarmth(Color color) {
        switch (color) {
            case RED:
            case ORANGE:
            case YELLOW:
                return "warm";
            case GREEN:
                return "neutral";
            case BLUE:
            case INDIGO:
            case VIOLET:
                return "cold";
            default:
                return "";
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

5.“while” 和 “for” 循环

“while” 循环

while 和 do-while 循环与 Java 循环是一样的:

while (condition) {
/*...*/
}

do { 

}  while (condition){

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

“for” 循环

Kotlin:

使用..运算符(range 表达式) 来表示区间:

val oneToTen = 1..10

for (i in 1..100){
    println(i)
}
  • 1
  • 2
  • 3
  • 4
  • 5
fun isNotDigit(c: Char) = c !in '0'..'9'
  • 1

区间是包含或者闭合的,意味着第二个值始终是区间的一部分。

迭代 map:

val binaryResp = TreeMap<Char, String>()
for (c in 'A'..'Z') {
    val binary = Integer.toBinaryString(c.toInt())
    binaryResp[c] = binary
}
for ((letter, binary) in binaryResp) {
    println("$letter = $binary")
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

使用下标迭代:

val list = arrayListOf("10", "11", "111")
for ((index, element) in list.withIndex()) {
    println("$index : $element")
}
  • 1
  • 2
  • 3
  • 4

Java:

   for (int i = 1; i <= 100; i++) {
        System.out.println(i);
    }

    TreeMap<Character, String> binaryResp = new TreeMap<>();
    Character[] characters = {'A', 'B', 'C','D','Z'};
    for (Character c : characters) {
        String binary = Integer.toBinaryString(c);
        binaryResp.put(c, binary);
    }
    Set<Map.Entry<Character, String>> entries = binaryResp.entrySet();
    for (Map.Entry<Character, String> entry : entries) {
        System.out.println(entry.getKey() + "=" + entry.getValue());
    }

    List<String> list = Arrays.asList("10", "11", "111");
    for (int i = 0, size = list.size(); i < size; i++) {
        System.out.println(i + ":" + list.get(i));
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

6.异常

抛出异常

Kotlin:

  val percentage = 50
    if (percentage !in 0..100)
        throw IllegalArgumentException("A percentage value must be between 0 and 100: $percentage")
  • 1
  • 2
  • 3

不必使用 new 关键字来创建异常实例。

与 Java 不同的是,Kotlin 中的 throw 结构是一个表达式,能作为另一个表达式的一部分使用

val percentage =
    if (number in 0..100) {
        number
    } else {
        throw IllegalArgumentException("A percentage value must be between 0 and 100: $percentage")
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

Java:

int percentage = 50;
if (percentage < 0 || percentage > 100) {
    throw new IllegalArgumentException("A percentage value must be between 0 and 100: " + percentage);
}
  • 1
  • 2
  • 3
  • 4

“try” “catch” 和 “finally”

Kotlin:

 fun readNumber(reader: BufferedReader): Int? {
        try {
            val line = reader.readLine()
            return Integer.parseInt(line)
        } catch (e: NumberFormatException) {
            return null
        } finally {
            reader.close() //finally 的作用和 Java 中的一样
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

Kotlin 不区分受检异常和未受检异常。 在这里没有处理readLine方法抛出的 IOException 异常。

“try” 也可以作为表达式:

  fun readNumber(reader: BufferedReader): Int? {
        return try {
            val line = reader.readLine()
            Integer.parseInt(line)
        } catch (e: NumberFormatException) {
            null
        } finally {
            reader.close()
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

Java:

 public Integer readNumber(BufferedReader reader) throws IOException {
        try {
            String line = reader.readLine();
            return Integer.parseInt(line);
        } catch (NumberFormatException e) {
            return null;
        } finally {
            reader.close();
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

IOException 是一个受检异常。在 Java 中必须显示地处理。必须声明函数能抛出的所有受检异常。如果调用另外一个函数,需要处理这个函数的受检异常,或者声明函数也能抛出这些异常

7.创建集合

Kotlin:

val set = hashSetOf(1, 7, 53) //创建 HashSet 集合

val arrayList = arrayListOf(1, 7, 53) //创建 List 集合

val map = hashMapOf(1 to "one", 2 to "two", 3 to "three") //创建 HashMap 集合

set.javaClass // Kotlin 的 javaClass 等价于 Java  的 getClass()

arrayList.last() // 获取列表的最后一个

arrayList.max() //得到数字列表的最大值
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

Java:

   Set<Integer> set = new HashSet<Integer>(); //创建 HashSet 集合
    set.add(1);
    set.add(7);
    set.add(53);

    List<Integer> arrayList = new ArrayList<>(); //创建 List 集合
    arrayList.add(1);
    arrayList.add(7);
    arrayList.add(53);

    Map<Integer, String> map = new HashMap<>(); //创建 HashMap 集合
    map.put(1, "one");
    map.put(2, "two");
    map.put(3, "three");

    set.getClass();  //Java  的 getClass() 等价于 Kotlin 的 javaClass 

    if (arrayList.size() > 0) // 获取列表的最后一个
        arrayList.get(arrayList.size() - 1);

    Collections.max(arrayList, new Comparator<Integer>() { //得到数字列表的最大值
        @Override
        public int compare(Integer o1, Integer o2) {
            if (o1 > o2) {
                return 1;
            } else if (o1 == o2) {
                return 0;
            }
            return -1;
        }
    });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

8.函数

命名参数

Kotlin:

假设现在有一个函数,它的作用是在集合元素中添加分割符号,然后将集合转化为字符串。

kotlin 函授默认都是public,其实kotlin 的函数,更规范,先有输入,再有输出

  fun <T> joinToString(collection: Collection<T>, separator: String, prefix: String, postfix: String): String {

        val result = StringBuffer(prefix)

        for ((index, element) in collection.withIndex()) {
            if (index > 0) result.append(separator)
            result.append(element)
        }

        result.append(postfix)

        return result.toString()

    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

在调用函数时,显示地标明一些参数的名称,避免参数混淆:

   val arrayList = arrayListOf(1, 7, 53)
    joinToString(arrayList, separator = ";", prefix = "[", postfix = "]")
  • 1
  • 2

Java:

   public <T> String joinToString(Collection<T> collection, String separator, String prefix, String postfix) {
        StringBuilder sb = new StringBuilder(prefix);

        Iterator<T> iterator = collection.iterator();
        int i = 0;
        while (iterator.hasNext()) {
            if (i > 0) sb.append(separator);
            sb.append(iterator.next());
            i++;
        }

        sb.append(postfix);
        return sb.toString();
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

在调用函数时,标明参数的名称:

 List<Integer> arrayList = new ArrayList<>();
    arrayList.add(1);
    arrayList.add(7);
    arrayList.add(53);
    joinToString(arrayList, /* separator */";",/* prefix */ "[", /* postfix */ "]");
  • 1
  • 2
  • 3
  • 4
  • 5

默认参数

Kotlin:

声明函数的时候,指定参数的默认值,避免创建重载函数:

fun <T> joinToString(
    collection: Collection<T>,
    separator: String = ";",
    prefix: String = "",
    postfix: String = ""
): String
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

在调用函数时,可以用所有参数来调用,也可以省略掉部分参数:

joinToString(arrayList, ";", "", "")
joinToString(arrayList)
joinToString(arrayList, ";")
  • 1
  • 2
  • 3

当使用常规的调用语法时,必须按照函数声明中定义的参数顺序来给定参数,可以省略的只有在末尾的参数。如果使用命名参数,可以省略中间的一些参数,也可以以任意顺序只给定需要的参数:

joinToString(arrayList, prefix = "[",postfix = "]")
  • 1

Java:

 public <T> String joinToString(Collection<T> collection) {
        return joinToString(collection, ";", "", "");
    }

    public <T> String joinToString(Collection<T> collection, String separator) {
        return joinToString(collection, separator, "", "");
    }

    public <T> String joinToString(Collection<T> collection, String separator, String prefix, String postfix) {
         //...
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

因为Java 没有默认值的概念,从Java 中调用 Kotlin 函数的时候,必须显示地指定所有参数值。如果需要从 Java 代码中做频繁的调用,而且希望它能对 Java 的调用者简便,可以用 @JvmOverloads 注解它。

   @JvmOverloads
    fun <T> joinToString(
        collection: Collection<T>,
        separator: String = ";",
        prefix: String = "",
        postfix: String = ""
    ): String
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

此时,编译器就会生成如下重载函数:

public <T> String joinToString(Collection<T> collection) {

}

public <T> String joinToString(Collection<T> collection, String separator) {

}

public <T> String joinToString(Collection<T> collection, String separator, String prefix) {

}

public <T> String joinToString(Collection<T> collection, String separator, String prefix, String postfix) {

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

每个重载函数的默认参数值都会被省略。

9.静态工具类

顶层函数(静态函数)

Kotlin:

Kotlin 中的新定义:顶层函数,也就是把函数直接放到代码文件的顶层,不用从属于任何的类。这些文件顶层的函数依然是包内的成员,如果需要从包外访问它,则需要 import ,但不再需要额外包一层。

实例:把 joinToString 直接放到 strings 的包中,创建一个名为 Join.kt 的文件。

package com.example.kotlin.strings

fun <T> joinToString(
    collection: Collection<T>,
    separator: String = ";",
    prefix: String = "",
    postfix: String = ""
): String {

    val result = StringBuffer(prefix)

    for ((index, element) in collection.withIndex()) {
        if (index > 0) result.append(separator)
        result.append(element)
    }

    result.append(postfix)

    return result.toString()

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

在 Kotlin 中调用顶层函数:

    com.example.kotlin.strings.joinToString(arrayList, ";", "", "")
  • 1

1
在 Java 中调用顶层函数:

   com.example.kotlin.strings.JoinKt.joinToString(arrayList, /* separator */";",/* prefix */ "[", /* postfix */ "]");
  • 1

要改变包含Kotlin 顶层函数的生成的类的名称,需要为这个文件添加 @JvmName 的注解,将其放到这个文件的开头,位于包名的前面:

@file:JvmName("StringFunctions")

package com.example.kotlin.strings

fun <T> joinToString(
    collection: Collection<T>,
    separator: String = ";",
    prefix: String = "",
    postfix: String = ""
): String {
   //......
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

然后在 Java 中再调用顶层函数,类型需要改变:

com.example.kotlin.strings.StringFunctions.joinToString(arrayList, /* separator */";",/* prefix */ "[", /* postfix */ "]");
  • 1

顶层函数对应 Java 中的静态函数。

Java:

public class JoinJava {

    public static <T> String joinToString(Collection<T> collection, String separator, String prefix, String postfix) {
        StringBuilder sb = new StringBuilder(prefix);

        Iterator<T> iterator = collection.iterator();
        int i = 0;
        while (iterator.hasNext()) {
            if (i > 0) sb.append(separator);
            sb.append(iterator.next());
            i++;
        }

        sb.append(postfix);
        return sb.toString();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

顶层属性(静态变量)

Kotlin:

Kotlin 中的新定义:顶层属性,和顶层函数一样,属性也是放到文件的顶层。

@file:JvmName("StringFunctions")

package com.example.kotlin.strings

const val LANGUAGE_KOTLIN: String = "Kotlin"
  • 1
  • 2
  • 3
  • 4
  • 5

在 Kotlin 中调用顶层函数:

com.example.kotlin.strings.LANGUAGE_KOTLIN
  • 1

在 Java 中调用顶层函数:

com.example.kotlin.strings.StringFunctions.LANGUAGE_KOTLIN;
  • 1

顶层属性对应 Java 中的静态属性。

Java:

public static final String LANGUAGE_KOTLIN  = "Kotlin";
  • 1

10.可变参数

Kotlin:

参数通过 vararg 来修饰:

fun convertNumbersToList(vararg values: Int) {
    println(values)
}
   
convertNumbersToList(1, 2, 3, 5)
  • 1
  • 2
  • 3
  • 4
  • 5

Java:

public void convertNumbersToList(int ...values){
    System.out.println(values);
}

convertNumbersToList(1,2,3,4);
  • 1
  • 2
  • 3
  • 4
  • 5

11.字符串和正则表达式

Kotlin:

在三重引号中的字符串,不会对任何字符进行转义,包括反斜杠。

实例:使用正则表达式解析文件路径。

文件路径格式:

"/users/wangjiang/koltin-book/chapter.adoc"
"/users/wangjiang/koltin-book/" 目录
"chapter" 文件名
".adoc" 扩展名
  • 1
  • 2
  • 3
  • 4

函数解析文件路径:

    fun parsePath(path: String) {
        val regex = """(.+)/(.+)\.(.+)""".toRegex()
        val matchResult = regex.matchEntire(path)
        if (matchResult != null) {
            val (directory, filename, extension) = matchResult.destructured
            println("Dir:$directory,name:$filename,ext:$extension")
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

三重引号字符串除了避免转义字符以外,还可以包含任何字符,包括换行符。

val kotlinLogo = """|  //
    .| //
    .|/ \
""".trimMargin(".")
Log.d("parsePath",kotlinLogo)

|  //
| //
|/ \
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

Java:

函数解析文件路径:

public void parsePath(String path) {
    Pattern pattern = Pattern.compile("(.+)/(.+)\\.(.+)");
    Matcher matcher = pattern.matcher(path);
    if (matcher.find()) {
        Log.d("parsePath", "Dir:" + matcher.group(1) + ",name:" + matcher.group(2) + ",ext:" + matcher.group(3) );
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

总结

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/745855
推荐阅读
相关标签