Java8发布时间是2014年3月19日,距离今日已经很久了,那么Java8新特性你了解吗?

java8是Java的一次重大升级,巨大的里程碑式的改进!!

Java语言新特性:

1.与传统结合 -- Lambda(闭包)表达式和函数式接口以及注解

注意:要能写成Lambda 其对象类一定支持函数式接口的规范,这个规范是jdk检验的,那么什么是函数式接口的规范,原理是什么???

叙说背景和原理:

随着回调模式和函数式编程风格的日益流行,我们需要在Java中提供一种尽可能轻量级的将代码封装为数据(Model code as data)的方法。匿名内部类并不是一个好的选择,因为:

  1. 语法过于冗余
  2. 匿名类中的this和变量名容易使人产生误解
  3. 类型载入和实例创建语义不够灵活
  4. 无法捕获非final的局部变量
  5. 无法对控制流进行抽象

上面的多数问题均在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注解来显式指定一个接口是函数式接口(以避免无意声明了一个符合函数式标准的接口),加上这个注解之后,编译器就会验证该接口是否满足函数式接口的要求。

实现函数式类型的另一种方式是引入一个全新的结构化函数类型,我们也称其为“箭头”类型。例如,一个接收StringObject并返回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() − 为集合创建并行流。

List<String>strings =Arrays.asList("abc","","bc","efg","abcd","","jkl");List<String>filtered =strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());

forEach

Stream 提供了新的方法 'forEach' 来迭代流中的每个数据。以下代码片段使用 forEach 输出了10个随机数:

Randomrandom =newRandom();random.ints().limit(10).forEach(System.out::println);

map

map 方法用于映射每个元素到对应的结果,以下代码片段使用 map 输出了元素对应的平方数:

List<Integer>numbers =Arrays.asList(3,2,2,3,7,3,5);// 获取对应的平方数List<Integer>squaresList =numbers.stream().map(i ->i*i).distinct().collect(Collectors.toList());

filter

filter 方法用于通过设置的条件过滤出元素。以下代码片段使用 filter 方法过滤出空字符串:

List<String>strings = Arrays.asList("abc","","bc","efg","abcd","","jkl");// 获取空字符串的数量intcount =strings.stream().filter(string -> string.isEmpty()).count();

limit

limit 方法用于获取指定数量的流。 以下代码片段使用 limit 方法打印出 10 条数据:

Randomrandom =newRandom();random.ints().limit(10).forEach(System.out::println);

sorted

sorted 方法用于对流进行排序。以下代码片段使用 sorted 方法对输出的 10 个随机数进行排序:

Randomrandom =newRandom();random.ints().limit(10).sorted().forEach(System.out::println);

并行(parallel)程序

parallelStream 是流并行处理程序的代替方法。以下实例我们使用 parallelStream 来输出空字符串的数量:

List<String>strings =Arrays.asList("abc","","bc","efg","abcd","","jkl");// 获取空字符串的数量intcount =strings.parallelStream().filter(string -> string.isEmpty()).count();

我们可以很容易的在顺序运行和并行直接切换。


Collectors

Collectors 类实现了很多归约操作,例如将流转换成集合和聚合元素。Collectors 可用于返回列表或字符串:

List<String>strings = Arrays.asList("abc","","bc","efg","abcd","","jkl");List<String>filtered =strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());System.out.println("筛选列表:" +filtered);StringmergedString =strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.joining(","));System.out.println("合并字符串:" +mergedString);

统计

另外,一些产生统计结果的收集器也非常有用。它们主要用于int、double、long等基本类型上,它们可以用来产生类似如下的统计结果。

List<Integer>numbers =Arrays.asList(3,2,2,3,7,3,5);IntSummaryStatisticsstats =integers.stream().mapToInt((x) -> x).summaryStatistics();System.out.println("列表中最大的数 : " +stats.getMax());System.out.println("列表中最小的数 : " +stats.getMin());System.out.println("所有数之和 : " +stats.getSum());System.out.println("平均数 : " +stats.getAverage());

