jdk8新特性终极指南Word格式.docx
- 文档编号:21869045
- 上传时间:2023-02-01
- 格式:DOCX
- 页数:30
- 大小:74.49KB
jdk8新特性终极指南Word格式.docx
《jdk8新特性终极指南Word格式.docx》由会员分享,可在线阅读,更多相关《jdk8新特性终极指南Word格式.docx(30页珍藏版)》请在冰豆网上搜索。
符号与函数体三部分表示。
例如:
1
Arrays.asList("
a"
"
b"
d"
).forEach(e->
System.out.println(e));
请注意参数e的类型是由编译器推测出来的。
同时,你也可以通过把参数类型与参数包括在括号中的形式直接给出参数的类型:
).forEach((Stringe)->
在某些情况下lambda的函数体会更加复杂,这时可以把函数体放到在一对花括号中,就像在Java中定义普通函数一样。
2
3
4
{
System.out.print(e);
});
Lambda可以引用类的成员变量与局部变量(如果这些变量不是final的话,它们会被隐含的转为final,这样效率更高)。
例如,下面两个代码片段是等价的:
Stringseparator="
"
;
).forEach(
(Stringe)->
System.out.print(e+separator));
和:
finalStringseparator="
Lambda可能会返回一个值。
返回值的类型也是由编译器推测出来的。
如果lambda的函数体只有一行的话,那么没有必要显式使用return语句。
下面两个代码片段是等价的:
).sort((e1,e2)->
pareTo(e2));
intresult=pareTo(e2);
returnresult;
语言设计者投入了大量精力来思考如何使现有的函数友好地支持lambda。
最终采取的方法是:
增加函数式接口的概念。
函数式接口就是一个具有一个方法的普通接口。
像这样的接口,可以被隐式转换为lambda表达式。
java.lang.Runnable与java.util.concurrent.Callable是函数式接口最典型的两个例子。
在实际使用过程中,函数式接口是容易出错的:
如有某个人在接口定义中增加了另一个方法,这时,这个接口就不再是函数式的了,并且编译过程也会失败。
为了克服函数式接口的这种脆弱性并且能够明确声明接口作为函数式接口的意图,Java8增加了一种特殊的注解@FunctionalInterface(Java8中所有类库的已有接口都添加了@FunctionalInterface注解)。
让我们看一下这种函数式接口的定义:
@FunctionalInterface
publicinterfaceFunctional{
voidmethod();
}
需要记住的一件事是:
默认方法与静态方法并不影响函数式接口的契约,可以任意使用:
5
6
7
publicinterfaceFunctionalDefaultMethods{
defaultvoiddefaultMethod(){
}
Lambda是Java8最大的卖点。
它具有吸引越来越多程序员到Java平台上的潜力,并且能够在纯Java语言环境中提供一种优雅的方式来支持函数式编程。
更多详情可以参考官方文档。
2.2接口的默认方法与静态方法
Java8用默认方法与静态方法这两个新概念来扩展接口的声明。
默认方法使接口有点像Traits(Scala中特征(trait)类似于Java中的Interface,但它可以包含实现代码,也就是目前Java8新增的功能),但与传统的接口又有些不一样,它允许在已有的接口中添加新方法,而同时又保持了与旧版本代码的兼容性。
默认方法与抽象方法不同之处在于抽象方法必须要求实现,但是默认方法则没有这个要求。
相反,每个接口都必须提供一个所谓的默认实现,这样所有的接口实现者将会默认继承它(如果有必要的话,可以覆盖这个默认实现)。
让我们看看下面的例子:
8
9
10
11
12
13
14
15
16
17
privateinterfaceDefaulable{
//Interfacesnowallowdefaultmethods,theimplementermayor
//maynotimplement(override)them.
defaultStringnotRequired(){
return"
Defaultimplementation"
privatestaticclassDefaultableImplimplementsDefaulable{
privatestaticclassOverridableImplimplementsDefaulable{
@Override
publicStringnotRequired(){
Overriddenimplementation"
Defaulable接口用关键字default声明了一个默认方法notRequired(),Defaulable接口的实现者之一DefaultableImpl实现了这个接口,并且让默认方法保持原样。
Defaulable接口的另一个实现者OverridableImpl用自己的方法覆盖了默认方法。
Java8带来的另一个有趣的特性是接口可以声明(并且可以提供实现)静态方法。
privateinterfaceDefaulableFactory{
//Interfacesnowallowstaticmethods
staticDefaulablecreate(Supplier<
Defaulable>
supplier){
returnsupplier.get();
下面的一小段代码片段把上面的默认方法与静态方法黏合到一起。
publicstaticvoidmain(String[]args){
Defaulabledefaulable=DefaulableFactory.create(DefaultableImpl:
:
new);
System.out.println(defaulable.notRequired());
defaulable=DefaulableFactory.create(OverridableImpl:
这个程序的控制台输出如下:
Defaultimplementation
Overriddenimplementation
在JVM中,默认方法的实现是非常高效的,并且通过字节码指令为方法调用提供了支持。
默认方法允许继续使用现有的Java接口,而同时能够保障正常的编译过程。
这方面好的例子是大量的方法被添加到java.util.Collection接口中去:
stream(),parallelStream(),forEach(),removeIf(),……
尽管默认方法非常强大,但是在使用默认方法时我们需要小心注意一个地方:
在声明一个默认方法前,请仔细思考是不是真的有必要使用默认方法,因为默认方法会带给程序歧义,并且在复杂的继承体系中容易产生编译错误。
更多详情请参考官方文档
2.3方法引用
方法引用提供了非常有用的语法,可以直接引用已有Java类或对象(实例)的方法或构造器。
与lambda联合使用,方法引用可以使语言的构造更紧凑简洁,减少冗余代码。
下面,我们以定义了4个方法的Car这个类作为例子,区分Java中支持的4种不同的方法引用。
publicstaticclassCar{
publicstaticCarcreate(finalSupplier<
Car>
publicstaticvoidcollide(finalCarcar){
System.out.println("
Collided"
+car.toString());
publicvoidfollow(finalCaranother){
Followingthe"
+another.toString());
publicvoidrepair(){
Repaired"
+this.toString());
第一种方法引用是构造器引用,它的语法是Class:
new,或者更一般的Class<
T>
new。
请注意构造器没有参数。
finalCarcar=Car.create(Car:
finalList<
cars=Arrays.asList(car);
第二种方法引用是静态方法引用,它的语法是Class:
static_method。
请注意这个方法接受一个Car类型的参数。
cars.forEach(Car:
collide);
第三种方法引用是特定类的任意对象的方法引用,它的语法是Class:
method。
请注意,这个方法没有参数。
repair);
最后,第四种方法引用是特定对象的方法引用,它的语法是instance:
请注意,这个方法接受一个Car类型的参数
finalCarpolice=Car.create(Car:
cars.forEach(police:
follow);
运行上面的Java程序在控制台上会有下面的输出(Car的实例可能不一样):
Collidedcom.javacodegeeks.java8.method.references.MethodReferences$Car@7a81197d
Repairedcom.javacodegeeks.java8.method.references.MethodReferences$Car@7a81197d
Followingthecom.javacodegeeks.java8.method.references.MethodReferences$Car@7a81197d
关于方法引用的更多详情请参考官方文档。
2.4重复注解
自从Java5引入了注解机制,这一特性就变得非常流行并且广为使用。
然而,使用注解的一个限制是相同的注解在同一位置只能声明一次,不能声明多次。
Java8打破了这条规则,引入了重复注解机制,这样相同的注解可以在同一地方声明多次。
重复注解机制本身必须用@Repeatable注解。
事实上,这并不是语言层面上的改变,更多的是编译器的技巧,底层的原理保持不变。
让我们看一个快速入门的例子:
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
packagecom.javacodegeeks.java8.repeatable.annotations;
importjava.lang.annotation.ElementType;
importjava.lang.annotation.Repeatable;
importjava.lang.annotation.Retention;
importjava.lang.annotation.RetentionPolicy;
importjava.lang.annotation.Target;
publicclassRepeatingAnnotations{
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public@interfaceFilters{
Filter[]value();
@Repeatable(Filters.class)
public@interfaceFilter{
Stringvalue();
};
@Filter("
filter1"
)
filter2"
publicinterfaceFilterable{
publicstaticvoidmain(String[]args){
for(Filterfilter:
Filterable.class.getAnnotationsByType(Filter.class)){
System.out.println(filter.value());
正如我们看到的,这里有个使用@Repeatable(Filters.class)注解的注解类Filter,Filters仅仅是Filter注解的数组,但Java编译器并不想让程序员意识到Filters的存在。
这样,接口Filterable就拥有了两次Filter(并没有提到Filter)注解。
同时,反射相关的API提供了新的函数getAnnotationsByType()来返回重复注解的类型(请注意Filterable.class.getAnnotation(Filters.class)经编译器处理后将会返回Filters的实例)。
程序输出结果如下:
filter1
filter2
2.5更好的类型推测机制
Java8在类型推测方面有了很大的提高。
在很多情况下,编译器可以推测出确定的参数类型,这样就能使代码更整洁。
让我们看一个例子:
packagecom.javacodegeeks.java8.type.inference;
publicclassValue<
publicstatic<
TdefaultValue(){
returnnull;
publicTgetOrDefault(Tvalue,TdefaultValue){
return(value!
=null)?
value:
defaultValue;
这里是Value<
String>
类型的用法。
publicclassTypeInference{
finalValue<
value=newValue<
>
();
value.getOrDefault("
22"
Value.defaultValue());
Value.defaultValue()的参数类型可以被推测出,所以就不必明确给出。
在Java7中,相同的例子将不会通过编译,正确的书写方式是Value.<
defaultValue()。
2.6扩展注解的支持
Java8扩展了注解的上下文。
现在几乎可以为任何东西添加注解:
局部变量、泛型类、父类与接口的实现,就连方法的异常也能添加注解。
下面演示几个例子:
packagecom.javacodegeeks.java8.annotations;
importjava.util.ArrayList;
importjava.util.Collection;
publicclassAnnotations{
@Target({ElementType.TYPE_USE,ElementType.TYPE_PARAMETER})
public@interfaceNonEmpty{
publicstaticclassHolder<
@NonEmptyT>
extends@NonEmptyObject{
publicvoidmethod()throws@NonEmptyException{
@SuppressWarnings("
unused"
finalHolder<
holder=new@NonEmptyHolder<
@NonEmptyCollection<
@NonEmptyString>
strings=newArrayList<
ElementType.TYPE_USE和ElementType.TYPE_PARAMETER是两个新添加的用于描述适当的注解上下文的元素类型。
在Java语言中,注解处理API也有小的改动来识别新增的类型注解。
3.Java编译器的新特性
3.1参数名字
很长一段时间里,Java程序员一直在发明不同的方式使得方法参数的名字能保留在Java字节码中,并且能够在运行时获取它们(比如,Paranamer类库)。
最终,在Java8中把这个强烈要求的功能添加到语言层面(通过反射API与Par
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- jdk8 特性 终极 指南