接口的默认方法
Java8允许我们给接口添加一个非抽象的方法实现,只需要使用default关键字即可,这个特征被称作扩展方法。
首先我们定义一个接口,该接口有一个抽象方法print和一个具体方法defaultPrint();
|
|
实现了该接口一个类如下,并对其进行调用:
|
|
运行结果如下:
|
|
考虑到Java中只有单继承,如果需要给一个类赋予新特性,通常是使用接口来实现。允许接口中写具体的实现方法,实现对接口功能的扩展,避免了单继承的弊端。
Lambda表达式
Java中对字符串进行排序,可以通过传入一个List对象和一个比较器来制定顺序排列。如下:
|
|
Lambda表达式提供了更加简洁的写法:
|
|
函数式接口
每一个Lambda表达式对应着一个类型,通常是接口类型。函数式接口指的是仅仅只包含一个抽象方法的接口,每一个该类型的lambda表达式都会被匹配到这个抽象方法中,该接口也可以添加默认方法。
因此实际上,我们可以把Lambda当成任意只包含一个抽象方法的接口类型,确保你的接口一定达到这个要求,只需要给接口添加@FunctionalInterface注解,编译时会检查接口中是否只存在一个抽象方法。
|
|
实际上不添加注解,程序也是可以正确执行的。而将Lambda表达式映射到一个但方法的接口上,在其他语言中已经有实现了。单一方法的接口使得Lambda表达式更加的简洁。
方法与构造函数引用
Java中允许你使用::
关键字来传递方法或者构造函数的引用,下面有一个实例:
|
|
可以看出Person::new获取Person类的构造函数的引用,Java编译器会根据create方法的签名来选取合适的构造方法。
Lambda作用域
Lambda表达式中访问外层作用域和匿名方法中的方式类似,可以直接访问final修饰的外层局部变量,实例的字段及静态变量。
访问局部变量
|
|
- final不强制要求添加
- 不添加final,num也不能被后面的程序修改,隐式的final。
访问字段和静态变量
|
|
访问接口的默认方法
JDK1.8中包含了很多内建的函数式接口,如之前常用的Comparator或者Runnable接口,这些接口都增加了@FunctionInterface注解以便可以使用Lambda表达式。同样提供了很多全新的Lambda接口。
- Predicate接口
|
|
该接口只有一个参数,返回boolean类型的值。改接口包含多种默认方式来将Predicate组合成其他复杂的逻辑:
|
|
- Function接口
|
|
只有一个参数并且返回一个结果,附带了一些组合方法。
|
|
- Supplier接口
|
|
返回一个任意范式的值。
- Consumer接口
|
|
- Comparator接口
|
|
- Optional接口
不是函数式接口,是用来放置空指针异常的辅助类型。
- Stream接口
表示能应用中哎一组元素上一次执行的操作序列。Stream操作分为中间操作或者最终操作两种,最终操作返回以特定类型的计算结果,而中间操作返回Stream本身。可以将多个操作穿起来。Stream创建过程中需要指定一个数据源。
|
|
* Filter过滤:通过一个Predicate接口来过滤并只保留符合条件的元素,该操作属于中间操作,所以在过滤后可以将结果来应用其他Stream操作。forEach需要一个函数来对过滤后的 元素依次执行。forEach时一个最终操作,不能在其之后再执行Stream操作。
* Sort排序:排序是一个中间操作。
* Map映射:中间操作map,会将元素根据指定的Function接口来依次将元素转换成另外的对象,如将小写转换成大写
* Match匹配:检测指定的Predicate是否匹配整个Stream,最终操作。
* Count计数,最终操作,返回Stream中元素的个数,返回值为long
* Reduce规约,将stream中的多个元素规约为一个元素,通过Optional接口来接收结果
上述的输出结果如下:
|
|
并行Stream
多个线程并行计算。
|
|
实际上,并行计算不一定会快于串行运算,影响的因素很多:
- 数据大小输入数据的大小会影响并行化处理对性能的提升。将问题分解之后并行化处理, 再将结果合并会带来额外的开销。 因此只有数据足够大、 每个数据处理管道花费的时间足够多
时, 并行化处理才有意义。 - 源数据结构,每个管道的操作都基于一些初始数据源,通常是集合。将不同的数据源分割相对容易,这里的开销影响了在管道中并行处理数据时到底能带来多少性能上的提升。
- 装箱,处理基本类型比处理装箱类型要快。
- 核的数量,极端情况下,只有一个核,因此完全没必要并行化。显然,拥有的核越多,获得潜在性能提升的幅度就越大。在实践中,核的数量不单指你的机器上有多少核,更是指运行时你的机器能使用多少核。这也就是说同时运行的其他进程,或者线程关联性(强制线程在某些核或CPU上运行)会影响性能。
- 单元处理开销,比如数据大小,这是一场并行执行花费时间和分解合并操作开销之间的战争。花在流中每个元素身上的时间越长,并行操作带来的性能提升越明显。
Date API
Java8中包含了一组全新的时间日期API,简单介绍下:
- Clock时钟:访问当前日期和时间的方法,对时区敏感。
- Timezones时区:ZoneID来标志时区。
- LocalTime本地时间:没有时区信息的时间
- LocalDate本地日期
- LocalDateTime:本地日期时间
Annotation注解
- Java8中吃吃了多重注解。
|
|
- Java8中允许一个类型的注解使用多次
使用包装类当容器来存多个注解
|
|
使用多重注解
|
|