【闲聊杂谈】深入剖析Java8新特性

0、初尝新特性 

在没有接触Java8新特性之前,要新开一个线程,可以这么做:

【闲聊杂谈】深入剖析Java8新特性_第1张图片

Thread类需要一个Runnable接口作为参数,其中的抽象方法run方法是用来指定线程任务内容的核心。为了指定run方法体,不得不需要Runnable的实现类。为了省去定义一个Runnable 的实现类,不得不使用匿名内部类。必须覆盖重写抽象的run方法,所有的方法名称,方法参数,方法返回值不得不都重写一遍,而且不能出错。而实际上,我们只在乎方法体中的代码。为了达到这一目的,Java8提供了Lambda表达式这种操作:

【闲聊杂谈】深入剖析Java8新特性_第2张图片

而实际上,Lambda表达式是一个匿名函数,可以理解为一段可以传递的代码。Lambda表达式的重点是简化了匿名内部类的使用,语法更加简单。匿名内部类语法冗余,体验了Lambda表达式后,发现Lambda表达式是简化匿名内部类的一种方式。 

1、Lambda表达式

基本语法

Lambda表达式省去了面向对象的条条框框,Lambda表达式的标准格式由3个部分组成:

(参数类型 参数名称) -> {
    代码体;
}

格式说明:

  • (参数类型 参数名称):参数列表

  • {代码体;}:方法体

  • ->:箭头,分割参数列表和方法体

完成一个无参无返回值的Lambda表达式【闲聊杂谈】深入剖析Java8新特性_第3张图片【闲聊杂谈】深入剖析Java8新特性_第4张图片

完成一个有参有返回值的Lambda表达式【闲聊杂谈】深入剖析Java8新特性_第5张图片【闲聊杂谈】深入剖析Java8新特性_第6张图片在sort方法的第二个参数是一个Comparator接口的匿名内部类,且执行的方法有参数和返回值,那么就可以改写为Lambda表达式形式。

@FunctionalInterface注解

如果在上例的UserService接口中再定义另外一个抽象方法,那么Lambda表达式就会报错:【闲聊杂谈】深入剖析Java8新特性_第7张图片【闲聊杂谈】深入剖析Java8新特性_第8张图片接口中有两个抽象方法,但是通过Lambda表达式只能去实现其中一个,Lambda表达式就懵逼了,到底要实现哪一个?所以只能有一个抽象方法才可以。

那要怎么保证这个接口中只能有一个抽象方法?使用@FunctionalInterface注解来保证。这是一个标志注解,被该注解修饰的接口只能声明一个抽象方法。有了这个注解之后,定义超过一个抽象方法就会给出报错提示:【闲聊杂谈】深入剖析Java8新特性_第9张图片

Lambda表达式的原理

匿名内部类的本质是在编译时生成一个Class文件:XXXXX$1.class【闲聊杂谈】深入剖析Java8新特性_第10张图片

还可以通过反编译工具来查看生成的代码XJad工具来查看:【闲聊杂谈】深入剖析Java8新特性_第11张图片

同样的也可以使用反编译工具来看Lambda表达式生成的class文件,但是发现使用XJad查看报错。其实可以通过JDK自带的一个工具:javap 对字节码进行反汇编操作:

javap -c -p 文件名.class,-c:表示对代码进行反汇编,-p:显示所有的类和成员【闲聊杂谈】深入剖析Java8新特性_第12张图片

在这个反编译的源码中我们看到了一个静态方法 lambda$main$0(),这个方法里面做了什么事情呢?可以通过debug的方式来查看下: 【闲聊杂谈】深入剖析Java8新特性_第13张图片

可以看到,【System.out.println("通过Lambda表达式实现show方法");】这个方法是在【lambda$main$0()】中执行的,简单点可以理解为:【闲聊杂谈】深入剖析Java8新特性_第14张图片

为了更加直观的理解这个内容,我们可以在运行的时候添加参数:
java -Djdk.internal.lambda.dumpProxyClasses 要运行的包名.类名,加上这个参数会将内部class码输出到一个文件中: 【闲聊杂谈】深入剖析Java8新特性_第15张图片【闲聊杂谈】深入剖析Java8新特性_第16张图片

