java8新特性简述
Java8发布时间是2014年3月19日,距离今日已经很久了,那么Java8新特性你了解吗?
java8是Java的一次重大升级,巨大的里程碑式的改进!!
Java语言新特性:
1.与传统结合 -- Lambda(闭包)表达式和函数式接口以及注解
注意:要能写成Lambda 其对象类一定支持函数式接口的规范,这个规范是jdk检验的,那么什么是函数式接口的规范,原理是什么???
叙说背景和原理:
随着回调模式和函数式编程风格的日益流行,我们需要在Java中提供一种尽可能轻量级的将代码封装为数据(Model code as data)的方法。匿名内部类并不是一个好的选择,因为:
- 语法过于冗余
- 匿名类中的
this
和变量名容易使人产生误解 - 类型载入和实例创建语义不够灵活
- 无法捕获非
final
的局部变量 - 无法对控制流进行抽象
上面的多数问题均在Java SE 8中得以解决:
- 通过提供更简洁的语法和局部作用域规则,Java SE 8彻底解决了问题1和问题2
- 通过提供更加灵活而且便于优化的表达式语义,Java SE 8绕开了问题3
- 通过允许编译器推断变量的“常量性”(finality),Java SE 8减轻了问题4带来的困扰
不过,Java SE 8的目标并非解决所有上述问题。因此捕获可变变量(问题4)和非局部控制流(问题5)并不在Java SE 8的范畴之内。(尽管我们可能会在未来提供对这些特性的支持)
尽管匿名内部类有着种种限制和问题,但是它有一个良好的特性,它和Java类型系统结合的十分紧密:每一个函数对象都对应一个接口类型。之所以说这个特性是良好的,是因为:
- 接口是Java类型系统的一部分
- 接口天然就拥有其运行时表示(Runtime representation)
- 接口可以通过Javadoc注释来表达一些非正式的协定(contract),例如,通过注释说明该操作应可交换(commutative)
上面提到的ActionListener
接口只有一个方法,大多数回调接口都拥有这个特征:比如Runnable
接口和Comparator
接口。我们把这些只拥有一个方法的接口称为函数式接口。(之前它们被称为SAM类型,即单抽象方法类型(Single Abstract Method))
我们并不需要额外的工作来声明一个接口是函数式接口:编译器会根据接口的结构自行判断(判断过程并非简单的对接口方法计数:一个接口可能冗余的定义了一个Object
已经提供的方法,比如toString()
,或者定义了静态方法或默认方法,这些都不属于函数式接口方法的范畴)。不过API作者们可以通过@FunctionalInterface
注解来显式指定一个接口是函数式接口(以避免无意声明了一个符合函数式标准的接口),加上这个注解之后,编译器就会验证该接口是否满足函数式接口的要求。
实现函数式类型的另一种方式是引入一个全新的结构化函数类型,我们也称其为“箭头”类型。例如,一个接收String
和Object
并返回int
的函数类型可以被表示为(String, Object) -> int
。我们仔细考虑了这个方式,但出于下面的原因,最终将其否定:
- 它会为Java类型系统引入额外的复杂度,并带来结构类型(Structural Type)和指名类型(Nominal Type)的混用。(Java几乎全部使用指名类型)
- 它会导致类库风格的分歧——一些类库会继续使用回调接口,而另一些类库会使用结构化函数类型
- 它的语法会变得十分笨拙,尤其在包含受检异常(checked exception)之后
- 每个函数类型很难拥有其运行时表示,这意味着开发者会受到类型擦除(erasure)的困扰和局限。比如说,我们无法对方法
m(T->U)
和m(X->Y)
进行重载(Overload)
java7中支持的函数式接口:
- java.lang.Runnable
- java.util.concurrent.Callable
- java.security.PrivilegedAction
- java.util.Comparator
- java.io.FileFilter
- java.nio.file.PathMatcher
- java.lang.reflect.InvocationHandler
- java.beans.PropertyChangeListener
- java.awt.event.ActionListener
- javax.swing.event.ChangeListener
Java 8中新增加接口:
JDK 1.8 新增加的函数接口:
- java.util.function
java.util.function 它包含了很多类,用来支持 Java的 函数式编程,该包中的函数式接口有:
序号 | 接口 & 描述 |
---|---|
1 |
BiConsumer<T,U>
代表了一个接受两个输入参数的操作,并且不返回任何结果 |
2 |
BiFunction<T,U,R>
代表了一个接受两个输入参数的方法,并且返回一个结果 |
3 |
BinaryOperator<T>
代表了一个作用于于两个同类型操作符的操作,并且返回了操作符同类型的结果 |
4 |
BiPredicate<T,U>
代表了一个两个参数的boolean值方法 |
5 |
BooleanSupplier
代表了boolean值结果的提供方 |
6 |
Consumer<T>
代表了接受一个输入参数并且无返回的操作 |
7 |
DoubleBinaryOperator
代表了作用于两个double值操作符的操作,并且返回了一个double值的结果。 |
8 |
DoubleConsumer
代表一个接受double值参数的操作,并且不返回结果。 |
9 |
DoubleFunction<R>
代表接受一个double值参数的方法,并且返回结果 |
10 |
DoublePredicate
代表一个拥有double值参数的boolean值方法 |
11 |
DoubleSupplier
代表一个double值结构的提供方 |
12 |
DoubleToIntFunction
接受一个double类型输入,返回一个int类型结果。 |
13 |
DoubleToLongFunction
接受一个double类型输入,返回一个long类型结果 |
14 |
DoubleUnaryOperator
接受一个参数同为类型double,返回值类型也为double 。 |
15 |
Function<T,R>
接受一个输入参数,返回一个结果。 |
16 |
IntBinaryOperator
接受两个参数同为类型int,返回值类型也为int 。 |
17 |
IntConsumer
接受一个int类型的输入参数,无返回值 。 |
18 |
IntFunction<R>
接受一个int类型输入参数,返回一个结果 。 |
19 |
IntPredicate
:接受一个int输入参数,返回一个布尔值的结果。 |
20 |
IntSupplier
无参数,返回一个int类型结果。 |
21 |
IntToDoubleFunction
接受一个int类型输入,返回一个double类型结果 。 |
22 |
IntToLongFunction
接受一个int类型输入,返回一个long类型结果。 |
23 |
IntUnaryOperator
接受一个参数同为类型int,返回值类型也为int 。 |
24 |
LongBinaryOperator
接受两个参数同为类型long,返回值类型也为long。 |
25 |
LongConsumer
接受一个long类型的输入参数,无返回值。 |
26 |
LongFunction<R>
接受一个long类型输入参数,返回一个结果。 |
27 |
LongPredicate
R接受一个long输入参数,返回一个布尔值类型结果。 |
28 |
LongSupplier
无参数,返回一个结果long类型的值。 |
29 |
LongToDoubleFunction
接受一个long类型输入,返回一个double类型结果。 |
30 |
LongToIntFunction
接受一个long类型输入,返回一个int类型结果。 |
31 |
LongUnaryOperator
接受一个参数同为类型long,返回值类型也为long。 |
32 |
ObjDoubleConsumer<T>
接受一个object类型和一个double类型的输入参数,无返回值。 |
33 |
ObjIntConsumer<T>
接受一个object类型和一个int类型的输入参数,无返回值。 |
34 |
ObjLongConsumer<T>
接受一个object类型和一个long类型的输入参数,无返回值。 |
35 |
Predicate<T>
接受一个输入参数,返回一个布尔值结果。 |
36 |
Supplier<T>
无参数,返回一个结果。 |
37 |
ToDoubleBiFunction<T,U>
接受两个输入参数,返回一个double类型结果 |
38 |
ToDoubleFunction<T>
接受一个输入参数,返回一个double类型结果 |
39 |
ToIntBiFunction<T,U>
接受两个输入参数,返回一个int类型结果。 |
40 |
ToIntFunction<T>
接受一个输入参数,返回一个int类型结果。 |
41 |
ToLongBiFunction<T,U>
接受两个输入参数,返回一个long类型结果。 |
42 |
ToLongFunction<T>
接受一个输入参数,返回一个long类型结果。 |
43 |
UnaryOperator<T>
接受一个参数为类型T,返回值类型也为T。 |
Lambda表达式例子:
Arrays.asList( "a", "b", "d" ).forEach( e -> System.out.println( e ) );
在上面这个代码中的参数e的类型是由编译器推理得出的,你也可以显式指定该参数的类型,例如:
Arrays.asList( "a", "b", "d" ).forEach( ( String e ) -> System.out.println( e ) );
如果Lambda表达式需要更复杂的语句块,则可以使用花括号将该语句块括起来,类似于Java中的函数体,例如:
Arrays.asList( "a", "b", "d" ).forEach( e -> {System.out.print( e );System.out.print( e );
} );
Lambda表达式可以引用类成员和局部变量(会将这些变量隐式得转换成 final 的),例如下列两个代码块的效果完全相同:
String separator = ",";
Arrays.asList( "a", "b", "d" ).forEach( ( String e ) -> System.out.print( e + separator ) );
和
final String separator = ",";
Arrays.asList( "a", "b", "d" ).forEach( ( String e ) -> System.out.print( e + separator ) );
Lambda表达式有返回值,返回值的类型也由编译器推理得出。如果Lambda表达式中的语句块只有一行,则可以不用使用 return 语句,下列两个代码片段效果相同:
Arrays.asList("a","b","d" ).sort(( e1, e2 ) -> e1.compareTo( e2 ) );和
Arrays.asList("a","b","d" ).sort(( e1, e2 ) -> {
int result = e1.compareTo( e2 );return result;
} );
上述的forEach(),sort() 就是一个Consumer<String>函数式接口,传入String值。
以上是函数式接口的lambda表达,接着看几个依据函数式接口的方法引用:
public class Car {public static Car create(final Supplier<Car > supplier){return supplier.get(); }public static void collide(final Car car){System.out.println("Collided" + car.toString());}public void follow(final Car another){System.out.println("Following the " + another.toString());}public void repair(){System.out.println("Repaired" + this.toString()); } }
构造器引用:它的语法是Class::new,或者更一般的Class< T >::new实例如下:
finalCarcar =Car.create(Car::new);finalList<Car >cars =Arrays.asList(car);静态方法引用:它的语法是Class::static_method,实例如下:
cars.forEach(Car::collide);特定类的任意对象的方法引用:它的语法是Class::method实例如下:
cars.forEach(Car::repair);特定对象的方法引用:它的语法是instance::method实例如下:
finalCarpolice =Car.create(Car::new);cars.forEach(police::follow);
Java思想:
Java8 新增加上述的函数式接口是为了干什么?如果你在未实际开发中使用这些接口,而是在了解这些函数式接口就能体会到,那么你对Java的思想的理解还是挺到位的!
上述函数式接口无非就是传入,提供的操作(返回值不是强制的),注意:因为既然是函数式接口,那么必然是接口实现的过程,只是语法表达上使用函数式罢了。既然接口要么就是回调开始端传入参数或者对象,也就是“传入”。要么就是接口回调执行端执行操作之后返回对象(就是提供对象)或者返回值。
那么是不是有人问:传入值和返回值(对象),直接在函数式表达中声明不就可以了,其实这样也可以,只是iava8多了一层对传入和返回的封装(对应做成了函数式接口),就是上面罗列的函数式接口。
@FunctionInterface 注解声明函数式接口,就是声明一个函数式接口,里面的抽象方法,就是可以使用Lambda表达式;但是注意函数参数类型。
2.接口的默认方法,静态方法
Java8中允许接口存在静态方法,增加了默认方法。默认方法就是可以在接口中有自己的函数体(注意不是虚方法),其他扩展接口,那么直接覆盖默认方法。
3.处理时间、日期的API
4.base64编码
5.nashorn js 引擎
提到nashorn,必须提到jjs(nashorn命令行工具),在cmd中你为什么配置环境变量,就可以输入命令行,编译Java。为什么呢,因为jdk中包含命令行工具,那么Jdk8中,包含了nashorn命令行工具--jjs。
在配置Jdk8环境变量之后,直接在cmd中输入jjs.
执行js脚本:
创建并保存sample.js在 C:> JAVA 文件夹。
sample.js
print('Hello World!');
打开控制台并使用下面的命令。
C:\JAVA>jjs sample.js
看到结果
Hello World!
在Java中调用js:
import javax.script.ScriptEngineManager; import javax.script.ScriptEngine; import javax.script.ScriptException;public class Java8Tester {public static void main(String args[]){ScriptEngineManager scriptEngineManager = new ScriptEngineManager(); ScriptEngine nashorn = scriptEngineManager.getEngineByName("nashorn"); String name = "Mahesh"; Integer result = null;try {nashorn.eval("print('" + name + "')");result = (Integer) nashorn.eval("10 + 2"); }catch(ScriptException e){System.out.println("Error executing script: "+ e.getMessage());}System.out.println(result.toString());} }
6.并发与并行数组
7.util下面的stream接口
Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。
Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。
Stream API可以极大提供Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。
这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。
元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。
+--------------------+ +------+ +------+ +---+ +-------+ | stream of elements +-----> |filter+-> |sorted+-> |map+-> |collect| +--------------------+ +------+ +------+ +---+ +-------+
以上的流程转换为 Java 代码为:
List<Integer> transactionsIds = widgets.stream().filter(b -> b.getColor() == RED).sorted((x,y) -> x.getWeight() - y.getWeight()).mapToInt(Widget::getWeight).sum();
什么是 Stream?
Stream(流)是一个来自数据源的元素队列并支持聚合操作
- <strong元素队列< strong="">元素是特定类型的对象,形成一个队列。 Java中的Stream并不会存储元素,而是按需计算。
- 数据源 流的来源。 可以是集合,数组,I/O channel, 产生器generator 等。
- 聚合操作 类似SQL语句一样的操作, 比如filter, map, reduce, find, match, sorted等。
和以前的Collection操作不同, Stream操作还有两个基础的特征:
- Pipelining: 中间操作都会返回流对象本身。 这样多个操作可以串联成一个管道, 如同流式风格(fluent style)。 这样做可以对操作进行优化, 比如延迟执行(laziness)和短路( short-circuiting)。
- 内部迭代: 以前对集合遍历都是通过Iterator或者For-Each的方式, 显式的在集合外部进行迭代, 这叫做外部迭代。 Stream提供了内部迭代的方式, 通过访问者模式(Visitor)实现。
生成流
在 Java 8 中, 集合接口有两个方法来生成流:
stream() − 为集合创建串行流。
parallelStream() − 为集合创建并行流。
forEach
Stream 提供了新的方法 'forEach' 来迭代流中的每个数据。以下代码片段使用 forEach 输出了10个随机数:
map
map 方法用于映射每个元素到对应的结果,以下代码片段使用 map 输出了元素对应的平方数:
filter
filter 方法用于通过设置的条件过滤出元素。以下代码片段使用 filter 方法过滤出空字符串:
limit
limit 方法用于获取指定数量的流。 以下代码片段使用 limit 方法打印出 10 条数据:
sorted
sorted 方法用于对流进行排序。以下代码片段使用 sorted 方法对输出的 10 个随机数进行排序:
并行(parallel)程序
parallelStream 是流并行处理程序的代替方法。以下实例我们使用 parallelStream 来输出空字符串的数量:
我们可以很容易的在顺序运行和并行直接切换。
Collectors
Collectors 类实现了很多归约操作,例如将流转换成集合和聚合元素。Collectors 可用于返回列表或字符串:
统计
另外,一些产生统计结果的收集器也非常有用。它们主要用于int、double、long等基本类型上,它们可以用来产生类似如下的统计结果。
java8新特性简述相关推荐
- 【小家java】java8新特性之---全新的日期、时间API(JSR 310规范),附SpringMVC、Mybatis中使用JSR310的正确姿势
[小家java]java5新特性(简述十大新特性) 重要一跃 [小家java]java6新特性(简述十大新特性) 鸡肋升级 [小家java]java7新特性(简述八大新特性) 不温不火 [小家java ...
- Java8新特性(一)—————Lambda表达式
关注微信公众号[行走在代码行的寻路人]获取Java学习视频及资料. 简述Java8中的新特性: 1.速度快:两个对象比较,采用红黑树替换了链表,使其速度变快新增的速度比较与链表较慢 2.新增Lambd ...
- 【小家java】java8新特性之---Optional的使用,避免空指针,代替三目运算符
相关阅读 [小家java]java5新特性(简述十大新特性) 重要一跃 [小家java]java6新特性(简述十大新特性) 鸡肋升级 [小家java]java7新特性(简述八大新特性) 不温不火 [小 ...
- 【Java8新特性】关于Java8的Stream API,看这一篇就够了!!
写在前面 Java8中有两大最为重要的改变.第一个是 Lambda 表达式:另外一个则是 Stream API(java.util.stream.*) ,那什么是Stream API呢?Java8中 ...
- 【Java8新特性】浅谈方法引用和构造器引用
写在前面 Java8中一个很牛逼的新特性就是方法引用和构造器引用,为什么说它很牛逼呢?往下看! 方法引用 当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用!这里需要注意的是:实现抽 ...
- java8新特性_Java8新特性之Date API|乐字节
大家好,我是乐字节的小乐,上篇文章讲述了<Java8新特性之Optional>,接下来,小乐将接着讲述Java8新特性之Date API 2019日历 Java8之Date API Jav ...
- Java8 新特性之流式数据处理(转)
转自:https://www.cnblogs.com/shenlanzhizun/p/6027042.html 一. 流式处理简介 在我接触到java8流式处理的时候,我的第一感觉是流式处理让集合操作 ...
- java8新特性_乐字节-Java8新特性-接口默认方法
总概 JAVA8 已经发布很久,而且毫无疑问,java8是自java5(2004年发布)之后的最重要的版本.其中包括语言.编译器.库.工具和JVM等诸多方面的新特性. Java8 新特性列表如下: 接 ...
- java8新特性: lambda表达式:直接获得某个list/array/对象里面的字段集合
java8新特性: lambda表达式:直接获得某个list/array/对象里面的字段集合 比如,我有一张表: entity Category.java service CategoryServic ...
最新文章
- 计算机类自主招生推荐信,自主招生推荐信范文-20210709232503.docx-原创力文档
- 使用tensorflow查询机器上是否存在可用的gpu设备
- Spring框架第一天知识总结
- 所以Apache基金会不受美国法律约束?
- SLS控制台内嵌操作指南
- 11.QT中同一个源文件对应两个不同的ui
- 思路与好题记录与小技巧
- 『科学计算_理论』矩阵求导
- opencv 获取图像最大连通域 c++和python版
- 【二、玩转vim(vi)编辑器】三大模式及命令介绍、如何通过配置文件.vimrc配置vim编辑器
- python窗体生成器_python 如何生成窗体
- 06)JDK1.8 新特性学习 重复注解
- 第五篇 应用Java
- c语言中阶乘相加怎么表示_c语言求阶乘累加和
- 如何比对excel表格两列数据中的相同部分或重复部分
- 添加腾讯007防水墙
- Hbuilder 嵌套外部链接
- UE4 PBR材质使用记录
- nape.geom.MarchingSquares
- [分享] 《步步为营封 Win7》--skyfree