Contents
  1. 1. 1. Lambda表达式
  2. 2. 2. Stream流处理
  3. 3. 3. optional类
  4. 4. 4. 日期类型
  5. 5. 5. 优化集合api
  6. 6. 6. 优化并发api

一句话总结一下Java8,“以前需要几行、十几行、几十行的代码,现在只需一行,统统只需一行。”
Java8改进的主要有lambda表达式、stream流处理、optional类、日期类型、优化集合api和并发api

1. Lambda表达式

先看个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 筛选红苹果
public List<Apple> filterRedApples(List<Apple> apples) {
List<Apple> result = new ArrayList<>();
for (Apple apple : apples) {
if ("red".equals(apple.getColor())) {
result.add(apple);
}
}
return result;
}
// 筛选重量大于10 的苹果
public List<Apple> filterRedApples(List<Apple> apples) {
List<Apple> result = new ArrayList<>();
for (Apple apple : apples) {
if (apple.getWeight() > 10) {
result.add(apple);
}
}
return result;
}

这两个方法只有 if 语句不同,其他的完全相同,有很大的冗余性。如果能把 if 语句里面的内容当成参数传递,就可以整合成一个方法了。
Java8之前方法只能传递对象或者集合,现在Java8可以通过方法传递行为(或者叫函数)。

1
2
3
4
新建个接口和方法,用来抽象化 if 语句
public interface Predicate<T> {
boolean test(T t);
}

1
2
3
4
5
6
7
8
9
10
把接口传入方法
List<Apple> filterApples(List<Apple> apples, Predicate<Apple> predicate) {
List<Apple> result = new ArrayList<>();
for (Apple apple : apples) {
if (predicate.test(apple)) {
result.add(apple);
}
}
return result;
}
1
2
3
4
5
6
7
8
// 传入具体的筛选函数,"red".equals(apple.getColor())会替换掉predicate.test(apple)
filterApples(apples, apple -> "red".equals(apple.getColor()));
// 筛选重量大于10的苹果,只需要改一下传入参数就可以
filterApples(apples, apple -> apple.getWeight() > 10);
// 想要同时筛选颜色和重量,也很简单
filterApples(apples, apple -> "red".equals(apple.getColor()) && apple.getWeight() > 10);

很强大吧!Java8内置常用的lambda函数接口,平时开发完全不用亲自去写函数接口。

2. Stream流处理

Java8针对集合新增了Stream流API,每次操作需要把集合先转换成流,可以理解为把集合放在流水线上,层层加工,最后再转换成想要的结果。
流API中可以传递lambda函数,算是强大的lambda函数的一个实践。

1
2
// 继续筛选红苹果
List<Apple> redApples = apples.stream().filter(apple -> "red".equals(apple.getColor())).collect(Collectors.toList());

通俗易懂,先把集合转换成流,然后筛选颜色是红色的,最后再转换成List集合,一行代码解决。

1
2
3
4
5
6
7
8
9
10
11
// 取出苹果的名字
List<String> appleNames = apples.stream().map(apple -> apple.getName()).collect(Collectors.toList());
// map就是映射,把集合中的每个元素映射成想要的结果。也可以简写成
List<String> appleNames = apples.stream().map(Apple::getName).collect(Collectors.toList());
// 把苹果按重量降序排列
List<Apple> orderedApples = apples.stream()
.sorted(Comparator.comparing(Apple::getWeight).reversed()).collect(Collectors.toList());
// 把苹果按颜色进行分组
Map<String, List<Apple>> groupedApples = apples.stream().collect(Collectors.groupingBy(Apple::getColor));

流可以操作集合像写SQL语句一样容易,流还有很多方法,比如:find、match、reduce、distinct、skip、limit、count、sum、max、min等,满足你的各种复杂的需求。

3. optional类

先看个例子:

1
2
3
4
5
6
7
8
9
10
11
12
// 查一下你的车险的名字
public String getCarInsuranceName(Person person) {
if (person != null) {
Car car = person.getCar();
if (car != null) {
Insurance insurance = car.getInsurance();
if (insurance != null) {
return insurance.getName();
}
}
}
}