java8新特性简述相关推荐

  1. 【小家java】java8新特性之---全新的日期、时间API(JSR 310规范),附SpringMVC、Mybatis中使用JSR310的正确姿势

    [小家java]java5新特性(简述十大新特性) 重要一跃 [小家java]java6新特性(简述十大新特性) 鸡肋升级 [小家java]java7新特性(简述八大新特性) 不温不火 [小家java ...

  2. Java8新特性(一)—————Lambda表达式

    关注微信公众号[行走在代码行的寻路人]获取Java学习视频及资料. 简述Java8中的新特性: 1.速度快:两个对象比较,采用红黑树替换了链表,使其速度变快新增的速度比较与链表较慢 2.新增Lambd ...

  3. 【小家java】java8新特性之---Optional的使用,避免空指针,代替三目运算符

    相关阅读 [小家java]java5新特性(简述十大新特性) 重要一跃 [小家java]java6新特性(简述十大新特性) 鸡肋升级 [小家java]java7新特性(简述八大新特性) 不温不火 [小 ...

  4. 【Java8新特性】关于Java8的Stream API,看这一篇就够了!!

    写在前面 Java8中有两大最为重要的改变.第一个是 Lambda 表达式:另外一个则是 Stream API(java.util.stream.*)  ,那什么是Stream API呢?Java8中 ...

  5. 【Java8新特性】浅谈方法引用和构造器引用

    写在前面 Java8中一个很牛逼的新特性就是方法引用和构造器引用,为什么说它很牛逼呢?往下看! 方法引用 当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用!这里需要注意的是:实现抽 ...

  6. java8新特性_Java8新特性之Date API|乐字节

    大家好,我是乐字节的小乐,上篇文章讲述了<Java8新特性之Optional>,接下来,小乐将接着讲述Java8新特性之Date API 2019日历 Java8之Date API Jav ...

  7. Java8 新特性之流式数据处理(转)

    转自:https://www.cnblogs.com/shenlanzhizun/p/6027042.html 一. 流式处理简介 在我接触到java8流式处理的时候,我的第一感觉是流式处理让集合操作 ...

  8. java8新特性_乐字节-Java8新特性-接口默认方法

    总概 JAVA8 已经发布很久,而且毫无疑问,java8是自java5(2004年发布)之后的最重要的版本.其中包括语言.编译器.库.工具和JVM等诸多方面的新特性. Java8 新特性列表如下: 接 ...

  9. java8新特性: lambda表达式:直接获得某个list/array/对象里面的字段集合

    java8新特性: lambda表达式:直接获得某个list/array/对象里面的字段集合 比如,我有一张表: entity Category.java service CategoryServic ...

最新文章

  1. 计算机类自主招生推荐信,自主招生推荐信范文-20210709232503.docx-原创力文档
  2. 使用tensorflow查询机器上是否存在可用的gpu设备
  3. Spring框架第一天知识总结
  4. 所以Apache基金会不受美国法律约束?
  5. SLS控制台内嵌操作指南
  6. 11.QT中同一个源文件对应两个不同的ui
  7. 思路与好题记录与小技巧
  8. 『科学计算_理论』矩阵求导
  9. opencv 获取图像最大连通域 c++和python版
  10. 【二、玩转vim(vi)编辑器】三大模式及命令介绍、如何通过配置文件.vimrc配置vim编辑器
  11. python窗体生成器_python 如何生成窗体
  12. 06)JDK1.8 新特性学习 重复注解
  13. 第五篇 应用Java
  14. c语言中阶乘相加怎么表示_c语言求阶乘累加和
  15. 如何比对excel表格两列数据中的相同部分或重复部分
  16. 添加腾讯007防水墙
  17. Hbuilder 嵌套外部链接
  18. UE4 PBR材质使用记录
  19. nape.geom.MarchingSquares
  20. [分享] 《步步为营封 Win7》--skyfree

热门文章

  1. SecureCRT连接CentOS阿里云,小键盘在VIM情况下,无法输入数字反而出现英文
  2. linux 命令终端显示-bash-4.2#解决方法
  3. python错误处理
  4. 复合机 涂布机_涂布复合机适用的范围在那些地方?
  5. Linux中自动删除n天前日志
  6. 5.2 Redis商业版
  7. LVS nat 负载均衡实验
  8. 将RGB转换成ToWin32值
  9. Jquery ajax 学习笔记
  10. 把老赵的页面缓存片断改一下,呵呵