kotlin中语法与关键字(总结资料)

来源:互联网 发布:天府之国英文翻译 知乎 编辑:程序博客网 时间:2024/06/14 20:45
kotlin的一些语法关键词收集,包括一些网上的资料以及自己遇到的一些kotlin的问题解决
var与val
var表示java中的变量申明,而val表示常量的申明

Kotlin不允许声明变量但不初始化
赋非空值
var str: String = ""
设为null
var str: String? = null
强制设为null
var str: String = null!!
Kotlin是空安全的,但是第三种是例外情况,如果给一个变量赋值为null!!,那么就等于声明这个变量不是空安全的,就算这样使用
var str:String = null!!
str.length

lateinit:延迟初始化属性
都知道的是,在类内声明的属性必须初始化,如果设置非NULL的属性,应该将此属性在构造器内进行初始化。假如想在类内声明一个NULL属性,在需要时再进行初始化,与Kotlin的规则是相背的,此时我们可以声明一个属性并延迟其初始化,此属性用lateinit修饰符修饰。

XX:Bundle?
代表xx允许为空

?:操作符
如果 ?: 左侧的表达式值不是null, 就会返回表达式的的值,否则, 返回右侧表达式的值.
用 ?. 运算符来访问一个可空的变量。
用 ?: 运算符来指定当该变量为空时的替代值

open class 的使用
使用open该关键字表示当前类需要被重写,与java中的final关键字相反,如果不希望该类被重写,可以使用final关键字

Unit
只有一个值的类型:单元对象。这种类型对应于Java中的“void”类型。
(pos : Int) ->Unit他的输入为int,返回值为Unit

as
as相当于java中的强制类型转换

"""
原始字符串(raw string)由三重引号(“”“)分隔。
原始字符串可以包含换行符和任何其他字符。
val fooRawString = """

vararg
fun varargExample(vararg names: Int)
用“vararg”关键字标记函数参数,
则允许将可变数量的参数传递给函数。

单个表达式
fun odd(x: Int): Boolean = x % 2 == 1
当函数由单个表达式组成时,可以省略大括号,
直接在 = 符号后写函数体。

::
用 :: 操作符把一个命名函数用作参数

it
如果lambda只有一个参数,
那么它的声明可以(与 -> 一起)省略。
单个参数的名称将是“it”。
val notPositive = not {it > 0}

调用构造函数来创建一个实例。
    注意,Kotlin没有 “new” 这个关键字。
    val fooExampleClass = ExampleClass(7)

infix
如果一个函数用 “infix” 关键字标记,称为中缀标记。
println(fooExampleClass infixMemberFunction 4) // => 28

dataclass
在kotlin中 class前添加data可以实现javabean的效果,“hashCode”、“equals”和“toString”方法都是自动生成的。

with
"with" 方法与JavaScript中的 "with" 声明类似.是kotlin中一种代替swich的方式,"when" 可以带参数,"when" 也可以当作函数,并返回值.

Of的使用
listOf
可以用 "listOf" 方法创建一个list。   这个list是不可变的 —— 不能增加或删除元素。
可以通过序号获取list中的元素。
println(fooList[1]) // => b

setOf
用 "setOf" 方法创建集合.
val fooSet = setOf("a", "b", "c")

mapOf
用 "mapOf" 方法创建 map.
val fooMap = mapOf("a" to 8, "b" to 7, "c" to 9)

在map中,通过 kep 来获取 value.
println(fooMap["a"]) // => 8

if
“if” 表达式可以,"when" 可以带参数.直接返回值。
因此,Kotlin 不需要三元运算符 ?:

is
可以用“is”运算符检查对象是否是特定类型。
如果对象通过了类型检查,就可以把它当作这个类型来用,无需显示转换。
if (x is Boolean) {
            // x is automatically cast to Boolean
            return x
        }

扩展方法
在kotlin中允许开发者在已写好的接口类中添加扩展方法,方法名与要扩展的方法名字一致就可添加

enum枚举类
枚举类与Java的枚举类型相似.
enum class EnumExample {
    A, B, C
}

object
"object" 关键字可用于创建单例对象。
我们不能实例化它,但我们可以通过它的名称来引用它的唯一实例。
这与Scala的单例对象类似。
*/
object ObjectExample {
    fun hello(): String {
        return "hello"
    }
}
fun useObject() {
    ObjectExample.hello()
    val someRef: Any = ObjectExample // 可以直接使用对象名称
}

const
如果属性值载编译期间就能确定,则可以使用const修饰符,将属性标记为编译器常数值,这类属性必须满足以下所有条件:
  • 必须是顶级属性,或者是一个object的成员
  • 值被初始化为String类型,或基本类型
  • 不存自定义的取值方法
其效果相当于java中的static,但是其内容必须确定是一个常量的值