即使代码素养很高的你也常常写出这样令人崩溃的代码吧,层层判空,深度质疑,现在有了Java8,可以做出一些改变了。

1
2
3
4
5
// 把对象有Optional类包装一下
public String getCarInsuranceName(Optional<Insurance> insurance) {
Optional<String> name = insurance.map(Insurance::getName);
return name.orElse("Unknown");
}

Optional提供了map方法,如果insurance为空,就不去调用getName方法,然后给返回值设置默认值。

1
2
3
4
5
6
7
// 因为map方法返回的是Optional<T>类型,我们就可以继续调用map方法了。
public String getCarInsuranceName(Optional<Person> person) {
return person.map(Person::getCar)
.map(Car::getInsurance)
.map(Insurance::getName)
.orElse("Unknown");
}

4. 日期类型

旧的日期类型,例如Date、Calendar、DateFormat都存在诸多问题,以至于每家公司都要复写大量日期函数的方法,或者引入第三方的日期时间库,例如Joda-Time。
现在Java8引入了LocalDate、LocalTime、Instant、Duration、Period,让你轻松需求。

看几个常用的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 当前日期
LocalDate nowDate = LocalDate.now(); // 2017-07-11
// 当前日期时间(这个显示的有点不人性化)
LocalDateTime nowDateTime = LocalDateTime.now(); // 2017-07-11T18:15:12.059
// 获取当前年数(同理,还可以获取月、日、星期、本月天数、是否闰年)
int year = nowDate.getYear(); // 2017
// 把带时分秒的日期转换成不带时分秒的
LocalDate localDate = nowDateTime.toLocalDate(); // 2017-07-11
// 获取当前月的第一天
LocalDate firstDayOfMonth = nowDate.with(TemporalAdjusters.firstDayOfMonth()); // 2017-07-01
// 把字符串转换成日期
LocalDate parse = LocalDate.parse("2017-07-11");
// 格式化当前日期时间
String format = nowDateTime
.format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM)); // 2017-7-11 18:53:37

Java8的日期函数非常强大,什么复杂的需求都能轻松实现。

5. 优化集合api

List、Map集合新增很多实用的api,看几个常用的:

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
40
41
42
43
44
45
46
//List、Map都新增了forEach方法,用于遍历
apples.forEach(System.out::println);
groupedApples.forEach((k, v) -> System.out.println(k + "," + v));
// 也可以修改并打印
apples.forEach(apple -> {
apple.setColor("red");
System.out.println(apple);
});
// replaceAll 替换集合中的每个元素
List<Integer> numbers = Arrays.asList(2, 3, 5);
numbers.replaceAll(number -> number * 2);
System.out.println(numbers);// 输出 4,6,10
// 先判断后删除
List<String> cars = new ArrayList<>();
cars.add("Aston Martin");
cars.removeIf(car -> "Aston Martin".equals(car));
// 获取该品牌汽车的存货量
Map<String, Integer> carInventory = new HashMap<>();
Integer count = 0;
if (carInventory.containsKey("Aston Martin")) {
count = carInventory.get("Aston Martin");
}
// 可以给Value设置默认值
Integer count = carInventory.getOrDefault("Aston Martin", 0);
// 如果缓存里没有,再从数据库获取数据
public String getData(String url) {
String data = cache.get(url);
if (data == null) {
data = getData(url);
cache.put(url, data);
}
return data;
}
// Java有了更简洁的写法
public String getData(String url) {
return cache.computeIfAbsent(url, this::getData);
}
// String增加一个非常实用的join方法
String[] arr = {"aa", "bb", "cc","dd"};
System.out.println(String.join(",", arr));// 输出 aa,bb,cc,dd

6. 优化并发api

stream流有parallel方法,可用作并行处理。
也优化了其他并发api。

Contents
  1. 1. 1. Lambda表达式
  2. 2. 2. Stream流处理
  3. 3. 3. optional类
  4. 4. 4. 日期类型
  5. 5. 5. 优化集合api
  6. 6. 6. 优化并发api