将这个文件反编译后看到:【闲聊杂谈】深入剖析Java8新特性_第17张图片

可以看到这个匿名的内部类实现了UserService接口,并重写了show()方法。在show()方法中调用了Demo03Lambda.lambda$main$0(),也就是调用了Lambda表达式中的内容。 【闲聊杂谈】深入剖析Java8新特性_第18张图片

总结下来就是:匿名内部类在编译的时候会产生一个class文件,Lambda表达式在程序运行的时候会形成一个类。在类中新增了一个方法,这个方法的方法体就是Lambda表达式中的代码。还会形成一个匿名内部类,实现接口,重写抽象方法,在接口中重写方法会调用新生成的方法。

Lambda表达式的省略写法

在lambda表达式的标准写法基础上,可以使用省略写法的规则为:
1、小括号内的参数类型可以省略;
2、如果小括号内有且仅有一个参数,则小括号可以省略;
3、如果大括号内有且仅有一个语句,可以同时省略大括号,return 关键字及语句分号;【闲聊杂谈】深入剖析Java8新特性_第19张图片

Lambda表达式的使用前提

Lambda表达式的语法是非常简洁的,但是Lambda表达式不是随便使用的,使用时有几个条件要特别注意:
1、方法的参数或局部变量类型必须为接口才能使用Lambda
2、接口中有且仅有一个抽象方法(@FunctionalInterface)

Lambda和匿名内部类的对比

1、所需类型不一样
    - 匿名内部类的类型可以是 类,抽象类,接口
    - Lambda表达式需要的类型必须是接口

2、抽象方法的数量不一样
    - 匿名内部类所需的接口中的抽象方法的数量是随意的
    - Lambda表达式所需的接口中只能有一个抽象方法

3、实现原理不一样
    - 匿名内部类是在编译后形成一个class
    - Lambda表达式是在程序运行的时候动态生成class

2、接口增强

在Java8之前:
interface 接口名{
    静态常量;
    抽象方法;
}

在Java8之后:
interface 接口名{
    静态常量;
    抽象方法;
    默认方法;
    静态方法;

}

默认方法

在JDK8以前接口中只能有抽象方法和静态常量,会存在一个问题:如果接口中新增抽象方法,那么实现类都必须要抽象这个抽象方法,非常不利于接口的扩展的。【闲聊杂谈】深入剖析Java8新特性_第20张图片

接口默认方法的语法

interface 接口名{
    修饰符 default 返回值类型 方法名{
        方法体;
    }
}

接口中的默认方法有两种使用方式:
1、实现类直接调用接口的默认方法
2、实现类重写接口的默认方法

【闲聊杂谈】深入剖析Java8新特性_第21张图片

静态方法

接口中的静态方法在实现类中是不能被重写的,调用的话只能通过接口类型来实现: 
接口名.静态方法名();

接口静态方法的语法

interface 接口名{
    修饰符 static 返回值类型 方法名{
        方法体;
    }
}

【闲聊杂谈】深入剖析Java8新特性_第22张图片

默认方法和静态方法的区别

1、默认方法通过实例调用,静态方法通过接口名调用;
2、默认方法可以被继承,实现类可以直接调用接口默认方法,也可以重写接口默认方法;
3、静态方法不能被继承,实现类不能重写接口的静态方法,只能使用接口名调用;

3、函数式接口

Supplier接口

【闲聊杂谈】深入剖析Java8新特性_第23张图片

无参有返回值的接口,对于的Lambda表达式需要提供一个返回数据的类型:【闲聊杂谈】深入剖析Java8新特性_第24张图片

Consumer接口

有参无返回值得接口。前面介绍的Supplier接口是用来生产数据的,而Consumer接口是用来消费数据的,使用的时候需要指定一个泛型来定义参数类型:【闲聊杂谈】深入剖析Java8新特性_第25张图片

