Java 8 新特性
Java 8
Java 8(JDK 1.8),发布于 2014 年 03 月 18 日。
-
Java 语言开发的一个主要版本。
-
Java 8 包含语言、编译器、库、工具、JVM 等方面的新特性。
1、语言
1.1、Lambda 表达式(❗)
允许函数作为方法参数传递
简化了匿名内部类的复杂写法。
1.1.1、语法
-
函数式接口:仅有一个抽象方法的接口(下一节详解)
-
->
:箭头操作符,将 lambda 表达式分为两部分。 -
左边是形参列表
()
-
右边是方法体
{}
<函数式接口> <变量名> = (形参列表) -> { // 方法体 };
1.1.2、case:简化过程
① Runnable
Java 线程创建 的方式之一
无需传参
-
匿名内部类
Runnable r1 = new Runnable() { @Override public void run() { System.out.println("running-1"); } }; new Thread(r1).start();
-
Lambda 表达式:省略
new
与方法名
之间的内容。Runnable r2 = () -> { System.out.println("running-2"); }; new Thread(r2).start();
② Comparator
通常用于定义 集合 元素的比较规则
需传参
-
匿名内部类
Comparator<String> c1 = new Comparator<String>() { @Override public int compare(String o1, String o2) { return o1.length() - o2.length(); } }; TreeSet<String> set1 = new TreeSet<>(c1);
-
Lambda 表达式:省略以下内容
-
new
与方法名
之间的内容。 -
方法参数类型。
Comparator<String> c2 = (o1, o2) -> { return o1.length() - o2.length(); }; TreeSet<String> set2 = new TreeSet<>(c2);
-
1.1.3、说明
- Lambda 表达式不会生成单独的内部类文件。
- 形参列表
- 形参列表为空,保留
()
。 - 数据类型会自动推断,可省略。
- 形参只有 1 个,可省略
()
。
- 形参列表为空,保留
- 方法体
- 仅 1 条语句,无返回值时可省略
{}
。 - 仅 1 条语句,有返回值时可省略
{}
,需同时省略return
。
- 仅 1 条语句,无返回值时可省略
1.2、函数式接口
函数式接口:有且仅有一个抽象方法的接口。
- 可使用 Lambda 表达式,Lambda 表达式会匹配该抽象方法。
@Functionallnterface
注解:检测接口是否符合函数式接口。
常见函数式接口
方法 | 入参 → 出参 | 说明 | |
---|---|---|---|
Consumer<T> |
void accpet(T t) | T → void | 消费一个值 |
Supplier<T> |
T get() | 无 → T | 提供一个值 |
Function<T, R> |
R apply(T t) | T → R | 运算 |
Predicate<T> |
boolean test(T t) | T → boolean | 判断是否符合条件 |
1.3、方法引用(❗)
Lambda 表达式的简写形式
使用场景:Lambda 表达式的方法体中,调用一个特定的已经存在的方法。
1.3.1、常见形式
操作符 | 方法 | |
---|---|---|
对象 | :: |
实例方法 |
类 | :: |
静态方法 |
类 | :: |
实例方法 |
类 | :: |
new |
1.3.2、示例
-
对象
::
实例方法Consumer<String> c = s -> System.out.println(s); // 简化 Consumer<String> c = System.out::println;
-
类
::
静态方法Comparator<Integer> c = (o1, o2) -> Integer.compare(o1, o2); // 简化 Comparator<Integer> c = Integer::compare;
-
类
::
实例方法// 假设有 Employee 类 Function<Employee, String> fx = e -> e.getName(); // 简化 Function<Employee, String> fx = Employee::getName;
-
类
::
newSupplier<Employee> s = () -> new Employee(); // 简化 Supplier<Employee> s = Employee::new;
2、工具
2.1、Stream 流式编程
Stream(流)定义了对集合/数组的操作
-
包名:package java.util.stream
-
特点
- Stream 本身不存储元素(数据),元素存储在集合/数组中。
- Stream 不会改变源对象,每次操作时返回一个新 Stream。
- Stream 的中间操作是延迟执行的,在终止操作时执行。
-
说明
-
相比 I/O 流 操作磁盘,Stream 是操作集合/数组。
-
Stream 可理解为流水线,允许多个操作(链式调用)。
-
使用步骤
- 创建 Stream
- 中间操作:将初始 Stream 处理转换为新的 Stream,延迟执行。
- 终止操作:产生预期的结果。
2.1.1、创建 Stream
方法 | 说明 | |
---|---|---|
Collection 对象 | stream() 或 parallelStream() |
串行/并行 |
Arrays 工具类 | stream() |
|
Stream 接口 | of() 或 iterate() 或 generate() |
构建/迭代/生成 |
IntStream、LongStream、DoubleStream 接口 | of() 或 range() 或 rangeClosed() |
构建/前闭后开/前闭后闭 |
2.1.2、中间操作(❗)
①
含义 | 参数 | 备注 | |
---|---|---|---|
filter | 过滤 | Predicate | |
limit | 限制个数 | long | 只处理集合前 n 个元素 |
skip | 跳过个数 | long | 跳过集合前 n 个元素 |
distinct | 去重 | - | 需重写 hashCode() 和 equals() |
sorted | 排序 | - | 升序 |
②
map:映射为另一个流
-
参数:Function
-
示例:从 User 集合映射为 username 集合。
// List<User> userList; userList.stream() .map(u - u.getName());
③
parallel:转换成并行流
// 判断是否并行流
list.stream().isParallel();
// 转换成并行流
list.stream().parallel();
2.1.3、终止操作(❗)
①
含义 | 参数 | 说明 | |
---|---|---|---|
forEach | 遍历 | Consumer | |
min | 最小值 | Comparator | 返回 Optional,通过 get() 获取结果 |
max | 最大值 | Comparator | 返回 Optional,通过 get() 获取结果 |
count | 计数 | - | 返回 long |
②
-
reduce:约简
-
参数:BinaryOperator
-
示例:求和
Integer[] arr = {100, 100, 200, 300, 300, 400, 500, 10}; List<Integer> list = Arrays.asList(arr); Optional<Integer> reduce = list.stream() .reduce((a, b) -> a + b); reduce.get();
-
-
collect:将流转换成集合。
-
参数:Collector
-
示例:通过 User 集合的流获取 username 流,再转换成集合。
// List<User> userList userList.stream() // User流 -> username流 .map(User::getName) // username流 -> 集合 .collect(Collectors.toList());
-
2.2、新时间 API
旧时间 API 设计混乱,存在线程安全问题。
JDK 8 引入新时间 API(package java.time)
2.2.1、本地化日期时间
- 类型
- LocalDate
- LocalTime
- LocalDateTime
- 创建方式
- now()
- of()
- 操作
- 获取时间:getYear(),getMonthValue(),...
- 修改时间:plusXxx(),minusXxx(),...
2.2.2、时间戳 & 时区
-
lnstant:时间戳
- 创建方式:now(),of()
- 修改时间:plusXxx(),minusXxx(),...
-
Zoneld:时区
// 本机支持时区 ZoneId.getZone.getAvailableZoneIds(); // 本机默认时区 ZoneId.systemDefault();
-
日期转换
-
Date → Instance → LocalDateTime
// Date -> Instance date.toInstant(); // Instance -> LocalDateTime LocalDateTime.ofInstance(Instance i, ZoneId zid);
-
反之
// LocalDateTime -> Instance:需指定时区 localDateTime.atZone(ZoneId).toInstant(); // Instance -> Date Date.from(Instance i);
-
2.2.3、格式化类
-
SimpleDateFormatter:线程不安全。
-
DateTimeFormatter:线程安全。
// 创建 DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); // 时间 -> 字符串 dtf.format(LocalDateTime.now()); // 字符串 -> 时间 LocalDateTime.parse("时间字符串", dtf);