Java 8 新特性概述.docx
- 文档编号:29732157
- 上传时间:2023-07-26
- 格式:DOCX
- 页数:17
- 大小:204.56KB
Java 8 新特性概述.docx
《Java 8 新特性概述.docx》由会员分享,可在线阅读,更多相关《Java 8 新特性概述.docx(17页珍藏版)》请在冰豆网上搜索。
Java8新特性概述
Java8新特性概述
函数式接口
Java8引入的一个核心概念是函数式接口(FunctionalInterfaces)。
通过在接口里面添加一个抽象方法,这些方法可以直接从接口中运行。
如果一个接口定义个唯一一个抽象方法,那么这个接口就成为函数式接口。
同时,引入了一个新的注解:
@FunctionalInterface。
可以把他它放在一个接口前,表示这个接口是一个函数式接口。
这个注解是非必须的,只要接口只包含一个方法的接口,虚拟机会自动判断,不过最好在接口上使用注解@FunctionalInterface进行声明。
在接口中添加了@FunctionalInterface的接口,只允许有一个抽象方法,否则编译器也会报错。
java.lang.Runnable就是一个函数式接口。
[java]viewplaincopyprint?
在CODE上查看代码片派生到我的代码片
@FunctionalInterface
publicinterfaceRunnable{
publicabstractvoidrun();
}
Lambda表达式
函数式接口的重要属性是:
我们能够使用Lambda实例化它们,Lambda表达式让你能够将函数作为方法参数,或者将代码作为数据对待。
Lambda表达式的引入给开发者带来了不少优点:
在Java8之前,匿名内部类,监听器和事件处理器的使用都显得很冗长,代码可读性很差,Lambda表达式的应用则使代码变得更加紧凑,可读性增强;Lambda表达式使并行操作大集合变得很方便,可以充分发挥多核CPU的优势,更易于为多核处理器编写代码;
Lambda表达式由三个部分组成:
第一部分为一个括号内用逗号分隔的形式参数,参数是函数式接口里面方法的参数;第二部分为一个箭头符号:
->;第三部分为方法体,可以是表达式和代码块。
语法如下:
1.方法体为表达式,该表达式的值作为返回值返回。
(parameters)->expression
2.方法体为代码块,必须用{}来包裹起来,且需要一个return返回值,但若函数式接口里面方法返回值是void,则无需返回值。
(parameters)->{statements;}//例如,下面是使用匿名内部类和Lambda表达式的代码比较。
下面是用匿名内部类的代码:
[java]viewplaincopyprint?
在CODE上查看代码片派生到我的代码片
button.addActionListener(newActionListener(){
pre">@Override pre">publicvoidactionPerformed(ActionEvente){ pre">System.out.print("HellloLambdainactionPerformed"); pre">} }); 下面是使用Lambda表达式后: button.addActionListener( pre">//actionPerformed有一个参数e传入,所以用(ActionEvente) pre">(ActionEvente)-> pre">System.out.print("HellloLambdainactionPerformed") ); 上面是方法体包含了参数传入(ActionEvente),如果没有参数则只需(),例如Thread中的run方法就没有参数传入,当它使用Lambda表达式后: [java]viewplaincopyprint? 在CODE上查看代码片派生到我的代码片 Threadt=newThread( pre">//run没有参数传入,所以用(),后面用{}包起方法体 pre">()->{ pre">System.out.println("Hellofromathreadinrun"); pre">} ); /*通过上面两个代码的比较可以发现使用Lambda表达式可以简化代码,并提高代码的可读性。 为了进一步简化Lambda表达式,可以使用方法引用。 例如,下面三种分别是使用内部类,使用Lambda表示式和使用方法引用方式的比较: */ //1.使用内部类 Function pre">@Override pre">publicStringapply(Integert){ pre">returnnull; pre">} }; //2.使用Lambda表达式 Function //3.使用方法引用的方式 Function : valueOf; 要使用Lambda表达式,需要定义一个函数式接口,这样往往会让程序充斥着过量的仅为Lambda表达式服务的函数式接口。 为了减少这样过量的函数式接口,Java8在java.util.function中增加了不少新的函数式通用接口。 例如: Function 将T作为输入,返回R作为输出,他还包含了和其他函数组合的默认方法。 Predicate 将T作为输入,返回一个布尔值作为输出,该接口包含多种默认方法来将Predicate组合成其他复杂的逻辑(与、或、非)。 Consumer 将T作为输入,不返回任何内容,表示在单个参数上的操作。 [java]viewplaincopyprint? 在CODE上查看代码片派生到我的代码片 //例如,People类中有一个方法getMaleList需要获取男性的列表,这里需要定义一个函数式接口PersonInterface: interfacePersonInterface{ pre">publicbooleantest(Personperson); } publicclassPeople{ pre">privateList pre">publicList pre">List pre">persons.forEach( pre">(Personperson)-> pre">{ pre">if(filter.test(person)){//调用PersonInterface的方法 pre">res.add(person); pre">} pre">} ); returnres; } } //为了去除PersonInterface这个函数式接口,可以用通用函数式接口Predicate替代如下: classPeople{ pre">privateList pre">publicList pre">List pre">persons.forEach( pre">person->{ pre">if(predicate.test(person)){//调用Predicate的抽象方法test pre">res.add(person); pre">} }); returnres; } } 接口的增强 Java8对接口做了进一步的增强。 在接口中可以添加使用default关键字修饰的非抽象方法。 还可以在接口中定义静态方法。 如今,接口看上去与抽象类的功能越来越类似了。 默认方法 Java8还允许我们给接口添加一个非抽象的方法实现,只需要使用default关键字即可,这个特征又叫做扩展方法。 在实现该接口时,该默认扩展方法在子类上可以直接使用,它的使用方式类似于抽象类中非抽象成员方法。 但扩展方法不能够重载Object中的方法。 例如: toString、equals、hashCode不能在接口中被重载。 例如,下面接口中定义了一个默认方法count(),该方法可以在子类中直接使用。 [java]viewplaincopyprint? 在CODE上查看代码片派生到我的代码片 publicinterfaceDefaultFunInterface{ pre">//定义默认方法count pre">defaultintcount(){ pre">return1; pre">} } publicclassSubDefaultFunClassimplementsDefaultFunInterface{ pre">publicstaticvoidmain(String[]args){ pre">//实例化一个子类对象,改子类对象可以直接调用父接口中的默认方法count pre">SubDefaultFunClasssub=newSubDefaultFunClass(); pre">sub.count(); pre">} } 静态方法 在接口中,还允许定义静态的方法。 接口中的静态方法可以直接用接口来调用。 例如,下面接口中定义了一个静态方法find,该方法可以直接用StaticFunInterface.find()来调用。 [java]viewplaincopyprint? 在CODE上查看代码片派生到我的代码片 publicinterfaceStaticFunInterface{ pre">publicstaticintfind(){ pre">return1; pre">} } publicclassTestStaticFun{ pre">publicstaticvoidmain(String[]args){ pre">//接口中定义了静态方法find直接被调用 pre">StaticFunInterface.fine(); pre">} } 集合之流式操作 Java8引入了流式操作(Stream),通过该操作可以实现对集合(Collection)的并行处理和函数式操作。 根据操作返回的结果不同,流式操作分为中间操作和最终操作两种。 最终操作返回一特定类型的结果,而中间操作返回流本身,这样就可以将多个操作依次串联起来。 根据流的并发性,流又可以分为串行和并行两种。 流式操作实现了集合的过滤、排序、映射等功能。 Stream和Collection集合的区别: Collection是一种静态的内存数据结构,而Stream是有关计算的。 前者是主要面向内存,存储在内存中,后者主要是面向CPU,通过CPU实现计算。 串行和并行的流 流有串行和并行两种,串行流上的操作是在一个线程中依次完成,而并行流则是在多个线程上同时执行。 并行与串行的流可以相互切换: 通过stream.sequential()返回串行的流,通过stream.parallel()返回并行的流。 相比较串行的流,并行的流可以很大程度上提高程序的执行效率。 下面是分别用串行和并行的方式对集合进行排序。 串行排序: [java]viewplaincopyprint? 在CODE上查看代码片派生到我的代码片 List for(inti=0;i<1000000;i++){ pre">doubled=Math.random()*1000; pre">list.add(d+""); } longstart=System.nanoTime();//获取系统开始排序的时间点 intcount=(int)((Stream)list.stream().sequential()).sorted().count(); longend=System.nanoTime();//获取系统结束排序的时间点 longms=TimeUnit.NANOSECONDS.toMillis(end-start);//得到串行排序所用的时间 System.out.println(ms+”ms”); 并行排序: [java]viewplaincopyprint? 在CODE上查看代码片派生到我的代码片 List for(inti=0;i<1000000;i++){ pre">doubled=Math.random()*1000; pre">list.add(d+""); } longstart=System.nanoTime();//获取系统开始排序的时间点 intcount=(int)((Stream)list.stream().parallel()).sorted().count(); longend=System.nanoTime();//获取系统结束排序的时间点 longms=TimeUnit.NANOSECONDS.toMillis(end-start);//得到并行排序所用的时间 System.out.println(ms+”ms”); 串行输出为1200ms,并行输出为800ms。 可见,并行排序的时间相比较串行排序时间要少不少。 中间操作 该操作会保持stream处于中间状态,允许做进一步的操作。 它返回的还是的Stream,允许更多的链式操作。 常见的中间操作有: filter(): 对元素进行过滤; sorted(): 对元素排序; map(): 元素的映射; distinct(): 去除重复元素; subStream(): 获取子Stream等。 例如,下面是对一个字符串集合进行过滤,返回以“s”开头的字符串集合,并将该集合依次打印出来: [java]viewplaincopyprint? 在CODE上查看代码片派生到我的代码片 list.stream().filter((s)->s.startsWith("s")).forEach(System.out: : println); 这里的filter(...)就是一个中间操作,该中间操作可以链式地应用其他Stream操作。 终止操作 该操作必须是流的最后一个操作,一旦被调用,Stream就到了一个终止状态,而且不能再使用了。 常见的终止操作有: forEach(): 对每个元素做处理; toArray(): 把元素导出到数组; findFirst(): 返回第一个匹配的元素; anyMatch(): 是否有匹配的元素等。 例如,下面是对一个字符串集合进行过滤,返回以“s”开头的字符串集合,并将该集合依次打印出来: [java]viewplaincopyprint? 在CODE上查看代码片派生到我的代码片 list.stream()//获取列表的stream操作对象 .filter((s)->s.startsWith("s"))//对这个流做过滤操作 .forEach(System.out: : println); 这里的forEach(...)就是一个终止操作,该操作之后不能再链式的添加其他操作了。 注解的更新 对于注解,Java8主要有两点改进: 类型注解和重复注解。 Java8的类型注解扩展了注解使用的范围。 在该版本之前,注解只能是在声明的地方使用。 现在几乎可以为任何东西添加注解: 局部变量、类与接口,就连方法的异常也能添加注解。 新增的两个注释的程序元素类型ElementType.TYPE_USE和ElementType.TYPE_PARAMETER用来描述注解的新场合。 ElementType.TYPE_PARAMETER表示该注解能写在类型变量的声明语句中。 而ElementType.TYPE_USE表示该注解能写在使用类型的任何语句中(例如声明语句、泛型和强制转换语句中的类型)。 对类型注解的支持,增强了通过静态分析工具发现错误的能力。 原先只能在运行时发现的问题可以提前在编译的时候被排查出来。 Java8本身虽然没有自带类型检测的框架,但可以通过使用CheckerFramework这样的第三方工具,自动检查和确认软件的缺陷,提高生产效率。 例如,下面的代码可以通过编译,但是运行时会报NullPointerException的异常。 [java]viewplaincopyprint? 在CODE上查看代码片派生到我的代码片 publicclassTestAnno{ pre">publicstaticvoidmain(String[]args){ pre">Objectobj=null; pre">obj.toString(); pre">} } 为了能在编译期间就自动检查出这类异常,可以通过类型注解结合CheckerFramework提前排查出来: [java]viewplaincopyprint? 在CODE上查看代码片派生到我的代码片 importorg.checkerframework.checker.nullness.qual.NonNull; publicclassTestAnno{ pre">publicstaticvoidmain(String[]args){ pre">@NonNullObjectobj=null; pre">obj.toString();
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Java 新特性概述 特性 概述