除了抽象方法以外,还有一个默认方法:andThen。如果一个方法的参数和返回值全部是Consumer类型,那么就可以实现消费一个数据的时候,首先做一个操作,然后再做一个操作,实现组合,而这个方法就是Consumer接口中的default andThen方法:【闲聊杂谈】深入剖析Java8新特性_第26张图片

Function接口

【闲聊杂谈】深入剖析Java8新特性_第27张图片

有参有返回值的接口,Function接口是根据一个类型的数据得到另一个类型的数据,前者称为前置条件,后者称为后置条件。【闲聊杂谈】深入剖析Java8新特性_第28张图片

default andThen方法:【闲聊杂谈】深入剖析Java8新特性_第29张图片

这个接口中还包含另外两个方法,默认的compose方法的作用顺序和andThen方法刚好相反,而静态方法identity则是,输入什么参数就返回什么参数。

Predicate接口

有参且返回值为Boolean的接口。【闲聊杂谈】深入剖析Java8新特性_第30张图片【闲聊杂谈】深入剖析Java8新特性_第31张图片

在Predicate中的默认方法提供了逻辑关系操作 and、or、negate、isEquals等方法【闲聊杂谈】深入剖析Java8新特性_第32张图片

4、方法引用

在使用Lambda表达式的时候,也会出现代码冗余的情况,比如:用Lambda表达式求一个数组的和。【闲聊杂谈】深入剖析Java8新特性_第33张图片

因为在Lambda表达式中要执行的代码和另一个方法中的代码是一样的,这时就没有必要重写一份逻辑了,可以直接 “引用” 重复代码。【闲聊杂谈】深入剖析Java8新特性_第34张图片

方法引用的语法

符号表示:【::

符号说明:双冒号为方法引用运算符,而它所在的表达式被称为方法引用

应用场景:如果Lambda表达式所要实现的方案,已经有其他方法存在相同的方案,那么则可以使用方法引用。

方法引用在Java8中使用是相当灵活的,有以下几种形式:
1、instanceName::methodName  对象::方法名
2、ClassName::staticMethodName  类名::静态方法
3、ClassName::methodName  类名::普通方法
4、ClassName::new  类名::new 调用的构造器
5、TypeName[]::new String[]::new  调用数组的构造器

instanceName::methodName  对象::方法名
这是最常见的一种用法。如果一个类中的已经存在了一个成员方法,则可以通过对象名引用成员方法。方法引用的注意事项:
1、被引用的方法,参数要和接口中的抽象方法的参数一样;
2、当接口抽象方法有返回值时,被引用的方法也必须有返回值;【闲聊杂谈】深入剖析Java8新特性_第35张图片

ClassName::staticMethodName  类名::静态方法【闲聊杂谈】深入剖析Java8新特性_第36张图片

ClassName::methodName 类名::普通方法
Java面向对象中,类名只能调用静态方法,类名引用实例方法是用前提的,实际上是拿第一个参数作为方法的调用者。【闲聊杂谈】深入剖析Java8新特性_第37张图片

ClassName::new   类名::new 调用的构造器
由于构造器的名称和类名完全一致,所以构造器引用使用"::new"的格式使用。【闲聊杂谈】深入剖析Java8新特性_第38张图片

TypeName[]::new  String[]::new 调用数组的构造器【闲聊杂谈】深入剖析Java8新特性_第39张图片

方法引用是对Lambda表达式符合特定情况下的一种缩写方式,它使得Lambda表达式更加的精简,也可以理解为lambda表达式的缩写形式,不过要注意的是方法引用只能引用已经存在的方法。

5、Stream API

当需要对集合中的元素进行操作的时候,除了必需的添加,删除,获取外,最典型的操作就是集合遍历。很多时候针对不同的需求总是一次次的循环循环循环,这时就非常希望有更加高效的处理方式,现在可以通过JDK8中提供的Stream API来解决这个问题。

【闲聊杂谈】深入剖析Java8新特性_第40张图片

Stream流式思想

