0%

必知必会面试题之 Java 8 新特性

不定期更新……



Lambda 表达式

概念

特点:

  • 可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
  • 可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
  • 可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
  • 可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表达式返回了一个数值。

注意:

  • 最好不要在 Lambda 表达式内复杂的处理逻辑,只用来做数据处理
  • Lambda 表达式内使用外层局部变量,该局部变量不可修改,如果需要修改,需要将局部变量赋值给一个不做修改的新对象,使用新对象进行处理。

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
private class Item {
private Long id;
private String name;
private String group;
// 省略 get / set 方法
}

public static void main(String[] args) {
List<Item> list = new ArrayList<>();
// 可选类型声明
// 可选参数圆括号
// 可选大括号
// 可选返回关键字
List<Long> list1 = list.stream().map(Item::getId).collect(Collectors.toList());

// 不处理复杂逻辑
// - 正确示例:
list4.forEach(l -> System.out.println(l));
// - 错误示例:
list4.forEach(l -> {
int i = 0;
if (i <= 100) {
System.out.println("100:" + i);
} else if (i < 1000) {
System.out.println("1000:" + i);
} else {
System.out.println("undefined:" + i);
}
System.out.println(l);
});

// 使用局部变量
// - 正确示例:
final long[] s1 = {0L};
list4.forEach(a -> s1[0] += a);
// - 错误示例:
long s2 = 0L;
list4.forEach(a -> s2 += a);
}

方法引用

概念

方法引用通过方法的名字来指向一个方法。

方法引用可以使语言的构造更紧凑简洁,减少冗余代码。

方法引用使用一对冒号 ::

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public static void main(String[] args) {
// 1.构造器引用
final Car car = Car.create( Car::new );
final List< Car > cars = Arrays.asList( car );
// 2.静态方法引用
cars.forEach( Car::collide );
// 3.特定类的任意对象的方法引用
cars.forEach( Car::repair );
// 4.特定对象的方法引用
cars.forEach( car::follow );
}

@FunctionalInterface
public interface Supplier<T> {
T get();
}
public class Car {}
//Supplier 是 jdk1.8 的接口,这里和 lambda 一起使用了
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());
}
}

函数式接口

概念

默认方法

概念

Stream

概念

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
List<Item> list = new ArrayList<>();
// 转化
List<Long> list1 = list.stream().map(Item::getId).collect(Collectors.toList());
// 转 map
Map<Long, String> map1 = list.stream().collect(Collectors.toMap(Item::getId, Item::getName));
// 分组
Map<String, List<Item>> itemMap = list.stream().collect(Collectors.groupingBy(Item::getGroup));
// 求最大值
Optional<Item> maxDish = list.stream()
.collect(Collectors.maxBy(Comparator.comparing(Item::getId)));
// 求最小值
Optional<Item> minDish = list.stream()
.collect(Collectors.minBy(Comparator.comparing(Item::getId)));
// 求和
Long sum = list1.stream().mapToLong(Long::longValue).sum();
// 排序
List<Long> list2 = list1.stream().sorted().collect(Collectors.toList());
// 过滤
List<Item> list3 = list.stream().filter(item -> item.getName() != null)
.collect(Collectors.toList());
// 去重
List<Long> list4 = list1.stream().distinct().collect(Collectors.toList());

Spliterator

概念

Spliterator 是一个分割迭代器(Spliterator Iterator),顾名思义,作用就是用来分隔数据,以便于 Stream 中可以进行并行流计算。

在 Java 8 中,Spliterator 是通过 Collection 接口实现 parallelStream() 方法来提供给我们使用的,它可以讲集合数据根据一定规则分割为一个个小集合,然后集合便可以通过并行计算的方式进行处理,提高集合处理速度。

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
long t1 = System.currentTimeMillis();
System.out.println(t1);
list.stream().forEach(i -> System.out.println(i));
long t2 = System.currentTimeMillis();
System.out.println(t1 + ", stream 耗时:" + (t2 - t1));
list.parallelStream().forEach(i -> System.out.println(i));
long t3 = System.currentTimeMillis();
System.out.println(t3 + ", parallelSteam 耗时:" + (t3 - t2));
// 输出结果
/*
1615201828031
1
2
3
4
5
1615201828031, stream 耗时:82
3
1
5
4
2
1615201828120, parallelSteam 耗时:7
*/

Optional 类

概念

Optional 类是一个可以为 null 的容器对象。如果值存在则 isPresent() 方法会返回 true,调用 get() 方法会返回该对象。

Optional 是个容器:它可以保存类型 T 的值,或者仅仅保存 null。Optional 提供很多有用的方法,这样我们就不用显式进行空值检测。

Optional 类的引入很好的解决空指针异常。

示例

1
2
3
4
List<Integer>     list     = new ArrayList<>();
Optional<Integer> optional = list.stream().findFirst();
optional.orElse(0);
System.out.println(optional);

Nashorn、JavaScript 引擎

概念

新的日期时间 API

概念

Base 64

概念

——————————————————————————————————————————————

原创:西狩

编写日期 / 修订日期:2020-12-30 / 2020-12-30

版权声明:本文为博主原创文章,遵循 CC BY-NC-SA-4.0 版权协议,转载请附上原文出处链接和本声明。