!!与?空判断
Kotlin的空安全设计对于声明可为空的参数,在使用时要进行空判断处理,有两种处理方式一种像Java一样抛出空异常,字段后加 !! ,另一种不做处理直接跳过,字段后加 ?

$字符串模板
在Java中拼接字符串的代码可读性都很差,在Kotlin字符串拼接变得非常简洁,只需用 $ 后面加上参数名,复杂的参数要加上 {}
val user = User()
//赋值
user.name = "tutu"
user.age = "23"
//取值
val name = user.name
val age = user.age
var userInfo = "name:${user.name}, age:$age"
//输出结果:name:tutu, age:23

companion object
伴生对象(静态变量)
Kotlin一般在类中不允许static成员,可以使用companion object来创建一个伴生对象从而可以使用static成员.


高阶函数(Higher-Order Functions )

Kotlin还有一个Java不具备的特性,就是给方法传参数的时候,这个参数也可以是个方法。多么神奇。我们写个方法,就是从一个List种取出偶数,组成一个新的List。

我们用Java写:

    public List<Integer> filter(List<Integer> list) {

        List<Integer> resultList = new ArrayList<>();

        for (int t : list) {
            if (t % 2 == 0) {
                resultList.add(t);
            }
        }

        return resultList;
    }

我们用Kotlin写:

    fun  filter(items: Collection<Int>, f: (Int) -> Boolean): List<Int> {

        val filtered = arrayListOf<Int>()

        for (item in filtered) {
            if (f(item)) {
                filtered.add(item)
            }
        }

        return filtered
    }

在Kotlin中,方法的参数类型是在:的后面。(Int) -> Boolean这个是上面方法的第二个参数的参数类型。表示这个参数是个方法并且这个方法的传入的是一个Int类型的值,返回值是Boolean类型的值。那么怎么调用这个上面这个方法呢?

val numbers = listOf<Int>(1, 2, 3, 4)

// 得到所有偶数组成的List
filter(numbers, {
    it % 2 == 0
}) 

在Kotlin中当一个方法的方法参数是最后一个的时候我们还可以写成这样

val numbers = listOf<Int>(1, 2, 3, 4)
// 可以把大挂号放外面
filter(numbers) {
    it % 2 == 0
}

如果我们想得到List中的奇数组成的List可以这样,相当简单

val numbers = listOf<Int>(1, 2, 3, 4)
filter(numbers) {
    it % 2 == 1  // 奇数
}

从上面的例子我们可以看出方法参数的厉害和简洁了。



KotlinLambda表达式 
在Kotlin编写的过程中,会遇到大量的Lambda表达式,Lambda表达式是Java8中提出的一种表达式,对于Android用户来说,并没有相应的使用。kotlin为Android开发者提供了大量的现代语言编程方式与Java中新提到的概念与方法,Lambda表达式就是其中一种。

为什么? 
   我们为什么需要Lambda表达式 
   主要有三个原因: 
   > 更加紧凑的代码 
     比如Java中现有的匿名内部类以及监听器(listeners)和事件处理器(handlers)都显得很冗长 
   > 修改方法的能力(我个人理解为代码注入,或者有点类似JavaScript中传一个回调函数给另外一个函数) 
     比如Collection接口的contains方法,当且仅当传入的元素真正包含在集合中,才返回true。而假如我们想对一个字符串集合,传入一个字符串,只要这个字符串出现在集合中(忽略大小写)就返回true。 
     简单地说,我们想要的是传入“一些我们自己的代码”到已有的方法中,已有的方法将会执行我们传入的代码。Lambda表达式能很好地支持这点 
   > 更好地支持多核处理 
     例如,通过Java 8新增的Lambda表达式,我们可以很方便地并行操作大集合,充分发挥多核CPU的潜能。 
     并行处理函数如filter、map和reduce。

怎么做? 
   实例1 FileFilter 
File dir =new File("/an/dir/"); FileFilter directoryFilter = new FileFilter() {publicboolean accept(File file) {return file.isDirectory(); }};
   通过Lambda表达式这段代码可以简化为如下:
File dir =new File("/an/dir/");FileFilter directoryFilter = (File f) -> f.isDirectory();File[] dirs = dir.listFiles(directoryFilter);
   进一步简化:
File dir =new File("/an/dir/");File[] dirs = dir.listFiles((File f) -> f.isDirectory());

   Lambda表达式使得代码可读性增强了。我承认我开始学习Java的时候对那个匿名内部类感到很困扰,而现在Lambda表达式让这一切看起来都很自然(尤其是有.NET背景的童鞋会发现这个跟.NET中的Lambda表达式好像) 
   Lambda表达式利用了类型推断(type inference)技术:
编译器知道FileFilter只有一个方法accept(),所以accept()方法肯定对应(File f) -> f.isDirectory()
而且accept()方法只有一个File类型的参数,所以(File f) -> f.isDirectory()中的File f就是这个参数了,
.NET把类型推断做得更绝,如果上面用.NET Lambda表达式写法的话是这样的: File[] dirs = dir.ListFiles(f => f.isDirectory());即压根就不需要出现File类型指示。
   实例2 Event Handler
Button bt =new Button(); bt.addActionListener(new ActionListener() { publicvoid actionPerformed(ActionEvent e) { ui.showSomething(); }});

   使用Lambda表达式后:
Button bt =new Button();ActionListener listener = event -> { ui.showSomething(); };bt.addActionListener(listener);
   进一步简化: 
Button bt =new Button();bt.addActionListener(event -> { ui.showSomething(); });
 
外循环、内循环和Map、Reduce、Filter 
   一直到现在,处理Java集合的标准做法是采用外循环。比如:
List<String> list =new ArrayList<String>();list.add("hello");list.add("world");for(int item: list) { // 处理item}
   还有迭代器循环,它们都是外循环,并且都是顺序处理(sequential handling)。顺序特性也常常引发ConcurrentModificationException,只要我们尝试着并发修改集合。 
   Lambda表达式提供了内循环机制。 
   我们工作中可能经常面临下面的需求:
> 过滤掉一个集合中不符合条件的元素得到一个新集合> 对集合中的每个元素进行某种转换,并且对转换后的集合进行处理> 统计整个集合的某个属性,比如统计集合元素值的总和或平均值
   这些任务即filter、map和reduce,他们的共同特点是: 
   需要对集合中的每个元素运行一小段相同的代码。 
   传统的实现这些任务的代码让人感到很乏味,幸运的是Java 8提供了完成这些任务的更简洁的方案,当然还是利用Lambda表达式,但也引入了一个新的类库java.util.functions,包含Predicate、Mapper和Block。 
   Java 8中,一个Predicate(谓词)是这样一个方法:它根据变量的值进行评估(evaluate),返回true或false。 
   比如下面:
List<String> list = getMyStrings();for(String myString: list) { if(myString.contains(possible)) { System.out.println(myString + " contains " + possible); }}
   使用Predicate和Filter后得到下面代码:
List<String> list = getMyStrings();Predicate<String> matched = s -> s.equalsIgnoreCase(possible);list.filter(matched);
   进一步简化:
List<String> list = getMyStrings();list.filter(s -> s.equalsIgnoreCase(possible));
 
Lambda表达式语法规则 
   到目前为止Java 8中的Lambda表达式语法规则还没有完全确定。 
   但这里简单介绍下: 
   对于前面的:
File dir =new File("/an/dir/");File[] dirs = dir.listFiles((File f) -> f.isDirectory());
   accept()方法返回布尔值,这种情况f.isDirectory()显然也得是布尔值。这很简单。 
   而对于:
Button bt =new Button();bt.addActionListener(event -> { ui.showSomething(); });
   actionPerformed()方法的返回类型是void,所以需要特殊处理,即在ui.showSomething();左右加上花括号。(想象下不加会怎么样?如果不加的话,若showSomething()方法返回值是整数类型,那么就意味着actionPerformed()返回整数类型,显然不是,所以必须加花括号用来标记)。 
   如果Lambda表达式主体部分包含多条语句,也必须用花括号,并且return语句不能省。 
   比如下面这个:
File dir =new File("/an/dir/");File[] dirs = dir.listFiles((File f) -> { System.out.println("Log:...");return f.isDirectory(); });

使用三方控件遇到的坑与注意点

Databinding
使用Databinding需要在app moudle的build.gradle里面添加
kapt {
generateStubs = true
}
dependencies {
kapt 'com.android.databinding:compiler:2.2.0-rc2'
}
dependencies {
kapt 'com.android.databinding:compiler:2.2.0-rc2'
}
2.2.0-rc2 这个版本号必须要和根目录下的build.gradle文件内的com.android.tools.build:gradle:2.2.0-rc2 版本号一致


Dagger2
官方博客说是支持Dagger2的,但实际遇到的情况是和Databinding结合使用有问题
奇怪的报错
使用Databinding,设置ViewModel时
cannot access class '...'. check your module classpath for missing or conflicting dependencies
应该是Kotlin的bug,只是报错,不影响编译,如果不希望提示错误,可以添加
@Suppress("MISSING_DEPENDENCY_CLASS")
编译的时候报找不到class的问题,clean一下就好,不知道什么原因

怎么从Kotlin转为Java
两种方法
打包,输出apk,使用dex2jar将apk代码文件提取成jar,使用jd-jui查看,将对应的代码拷贝出来,修改,使用
把Kotlin文件删掉,用Java重写一遍

转载内容链接:
http://www.cnblogs.com/feichexia/archive/2012/11/15/Java8_LambdaExpression.html

原创粉丝点击