Java 10 都已经出来了,为啥还在学 Java 8 呢?
首先是我自己没有系统的学习 Java 8 的新特性,只是看博客的时候学到那些是那些。
其次呢,2017年9月,Oracle 将 Java 大版本周期从原来的 2-3 年,调整成每半年发布一个大的版本。而版本号仍延续原来的序号,即 Java 8、Java 9、Java 10、Java 11.....
但和之前不一样的是,同时还有一个版本号来表示发布的时间和是否为 LTS(长期支持版本),比如 Java 10 对应 18.3。如下示例:
/jdk-10/bin$ ./java -version
openjdk version "10" 2018-03-20
OpenJDK Runtime Environment 18.3 (build 10+46)
OpenJDK 64-Bit Server VM 18.3 (build 10+46, mixed mode)
需要注意的是 Java 9 和 Java 10 都不是 LTS 版本。和过去的 Java 大版本升级不同,这两个只有半年左右的开发和维护期。而未来的 Java 11,也就是 18.9 LTS,才是 Java 8 之后第一个 LTS 版本(得到 Oracle 等商业公司的长期支持服务)。
所以等 Java 11 出来了再去学习新的特征也不迟,不过尝鲜的小伙伴可以了解一下 Java 9 和 Java 10 添加了那些特征。这里我还是老老实实啃一下 Java 8 吧。
Java 8中我们谈论最多的就是 lambda 表达式了,当然它还有其他的特性,比如 默认方法,stream API 和 新的 Date/Time API 等等。下面我们先用例子来了解一下 Java 8 的一下特性吧。
Lambda 表达式
在编程使用上,Lambda 表达式就像是匿名函数一样,我们将Lambda 表达式当做一个参数传递给另一个函数,是不是很神奇。但是这个特性在 Scala 中已经很常见了。
Lambda 表达式的基本语法
(parameters) -> expression
或者
(parameters) -> { statements; }
或者
() -> expression
举个例子
(x, y) -> x + y // 这个函数接受2个参数,并且返回2个参数的和
书写 Lambda 表达式的规则
- 一个 Lambda 表达式可以有 0个,1个或者更多的参数。
- 参数的类型可以显示声明出来,也可以通过代码推断出来参数的类型。
- 多个参数必须放在 () 中并用 , 分隔 比如这样 (param1, param2, param3),空的() 表示不接受任何参数。
- 当只有一个参数的时候,如果参数类型能够被推断出来,可以不必使用(),比如 a -> a * a。
- lambda 书写语句部分能够有 0条,1条或多条语句。
- 当 lambda 书写语句部分只有1条语句时,可以不用书写 {},并且这个匿名函数的返回值就是表达式语句的结果。当书写语句部分不止1条语句时必须使用 {} 将这些语句包裹进来。
函数接口
函数接口也称为 Single Abstract Method interfaces (SAM Interfaces)。从名字可以看出,这种接口只允许有1个抽象方法。Java 8 提供了 @FunctionalInterface 注解,当使用这个注解标识一个接口的时候,这个接口如果不符合函数接口的规定,编译器会报错。
举个例子
@FunctionalInterface
public interface MyFirstFunctionalInterface {
public void firstWork();
}
注意,即使忽略@FunctionalInterface注释,函数接口也是有效的。 它仅用于通知编译器在接口内强制执行单一抽象方法。
因为默认方法不是抽象方法,所以可以在函数接口中任意添加默认方法(你开心就好)。
另外需要注意,一个接口声明了一个抽象方法重载了 java.lang.Object 类中的 public 方法,这个方法不算作接口的抽象方法,因为这个接口的任何实现都会有这些方法(Object 中声明的 public 方法)的实现,这些实现可能来自于 java.lang.Object 或其他类。例如下面这个函数接口任然合理。
@FunctionalInterface
public interface MyFirstFunctionalInterface{
public void firstWork();
@Override
public String toString(); //Overridden from Object class
@Override
public boolean equals(Object obj); //Overridden from Object class
}
默认方法
Java 8 允许在接口中添加非抽象的方法。这些方法必须声明为默认方法。在 Java 8 中引入了默认方法来启用 lambda 表达式的功能。
默认方法使您可以向库的接口添加新功能,并确保与为这些接口的旧版本编写的代码的二进制兼容性。最典型的例子就是 Java 8 中的 List 接口。
举个例子
public interface Moveable {
default void move(){
log.info("I am moving");
}
}
Moveable 接口定义了move()方法并提供了 move() 方法的默认实现,如果任何类实现了 Moveable 这个接口,这个类不必实现 move() 方法,可以直接调用 instance.move() 方法。
public class Animal implements Moveable {
public static void main(String[] args){
Animal tiger = new Animal();
tiger.move();
}
}
Output: I am moving
如果类想要自己实现 move() 方法也可以重载这个方法。
Streams
另外一个主要改变就是 Java 8 的 Streams API,Stream API 提供了对数据集处理的一种机制,可以对数据集进行过滤、转换或者对应用程序可能有用的任何其他方式。
举例说明, items 是 String 的集合,我们移除其中一些以某些前缀开始的项。
List<String> items;
String prefix;
List<String> filteredList = items.stream().filter(e -> (!e.startsWith(prefix))).collect(Collectors.toList());
items.stream() 表示我们希望使用 Stream API 来处理这个集合。
Date/Time API 的变化
Dates
Date 类已经过时啦,在 Java 8 中使用 LocalDate, LocalTime and LocalDateTime 来替代原来的 Date 类。
- LocalDate 代表日期。没有时间或时区的含义。
- LocalTime 掉代表时间。没有日期或时区的含义。
- LocalDateTime 代表 日期和时间。没有时区的含义。
如果想使用日期并且带上时区的信息, Lambda 提供可另外 3 个相似的类 OffsetDate, OffsetTime and OffsetDateTime。时区可以用 “+05:30” 或者 “Europe/Paris” 代表。可以使用 ZoneId 来完成。
LocalDate localDate = LocalDate.now();
LocalTime localTime = LocalTime.of(12, 20);
LocalDateTime localDateTime = LocalDateTime.now();
OffsetDateTime offsetDateTime = OffsetDateTime.now();
ZonedDateTime zonedDateTime = ZonedDateTime.now(ZoneId.of("Europe/Paris"));
====
输出
12:20
2018-04-12T22:21:01.597
2018-04-12T22:21:01.598+08:00
2018-04-12T16:21:01.601+02:00[Europe/Paris]
Timestamp and Duration
为了随时表示特定时间戳,需要使用 Instant 类。Instant 类表示一个瞬时,精度精确到了纳秒。 可以在 Instant 上进行加或减一段时间生成一个新的 Instant 类。
Instant instant = Instant.now();
Instant instant1 = instant.plus(Duration.ofMillis(5000));
Instant instant2 = instant.minus(Duration.ofMillis(5000));
Instant instant3 = instant.minusSeconds(10);
Duration 类是 Java 语言中首次引入的全新概念。 它表示两个时间戳之间的时间差。
Duration duration = Duration.ofMillis(5000);
duration = Duration.ofSeconds(60);
duration = Duration.ofMinutes(10);
Duration 类适合处理诸如毫秒,秒,分钟和小时等小单位时间,这更世界与程序代码交互,如果想与人类进行交互,最好使用更大的时间单位,这是可以使用 Period 类来代表。
Period period = Period.ofDays(6);
period = Period.ofMonths(6);
period = Period.between(LocalDate.now(), LocalDate.now().plusDays(60));
网友评论