首先先明确一个概念:Stream和IO流(InputStream/OutputStream)没有任何关系,请暂时忘记对传统IO流的固有印象。Stream流式思想类似于工厂车间的“生产流水线”,Stream流不是一种数据结构,不保存数据,而是对数据进行加工处理。Stream可以看作是流水线上的一个工序。在流水线上,通过多个工序让一个原材料加工成一个商品。

【闲聊杂谈】深入剖析Java8新特性_第41张图片

Stream API能让我们快速完成许多复杂的操作,如筛选、切片、映射、查找、去重、统计、匹配和归约。

【闲聊杂谈】深入剖析Java8新特性_第42张图片

Stream流获取方式

Collection接口获取

java.util.Collection 接口中加入了default方法stream,也就是说Collection接口下的所有的实现都可以通过steam方法来获取Stream流。 【闲聊杂谈】深入剖析Java8新特性_第43张图片

但是Map接口别没有实现Collection接口,那这时怎么办呢?可以根据Map获取对应的key-value的集合,在通过集合去获取Stream流。

Stream的of方法获取

在实际开发中不可避免的还是会操作到数组中的数据,由于数组对象不可能添加默认方法,所有Stream接口中提供了of静态方法。【闲聊杂谈】深入剖析Java8新特性_第44张图片

Stream流常用方法

Stream流模型的操作很丰富,这里介绍一些常用的API。这些方法可以被分成两种:

终结方法:返回值类型不再是 Stream 类型的方法,不再支持链式调用。终结方法包括 count forEach 方法;
非终结方法:返回值类型仍然是 Stream 类型的方法,支持链式调用。除了终结方法外,其余方法均为非终结方法;

Stream流需要注意:
1、Stream只能操作一次;
2、Stream方法返回的是新的流;
3、Stream不调用终结方法,中间的操作不会执行

方法名 方法作用 返回值类型 方法种类
count 统计个数 long 终结
forEach 逐一处理 void 终结
filter 过滤 Stream 函数拼接
limit 取用前几个 Stream 函数拼接
skip 跳过前几个 Stream 函数拼接
map 映射 Stream 函数拼接
concat 组合 Stream 函数拼接

【闲聊杂谈】深入剖析Java8新特性_第45张图片

forEach用来遍历流中的数据的,该方法接受一个Consumer接口,会将每一个流元素交给函数处理。

【闲聊杂谈】深入剖析Java8新特性_第46张图片

count

【闲聊杂谈】深入剖析Java8新特性_第47张图片

Stream流中的count方法用来统计其中的元素个数的,该方法返回一个long值,代表元素的个数。

【闲聊杂谈】深入剖析Java8新特性_第48张图片

filter

filter方法的作用是用来过滤数据的,返回符合条件的数据,可以通过filter方法将一个流转换成另一个子集流。

【闲聊杂谈】深入剖析Java8新特性_第49张图片

可以看到,该接口接收一个Predicate函数式接口参数作为筛选条件。

【闲聊杂谈】深入剖析Java8新特性_第50张图片

limit

limit方法可以对流进行截取处理,只取前n个数据。

【闲聊杂谈】深入剖析Java8新特性_第51张图片

参数是一个long类型的数值,如果集合当前长度大于参数就进行截取,否则不操作。

【闲聊杂谈】深入剖析Java8新特性_第52张图片

skip

如果希望跳过前面几个元素,可以使用skip方法获取一个截取之后的新流。

【闲聊杂谈】深入剖析Java8新特性_第53张图片【闲聊杂谈】深入剖析Java8新特性_第54张图片

map

如果我们需要将流中的元素映射到另一个流中,可以使用map方法。

【闲聊杂谈】深入剖析Java8新特性_第55张图片

该接口需要一个Function函数式接口参数,可以将当前流中的T类型数据转换为另一种R类型的数据。

【闲聊杂谈】深入剖析Java8新特性_第56张图片

sorted

如果需要将数据排序,可以使用sorted方法。

【闲聊杂谈】深入剖析Java8新特性_第57张图片

在使用的时候可以根据自然规则排序,也可以通过比较强来指定对应的排序规则。

