JAVA8 十大新特性详解
- 格式:doc
- 大小:177.00 KB
- 文档页数:19
JAVA8 十大新特性详解本教程将Jav a8的新特新逐一列出,并将使用简单的代码示例来指导你如何使用默认接口方法,lambda表达式,方法引用以及多重A nnot ation,之后你将会学到最新的A PI上的改进,比如流,函数式接口,Map以及全新的日期A PI“Jav aisstillnotdead—and peopleare startin g to figurethatout.”本教程将用带注释的简单代码来描述新特性,你将看不到大片吓人的文字。
一、接口的默认方法Java 8允许我们给接口添加一个非抽象的方法实现,只需要使用 default关键字即可,这个特征又叫做扩展方法,示例如下:复制代码代码如下:interfa ce F ormula {doublecalcula te(int a);default doublesqrt(int a) {returnMath.sqrt(a);}}F ormula接口在拥有c alcula te方法之外同时还定义了sqrt方法,实现了F orm ula接口的子类只需要实现一个cal culate方法,默认方法sqr t将在子类上可以直接使用。
复制代码代码如下:F ormula formula = new F ormula() {@O v errid epublicdoublecalcula te(int a) {returnsqrt(a * 100);}};formula.calcula te(100); // 100.0formula.sqrt(16); // 4.0文中的form ula被实现为一个匿名类的实例,该代码非常容易理解,6行代码实现了计算sqrt(a * 100)。
在下一节中,我们将会看到实现单方法接口的更简单的做法。
JAVA8 十大新特性详解本教程将Java8的新特新逐一列出,并将使用简单的代码示例来指导你如何使用默认接口方法,lambda表达式,方法引用以及多重Annotation,之后你将会学到最新的API上的改进,比如流,函数式接口,Map以及全新的日期API“Java is still not dead—and people are starting to figure that out.”本教程将用带注释的简单代码来描述新特性,你将看不到大片吓人的文字。
一、接口的默认方法Java 8允许我们给接口添加一个非抽象的方法实现,只需要使用default关键字即可,这个特征又叫做扩展方法,示例如下:复制代码代码如下:interface Formula {double calculate(int a);default double sqrt(int a) {return Math.sqrt(a);}}Formula接口在拥有calculate方法之外同时还定义了sqrt方法,实现了Formula接口的子类只需要实现一个calculate方法,默认方法sqrt将在子类上可以直接使用。
复制代码代码如下:Formula formula = new Formula() {@Overridepublic double calculate(int a) {return sqrt(a * 100);}};formula.calculate(100); // 100.0formula.sqrt(16); // 4.0文中的formula被实现为一个匿名类的实例,该代码非常容易理解,6行代码实现了计算sqrt(a * 100)。
在下一节中,我们将会看到实现单方法接口的更简单的做法。
译者注:在Java中只有单继承,如果要让一个类赋予新的特性,通常是使用接口来实现,在C++中支持多继承,允许一个子类同时具有多个父类的接口与功能,在其他语言中,让一个类同时具有其他的可复用代码的方法叫做mixin。
JAVA8十大新特性详解本教程将Java8的新特新逐一列出,并将使用简单的代码示例来指导你如何使用默认接口方法,lambda表达式,方法引用以及多重Annotation,之后你将会学到最新的API上的改进,比如流,函数式接口,Map以及全新的日期APIFormula接口在拥有calculate方法之外同时还定义了sqrt方法,实现了Formula接口的子类只需要实现一个calculate方法,默认方法sqrt将在子类上可以直接使用。
文中的formula被实现为一个匿名类的实例,该代码非常容易理解,6行代码实现了计算sqrt(a*100)。
在下一节中,我们将会看到实现单方法接口的更简单的做法。
public int compare(String a,String b){return pareTo(a);}});只需要给静态方法Collections.sort传入一个List对象以及一个比较器来按指定顺序排列。
通常做法都是创建一个匿名的比较器对象然后将其传递给sort方法。
看到了吧,代码变得更段且更具有可读性,但是实际上还可以写得更短:对于函数体只有一行代码的,你可以去掉大括号{}以及return关键字,但是你还可以写得更短点:Java编译器可以自动推导出参数类型,所以你可以不用再写一次类型。
接下来我们看看lambda表达式还能作出什么更方便的东西来:三、函数式接口Lambda表达式是如何在java的类型系统中表示的呢?每一个lambda表达式都对应一个类型,通常是接口类型。
而“函数式接口”是指仅仅只包含一个抽象方法的接口,每一个该类型的lambda表达式都会被匹配到这个抽象方法。
因为默认方法不算抽象方法,所以你也可以给你的函数式接口添加默认方法。
需要注意如果@FunctionalInterface如果没有指定,上面的代码也是对的。
Java8允许你使用::关键字来传递方法或者构造函数引用,上面的代码展示了如何引用一个静态方法,我们也可以引用一个对象的方法:接下来看看构造函数是如何使用::关键字来引用的,首先我们定义一个包含多个构造函数的简单类:接下来我们指定一个用来创建Person对象的对象工厂接口:这里我们使用构造函数引用来将他们关联起来,而不是实现一个完整的工厂:PersonFactory<Person>personFactory=Person::new;Person person=personFactory.create("Peter","Parker");我们只需要使用Person::new来获取Person类构造函数的引用,Java编译器会自动根据PersonFactory.create方法的签名来选择合适的构造函数。
全⽹最通透的Java8版本特性讲解「MoreThanJava」宣扬的是「学习,不⽌ CODE」,本系列 Java 基础教程是⾃⼰在结合各⽅⾯的知识之后,对 Java 基础的⼀个总回顾,旨在「帮助新朋友快速⾼质量的学习」。
当然不论新⽼朋友我相信您都可以从中获益。
如果觉得「不错」的朋友,欢迎「关注 + 留⾔ + 分享」,⽂末有完整的获取链接,您的⽀持是我前进的最⼤的动⼒!特性总览以下是 Java 8 中的引⼊的部分新特性。
关于 Java 8 新特性更详细的介绍可参考。
接⼝默认⽅法和静态⽅法Lambda 表达式函数式接⼝⽅法引⽤StreamOptionalDate/Time API重复注解扩展注解的⽀持Base64JavaFX其它JDBC 4.2 规范更好的类型推测机制HashMap 性能提升IO/NIO 的改进JavaScript 引擎 Nashorn并发(Concurrency)类依赖分析器 jdepsJVM 的 PermGen 空间被移除⼀. 接⼝默认⽅法和静态⽅法接⼝默认⽅法在 Java 8 中,允许为接⼝⽅法提供⼀个默认的实现。
必须⽤ default 修饰符标记这样⼀个⽅法,例如 JDK 中的 Iterator 接⼝:public interface Iterator<E> {boolean hasNext();E next();default void remove() { throw new UnsupportedOperationExceition("remove"); }}这将⾮常有⽤!如果你要实现⼀个迭代器,就需要提供 hasNext() 和 next() ⽅法。
这些⽅法没有默认实现——它们依赖于你要遍历访问的数据结构。
不过,如果你的迭代器是只读的,那么就不⽤操⼼实现 remove() ⽅法。
默认⽅法也可以调⽤其他⽅法,例如,我们可以改造 Collection 接⼝,定义⼀个⽅便的 isEmpty() ⽅法:public interface Collection {int size(); // an abstract methoddefault boolean isEmpty() { return size() == 0; }}这样,实现 Collection 的程序员就不⽤再操⼼实现 isEmpty() ⽅法了。
Java_新特性(Java8----Java11)第⼆⼗⼆章新特性22.1 Java8的新特性22.1.1 Java8的概述Java8是 Java 语⾔的⼀个重要版本,该版本于2014年3⽉发布,是⾃Java5以来最具⾰命性的版本,这个版本包含语⾔、编译器、库、⼯具和JVM等⽅⾯的⼗多个新特性。
22.1.2 函数式接⼝函数式接⼝主要指只包含⼀个抽象⽅法的接⼝,如:ng.Runnable、parator接⼝等。
Java8提供@FunctionalInterface注解来定义函数式接⼝,若定义的接⼝不符合函数式的规范便会报错。
Java8中增加了java.util.function包,该包包含了常⽤的函数式接⼝,具体如下:22.1.3 Lambda表达式Lambda 表达式是实例化函数式接⼝的重要⽅式,使⽤ Lambda 表达式可以使代码变的更加简洁紧凑。
lambda表达式:参数列表、箭头符号->和⽅法体组成,⽽⽅法体中可以是表达式,也可以是语句块。
语法格式:(参数列表) -> { ⽅法体; } - 其中()、参数类型、{} 以及return关键字可以省略。
22.1.4 ⽅法引⽤⽅法引⽤主要指通过⽅法的名字来指向⼀个⽅法⽽不需要为⽅法引⽤提供⽅法体,该⽅法的调⽤交给函数式接⼝执⾏。
⽅法引⽤使⽤⼀对冒号 :: 将类或对象与⽅法名进⾏连接,通常使⽤⽅式如下:对象的⾮静态⽅法引⽤ ObjectName :: MethodName类的静态⽅法引⽤ ClassName :: StaticMethodName类的⾮静态⽅法引⽤ ClassName :: MethodName构造器的引⽤ ClassName :: new数组的引⽤ TypeName[] :: new⽅法引⽤是在特定场景下lambda表达式的⼀种简化表⽰,可以进⼀步简化代码的编写使代码更加紧凑简洁,从⽽减少冗余代码。
22.1.5 Stream接⼝案例题⽬:准备⼀个List集合并放⼊Person类型的对象,将集合中所有成年⼈过滤出来放到另外⼀个集合并打印出来。
Java版本:JDK8的⼗⼤新特性介绍JDK8常⽤包及概述java.applet 提供了需要创建⼀个⼩程序和⽤来跟其他⼩程序交流上下⽂的类。
Java.awt 包含⽤于创建⽤户界⾯和绘制图形图像的所有类Java.io 提供与输⼊输出相关的类Java.beans 包含与开发javaBeans相关的类ng 提供java语⾔程序设计的基础类 提供实现⽹络操作相关的类Java.nio 为输⼊输出提供缓冲区的类Java.text 提供处理⽂本、⽇期、数字和消息的类和接⼝Java.util 提供处理⽇期、时间、随机数⽣成等各种使⽤⼯具的类 提供⽤于⽹络应⽤程序的类、⽹络应⽤扩展类Java.swing 提供⼀组与AWT功能相同的纯java的组件类java.sql 该包提供了使⽤Java语⾔访问并处理存储在数据源(通常是⼀个关系型数据库)中的数据API。
java.RMI 该包提供远程⽅法调⽤相关APIJDK8新特性:mbda表达式2.新的⽇期API3.引⼊Optional4.使⽤Base645.接⼝的默认⽅法和静态⽅法6.新增⽅法引⽤格式7.新增Stream类8.注解相关的改变9.⽀持并⾏(parallel)数组10.对并发类(Concurrency)的扩展。
⼀、Lambda表达式Lambda 表达式也可称为闭包,是推动Java 8 发布的最重要新特性。
lambda表达式本质上是⼀个匿名⽅法。
Lambda允许把函数作为⼀个⽅法的参数(函数作为参数传递进⽅法中)或者把代码看成数据。
使⽤Lambda 表达式可以使代码变的更加简洁紧凑。
在最简单的形式中,⼀个lambda可以由:⽤逗号分隔的参数列表、–>符号、函数体三部分表⽰,在某些情况下lambda的函数体会更加复杂,这时可以把函数体放到在⼀对花括号中,就像在Java中定义普通函数⼀样。
Lambda可以引⽤类的成员变量与局部变量(如果这些变量不是final的话,它们会被隐含的转为final,这样效率更⾼)。
Java8新特性(拉姆达表达式lambda)⼀、函数式接⼝ 函数式接⼝(functional interface 也叫功能性接⼝,其实是同⼀个东西)。
简单来说,函数式接⼝是只包含⼀个⽅法的接⼝。
⽐如Java 标准库中的ng.Runnable和 parator都是典型的函数式接⼝。
Java 8提供 @FunctionalInterface作为注解,这个注解是⾮必须的,只要接⼝符合函数式接⼝的标准(即只包含⼀个⽅法的接⼝),虚拟机会⾃动判断,但最好在接⼝上使⽤注解@FunctionalInterface进⾏声明,以免团队的其他⼈员错误地往接⼝中添加新的⽅法。
Java中的lambda⽆法单独出现,它需要⼀个函数式接⼝来盛放,lambda表达式⽅法体其实就是函数接⼝的实现. 下⾯的接⼝就是⼀个函数式接⼝1//添加此注解后,接⼝中只能有⼀个⽅法。
2 @FunctionalInterface3public interface A {4void call();5 }⼆、lambda语法 包含三部分: 1、⼀个括号内⽤逗号分隔的形式参数,参数是函数式接⼝⾥⾯⽅法的参数 2、⼀个箭头符号:-> 3、⽅法体,可以是表达式和代码块。
1 (parameters) -> expression 或者 (parameters) -> { statements; } 通过下⾯的代码可以看到lambda表达式设计的代码更简洁,⽽且可读性更好。
1public class Demo1 {2public static void main(String[] args) {3 runThreadByLambda();4 runThreadByInnerClass();5 }67public static void runThreadByLambda() {8/*9 Runnable就是⼀个函数式接⼝:他只有⼀个⽅法run()⽅法。
Java8,java9和java11的特性和区别!Java8,java9和java11的特性总结!Java 8 的主要新特性1. Lambda 表达式Lambda 允许把函数作为⼀个⽅法的参数传递进⽅法中。
作⽤:解决 Java 被诟病的匿名内部类的问题。
2. 接⼝中可增加了默认⽅法作⽤:在接⼝中也可以有实现⽅法了。
3. HashMap 底层数据结构的变化java 8 之前,HashMap 底层的数据结构是数组+链表实现的, Java 8 之后是数组+链表+红⿊树实现的,当链表的长度超过 8 之后,会转换成红⿊树。
作⽤:解决因哈希冲突导致的链表过长,查询效率低的问题。
4. Stream API新添加 Stream API (java.util.stream),把真正函数式编程的风格引⼊ Java。
5. 提供⼀个新的 JavaScript 引擎Java 8 提供了⼀个新的 Nashorn JavaScript 引擎,它允许在 JVM 上运⾏特定的 JavaScript 应⽤。
作⽤:解决⽇益增长的 Java 跟 JS 交互混合的需求。
Java 9 新特性1. 模块系统模块是⼀个包的容器,Java 9 最⼤的变化之⼀是引⼊模块系统。
(Jigsaw 项⽬)作⽤:解决⼤型项⽬模块化开发的需求。
2. ⽀持 HTTP/2 标准HTTP/2 标准是 HTTP 协议的最新版本,新的 HTTPClient API ⽀持 Websocket 和 HTTP2 流以及服务器推送特性。
3. 提供创建不可变集合的静态⼯⼚⽅法List、Set、Map 接⼝中,提供新的静态⼯⼚⽅法直接创建不可变的集合实例。
作⽤:创建不可变集合更⽅便,⼀⾏代码就搞定,节省了开销。
4. 私有接⼝⽅法在接⼝中也允许编写 private 修饰的私有⽅法了。
作⽤:增强了接⼝的功能,提⾼了可扩展性。
5. 轻量级的 JSON API内置了⼀个轻量级的 JSON API。
JAVA8 十大新特性详解本教程将Java8的新特新逐一列出,并将使用简单的代码示例来指导你如何使用默认接口方法,lambda表达式,方法引用以及多重Annotation,之后你将会学到最新的API上的改进,比如流,函数式接口,Map以及全新的日期API“Java is still not dead—and people are starting to figure that out.”本教程将用带注释的简单代码来描述新特性,你将看不到大片吓人的文字。
一、接口的默认方法Java 8允许我们给接口添加一个非抽象的方法实现,只需要使用default关键字即可,这个特征又叫做扩展方法,示例如下:代码如下:interface Formula {double calculate(int a);default double sqrt(int a) {return Math.sqrt(a);}}Formula接口在拥有calculate方法之外同时还定义了sqrt方法,实现了Formula接口的子类只需要实现一个calculate方法,默认方法sqrt将在子类上可以直接使用。
代码如下:Formula formula = new Formula() {@Overridepublic double calculate(int a) {return sqrt(a * 100);}};formula.calculate(100); // 100.0formula.sqrt(16); // 4.0文中的formula被实现为一个匿名类的实例,该代码非常容易理解,6行代码实现了计算sqrt(a * 100)。
在下一节中,我们将会看到实现单方法接口的更简单的做法。
译者注:在Java中只有单继承,如果要让一个类赋予新的特性,通常是使用接口来实现,在C++中支持多继承,允许一个子类同时具有多个父类的接口与功能,在其他语言中,让一个类同时具有其他的可复用代码的方法叫做mixin。
新的Java 8 的这个特新在编译器实现的角度上来说更加接近Scala的trait。
在C#中也有名为扩展方法的概念,允许给已存在的类型扩展方法,和Java 8的这个在语义上有差别。
二、Lambda 表达式首先看看在老版本的Java中是如何排列字符串的:代码如下:List<String> names = Arrays.asList("peter", "anna", "mike", "xenia");Collections.sort(names, new Comparator<String>() {@Overridepublic int compare(String a, String b) {return pareTo(a);}});只需要给静态方法Collections.sort 传入一个List对象以及一个比较器来按指定顺序排列。
通常做法都是创建一个匿名的比较器对象然后将其传递给sort方法。
在Java 8 中你就没必要使用这种传统的匿名对象的方式了,Java 8提供了更简洁的语法,lambda表达式:代码如下:Collections.sort(names, (String a, String b) -> {return pareTo(a);});看到了吧,代码变得更段且更具有可读性,但是实际上还可以写得更短:代码如下:Collections.sort(names, (String a, String b) -> pareTo(a));对于函数体只有一行代码的,你可以去掉大括号{}以及return关键字,但是你还可以写得更短点:复制代码代码如下:Collections.sort(names, (a, b) -> pareTo(a));Java编译器可以自动推导出参数类型,所以你可以不用再写一次类型。
接下来我们看看lambda表达式还能作出什么更方便的东西来:三、函数式接口Lambda表达式是如何在java的类型系统中表示的呢?每一个lambda表达式都对应一个类型,通常是接口类型。
而“函数式接口”是指仅仅只包含一个抽象方法的接口,每一个该类型的lambda表达式都会被匹配到这个抽象方法。
因为默认方法不算抽象方法,所以你也可以给你的函数式接口添加默认方法。
我们可以将lambda表达式当作任意只包含一个抽象方法的接口类型,确保你的接口一定达到这个要求,你只需要给你的接口添加@FunctionalInterface 注解,编译器如果发现你标注了这个注解的接口有多于一个抽象方法的时候会报错的。
示例如下:代码如下:@FunctionalInterfaceinterface Converter<F, T> {T convert(F from);}Converter<String, Integer> converter = (from) -> Integer.valueOf(from);Integer converted = converter.convert("123");System.out.println(converted); // 123需要注意如果@FunctionalInterface如果没有指定,上面的代码也是对的。
译者注将lambda表达式映射到一个单方法的接口上,这种做法在Java 8之前就有别的语言实现,比如Rhino JavaScript解释器,如果一个函数参数接收一个单方法的接口而你传递的是一个function,Rhino 解释器会自动做一个单接口的实例到function的适配器,典型的应用场景有org.w3c.dom.events.EventTarget 的addEventListener 第二个参数EventList ener。
四、方法与构造函数引用前一节中的代码还可以通过静态方法引用来表示:代码如下:Converter<String, Integer> converter = Integer::valueOf;Integer converted = converter.convert("123");System.out.println(converted); // 123Java 8 允许你使用:: 关键字来传递方法或者构造函数引用,上面的代码展示了如何引用一个静态方法,我们也可以引用一个对象的方法:代码如下:converter = something::startsWith;String converted = converter.convert("Java");System.out.println(converted); // "J"接下来看看构造函数是如何使用::关键字来引用的,首先我们定义一个包含多个构造函数的简单类:代码如下:class Person {String firstName;String lastName;Person() {}Person(String firstName, String lastName) {this.firstName = firstName;stName = lastName;}}接下来我们指定一个用来创建Person对象的对象工厂接口:代码如下:interface PersonFactory<P extends Person> {P create(String firstName, String lastName);}这里我们使用构造函数引用来将他们关联起来,而不是实现一个完整的工厂:代码如下:PersonFactory<Person> personFactory = Person::new;Person person = personFactory.create("Peter", "Parker");我们只需要使用Person::new 来获取Person类构造函数的引用,Java编译器会自动根据PersonFactory.create方法的签名来选择合适的构造函数。
五、Lambda 作用域在lambda表达式中访问外层作用域和老版本的匿名对象中的方式很相似。
你可以直接访问标记了final的外层局部变量,或者实例的字段以及静态变量。
六、访问局部变量我们可以直接在lambda表达式中访问外层的局部变量:代码如下:final int num = 1;Converter<Integer, String> stringConverter =(from) -> String.valueOf(from + num);stringConverter.convert(2); // 3但是和匿名对象不同的是,这里的变量num可以不用声明为final,该代码同样正确:代码如下:int num = 1;Converter<Integer, String> stringConverter =(from) -> String.valueOf(from + num);stringConverter.convert(2); // 3不过这里的num必须不可被后面的代码修改(即隐性的具有final的语义),例如下面的就无法编译:代码如下:int num = 1;Converter<Integer, String> stringConverter =(from) -> String.valueOf(from + num);num = 3;在lambda表达式中试图修改num同样是不允许的。
七、访问对象字段与静态变量和本地变量不同的是,lambda内部对于实例的字段以及静态变量是即可读又可写。
该行为和匿名对象是一致的:代码如下:class Lambda4 {static int outerStaticNum;int outerNum;void testScopes() {Converter<Integer, String> stringConverter1 = (from) -> {outerNum = 23;return String.valueOf(from);};Converter<Integer, String> stringConverter2 = (from) -> {outerStaticNum = 72;return String.valueOf(from);};}}八、访问接口的默认方法还记得第一节中的formula例子么,接口Formula定义了一个默认方法sqrt可以直接被formula的实例包括匿名对象访问到,但是在lambda表达式中这个是不行的。