【闲聊杂谈】深入剖析Java8新特性_第58张图片

distinct

如果要去掉重复数据,可以使用distinct方法。

【闲聊杂谈】深入剖析Java8新特性_第59张图片

Stream流中的distinct方法对于基本数据类型是可以直接出重的,但是对于自定义类型,需要重写hashCode和equals方法来移除重复元素。  

【闲聊杂谈】深入剖析Java8新特性_第60张图片【闲聊杂谈】深入剖析Java8新特性_第61张图片

match

如果需要判断数据是否匹配指定的条件,可以使用match相关的方法。

anyMatch:元素是否有任意一个满足条件【闲聊杂谈】深入剖析Java8新特性_第62张图片【闲聊杂谈】深入剖析Java8新特性_第63张图片

allMatch:元素是否都满足条件【闲聊杂谈】深入剖析Java8新特性_第64张图片【闲聊杂谈】深入剖析Java8新特性_第65张图片

noneMatch:元素是否都不满足条件【闲聊杂谈】深入剖析Java8新特性_第66张图片【闲聊杂谈】深入剖析Java8新特性_第67张图片

find

如果我们需要找到某些数据,可以使用find方法来实现。

【闲聊杂谈】深入剖析Java8新特性_第68张图片【闲聊杂谈】深入剖析Java8新特性_第69张图片

max / min 

【闲聊杂谈】深入剖析Java8新特性_第70张图片【闲聊杂谈】深入剖析Java8新特性_第71张图片

reduce

如果需要将所有数据归纳得到一个数据,可以使用reduce方法。 

【闲聊杂谈】深入剖析Java8新特性_第72张图片【闲聊杂谈】深入剖析Java8新特性_第73张图片

而在实际开发中,经常会将map和reduce一块来使用。

【闲聊杂谈】深入剖析Java8新特性_第74张图片

mapToInt

如果需要将Stream中的Integer类型转换成int类型,可以使用mapToInt方法来实现。

【闲聊杂谈】深入剖析Java8新特性_第75张图片【闲聊杂谈】深入剖析Java8新特性_第76张图片

concat

如果有两个流,希望合并成为一个流,那么可以使用Stream接口的静态方法concat。

【闲聊杂谈】深入剖析Java8新特性_第77张图片【闲聊杂谈】深入剖析Java8新特性_第78张图片

Stream流综合案例

定义两个集合,然后在集合中存储多个用户名称。然后完成如下的操作:
1、第一个队伍只保留姓名长度为3的成员;
2、第一个队伍筛选之后只要前3个人;
3、第二个队伍只要姓张的成员;
4、第二个队伍筛选之后不要前一个人;
5、将两个队伍合并为一个队伍;
6、根据姓名创建Person对象;
7、打印整个队伍的Person信息;

【闲聊杂谈】深入剖析Java8新特性_第79张图片

Stream结果收集

结果收集到集合中【闲聊杂谈】深入剖析Java8新特性_第80张图片

结果收集到数组中【闲聊杂谈】深入剖析Java8新特性_第81张图片

Stream流中数据进行聚合计算

在使用Stream流处理数据后,可以像数据库的聚合函数一样对某个字段进行操作,比如:获得最大值,最小值,求和,平均值,统计数量。

【闲聊杂谈】深入剖析Java8新特性_第82张图片

Stream流中数据进行分组

在使用Stream流处理数据后,可以根据某个属性将数据分组。

【闲聊杂谈】深入剖析Java8新特性_第83张图片

还可以根据多个字段进行多级组合分组。

【闲聊杂谈】深入剖析Java8新特性_第84张图片

Stream流中数据进行分区

Collectors.partitioningBy会根据值是否为true,把集合中的数据分割为两个列表,一个true列表,一个false列表。【闲聊杂谈】深入剖析Java8新特性_第85张图片

Stream流中数据进行拼接

Collectors.joining会根据指定的连接符,将所有的元素连接成一个字符串。

【闲聊杂谈】深入剖析Java8新特性_第86张图片

Stream并行流

并行流与串行流

上面提到的都是Stream串行流,也就是在一个线程上面执行。为了提高在大数据量方面的效率,引入了并行流的概念。parallelStream其实就是一个并行执行的流,它通过默认的ForkJoinPool,可以提高多线程任务的速度。可以通过两种方式来获取并行流:
1、通过List接口中的parallelStream方法来获取;
2、通过已有的串行流转换为并行流(parallel);

【闲聊杂谈】深入剖析Java8新特性_第87张图片

并行流的操作和串行流没有任何区别

【闲聊杂谈】深入剖析Java8新特性_第88张图片

通过for循环,串行Stream流,并行Stream流来对500000000亿个数字求和,来看消耗时间

【闲聊杂谈】深入剖析Java8新特性_第89张图片

可以看到parallelStream的效率是最高的,Stream并行处理的过程会分而治之,也就是将一个大的任务切分成了多个小任务,这表示每个任务都是一个线程操作。但需要注意的是,使用并行流是在数据量较大的情况下才会占据优势,如果是较小的数据量情况下,并行流的效率可能还不如串行流。

并行流的线程安全问题

【闲聊杂谈】深入剖析Java8新特性_第90张图片

加锁【闲聊杂谈】深入剖析Java8新特性_第91张图片

使用线程安全容器 【闲聊杂谈】深入剖析Java8新特性_第92张图片

使用Stream中的toArray/collect【闲聊杂谈】深入剖析Java8新特性_第93张图片

6、Optional

Optional是一个没有子类的工具类,Optional是一个可以为null的容器对象,主要就是解决空指针的问题,防止NullpointerException。

不使用Optional对null的处理显得代码非常的繁琐和臃肿【闲聊杂谈】深入剖析Java8新特性_第94张图片

Optional对象的三种创建方式【闲聊杂谈】深入剖析Java8新特性_第95张图片

Optional常用方法

get

如果Optional有值则返回,否则抛出NoSuchElementException异常【闲聊杂谈】深入剖析Java8新特性_第96张图片

isPresent

判断是否包含值,包含值返回true,不包含值返回false,常和get方法一起搭配使用【闲聊杂谈】深入剖析Java8新特性_第97张图片

orElse

如果调用对象包含值,就返回该值,否则返回t【闲聊杂谈】深入剖析Java8新特性_第98张图片

orElseGet

如果调用对象包含值,就返回该值,否则返回Lambda表达式的返回值【闲聊杂谈】深入剖析Java8新特性_第99张图片

7、LocalDateTime

为什么引入LocalDateTime

在旧版本中JDK对于日期和时间这块的支持是非常差的:
1、设计不合理,在java.util和java.sql的包中都有日期类,java.util.Date同时包含日期和时间的,而java.sql.Date仅仅包含日期,此外用于格式化和解析的类在java.text包下;
2、非线程安全,java.util.Date是非线程安全的,所有的日期类都是可变的,这是java日期类最大的问题之一;
3、时区处理麻烦,日期类并不提供国际化,没有时区支持;

【闲聊杂谈】深入剖析Java8新特性_第100张图片

针对以上种种问题,Java8中增加了一套全新的日期时间API,这套API设计合理,并且支持线程安全。新的日期及时间API位于 java.time 包
中,下面是一些关键类:
- LocalDate:表示日期,包含年月日,格式为【2019-10-16】;
- LocalTime:表示时间,包含时分秒,格式为【16:38:54.158549300】;
- LocalDateTime:表示日期时间,包含年月日,时分秒,格式为【2018-09-06T15:33:56.750】;
- DateTimeFormatter:日期时间格式化类;
- Instant:时间戳,表示一个特定的时间瞬间;
- Duration:用于计算2个时间(LocalTime,时分秒)的距离;
- Period:用于计算2个日期(LocalDate,年月日)的距离;
- ZonedDateTime :包含时区的时间;

Java中使用的历法是ISO 8601日历系统,它是世界民用历法,也就是所说的公历。平年有365天,闰年是366天。此外Java8还提供了4套其他历法,分别是:
- ThaiBuddhistDate:泰国佛教历
- MinguoDate:中华民国历
- JapaneseDate:日本历
- HijrahDate:伊斯兰历

LocalDate 常用方法【闲聊杂谈】深入剖析Java8新特性_第101张图片

LocalTime常用方法【闲聊杂谈】深入剖析Java8新特性_第102张图片

LocalDateTime常用方法【闲聊杂谈】深入剖析Java8新特性_第103张图片

日期时间的修改和比较

LocalDateTime中对日期时间的修改,对已存在的对象创建了它模板,并不会修改原来对象本身的时间,自然也就不会牵涉到数据安全的问题。

【闲聊杂谈】深入剖析Java8新特性_第104张图片【闲聊杂谈】深入剖析Java8新特性_第105张图片【闲聊杂谈】深入剖析Java8新特性_第106张图片

日期时间的格式化和解析

在JDK8中可以通过java.time.format.DateTimeFormatter类可以进行日期的解析和格式化操作

【闲聊杂谈】深入剖析Java8新特性_第107张图片

日期时间差

Java8中提供了两个工具类来计算日期时间差:
1、Duration:用来计算两个时间差(LocalTime);
2、Period:用来计算两个日期差(LocalDate);

【闲聊杂谈】深入剖析Java8新特性_第108张图片【闲聊杂谈】深入剖析Java8新特性_第109张图片

时间矫正器

有时候对时间可能需要如下调整:将日期调整到"下个月的第一天"这种操作,虽然通过前面介绍的plus和with也可以实现,不过使用时间校正器效果可能会更好。

- TemporalAdjuster:时间校正器
- TemporalAdjusters:通过该类静态方法提供了大量的常用TemporalAdjuster的实现

【闲聊杂谈】深入剖析Java8新特性_第110张图片

时区

Java8 中加入了对时区的支持,LocalDate、LocalTime、LocalDateTime是不带时区的,带时区的日期时间类分别为:ZonedDate、ZonedTime、ZonedDateTime。其中每个时区都对应着 ID,ID的格式为 “区域/城市” 。例如 :Asia/Shanghai 等。 ZoneId:该类中包含了所有的时区信息。

【闲聊杂谈】深入剖析Java8新特性_第111张图片

JDK新的日期和时间API的优势:
1、新版日期时间API中,日期和时间对象是不可变,操作日期不会影响原来的值,而是生成一个新的实例;
2、提供不同的两种方式,有效的区分了人和机器的操作;
3、TemporalAdjuster可以更精确的操作日期,还可以自定义日期调整期;
4、线程安全;

8、重复注解和类型注解

重复注解

自从Java5中引入注解以来,注解开始变得非常流行,并在各个框架和项目中被广泛使用。不过注解有一个很大的限制是,在同一个地方不能多次使用同一个注解。Java8引入了重复注解的概念,允许在同一个地方多次使用同一个注解。在Java8中使用@Repeatable注解定义重复注解。

定义一个可以重复的注解【闲聊杂谈】深入剖析Java8新特性_第112张图片

定义一个重复注解的容器 【闲聊杂谈】深入剖析Java8新特性_第113张图片

使用重复注解【闲聊杂谈】深入剖析Java8新特性_第114张图片

解析得到指定的注解 【闲聊杂谈】深入剖析Java8新特性_第115张图片

类型注解

Java8为@Target元注解新增了两种类型: TYPE_PARAMETER、TYPE_USE 
- TYPE_PARAMETER:表示该注解能写在类型参数的声明语句中。 类型参数声明如: 
- TYPE_USE:表示注解可以再任何用到类型的地方使用。

TYPE_PARAMETER

【闲聊杂谈】深入剖析Java8新特性_第116张图片【闲聊杂谈】深入剖析Java8新特性_第117张图片

TYPE_USE

【闲聊杂谈】深入剖析Java8新特性_第118张图片【闲聊杂谈】深入剖析Java8新特性_第119张图片

你可能感兴趣的:(闲聊杂谈,java,JDK8新特性,1024程序员节)