0%

java8 链式编程

本文介绍 java8 lambda表达式的技巧

NPE 的处理

入参判空

空引用空指针是无数个错误的来源

1
2
3
4
5
6
7
@Test
public void test2() {
DogDO dogDO = getDog();
if (dogDO != null) {
System.out.println(dogDO.getName() + ", " + dogDO.getAge());
}
}

使用 Optional 是这样写的:

1
2
3
4
5
@Test
public void test3() {
DogDO dogDO = getDog();
Optional.ofNullable(dogDO).ifPresent(d -> System.out.println(d.getName() + ", " + d.getAge()));
}

函数返回值非空

普通的写法

1
2
3
4
5
6
7
public DogDO playWithDog() {
DogDO d = ...;
if (d != null) {
return d;
}
return new DogDO();
}

我们的函数返回时,保证不返回空,可以使用 orElse 与 orElseGet

对象做默认值用 orElse,方法返回值做默认值用 orElseGet

如下,确实简洁了很多

1
2
3
4
5
public DogDO playWithDog() {
DogDO d = ...;
// return Optional.ofNullable(d).orElseGet(this::getDefaultDog);
return Optional.ofNullable(d).orElse(new DogDO());
}

对应的源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}
public static <T> Optional<T> of(T value) {
return new Optional<>(value);
}
public static<T> Optional<T> empty() {
@SuppressWarnings("unchecked")
Optional<T> t = (Optional<T>) EMPTY;
return t;
}
public T orElse(T other) {
return value != null ? value : other;
}
public T orElseGet(Supplier<? extends T> other) {
return value != null ? value : other.get();
}

集合处理

将A类型集合转为B类型集合

下面是集合中的对象:DO 狗和 DTO 狗

1
2
3
4
5
6
7
8
9
10
@Data
public class DogDO {
private String name;
private Integer age;
}
@Data
public class DogDTO {
private String name;
private Integer age;
}

现在要对一个 DogDO 列表,将符合条件的拿出来,转为 DogDTO 列表,一般的写法是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* 将 dogDOList 转为 DogDTOList
*/
public List<DogDTO> convert(List<DogDO> dogDOList) {
List<DogDTO> dogDTOList = new ArrayList<>();
if (CollectionUtils.isEmpty(dogDOList)) {
return dogDTOList;
}
for (DogDO dogDO : dogDOList) {
// 去掉空狗和未成年狗
if (dogDO == null || dogDO.getAge() < 18) {
continue;
}
DogDTO dogDTO = new DogDTO();
dogDTO.setName(dogDO.getName());
dogDTO.setAge(dogDO.getAge());
dogDTOList.add(dogDTO);
}
return dogDTOList;
}

使用 lambda 表达式可改为:

1
2
3
4
5
6
7
8
public List<DogDTO> convert(List<DogDO> dogDOList) {
return Optional.ofNullable(dogDOList).orElse(Collections.emptyList()).stream().filter(Objects::nonNull).filter(d->d.getAge() > 18).map(e -> {
DogDTO dogDTO = new DogDTO();
dogDTO.setName(e.getName());
dogDTO.setAge(e.getAge());
return dogDTO;
}).collect(Collectors.toList());
}

提取单个属性

和上面的转换是一样的,只不过 map 中 是类型转换还是直接返回某个属性值

要从狗集合中抽出狗昵称,普通的写法是

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 从狗列表中提取狗昵称
public List<String> getNamesFromDogs(List<DogDO> dogDOList) {
List<String> names = new ArrayList<>();
if (dogDOList == null || dogDOList.isEmpty()non) {
return names;
}
for (DogDO dogDO : dogDOList) {
// 去掉空狗
if (dogDO == null) {
continue;
}
names.add(dogDO.getName);
}
return names;
}

Lambda 写法

1
2
3
4
5
// 从狗列表中提取狗昵称
public List<String> getNamesFromDogs(List<DogDO> dogDOList) {
return Optional.ofNullable(dogDOList).orElse(Collections.emptyList()).stream().
filter(Objects::nonNull).map(DogDO::getName).collect(Collectors.toList());
}

可以看出用 lambda 表达式确实很简洁,逻辑上虽然没有普通写法那么清晰,不过习惯了还好

集合类型的转换

List 转 Map

列表转属性-对象的字典

现将一个狗列表转为 {id: 狗对象} 的字典,正常的写法如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public Map<Integer, DogDO> convertDogListToMap(List<DogDO> dogDOList) {
Map<Integer, DogDO> dogDOMap = new HashMap<>();
if (dogDOList == null || dogDOList.isEmpty()) {
return dogDOMap;
}
for (DogDO dogDO : dogDOList) {
if (dogDO == null) {
continue;
}
if (dogDOMap.containsKey(dogDO.getId())) {
continue;
}
dogDOMap.put(dogDO.getId(), dogDO);
}
return dogDOMap;
}
// {1=DogDO{name='a', age=1}, 2=DogDO{name='b', age=2}, 3=DogDO{name='c', age=3}}

使用 lambda 的写法

1
2
3
public Map<Integer, DogDO> convertDogListToMap(List<DogDO> dogDOList) {
return Optional.ofNullable(dogDOList).orElse(Collections.emptyList()).stream().filter(Objects::nonNull).collect(Collectors.toMap(DogDO::getId, v -> v, (p1, p2) -> p1));
}

列表转属性-属性的字典

正常写法略,lambda写法如下

1
2
3
4
public Map<Integer, String> convertDogListToMap(List<DogDO> dogDOList) {
return Optional.ofNullable(dogDOList).orElse(Collections.emptyList()).stream().filter(Objects::nonNull).collect(Collectors.toMap(DogDO::getId, DogDO::getName, (p1, p2) -> p1));
}
// {1=Shaun, 2=Spring, 3=Timmy}

Set 转 Map 的过程同上

列表分组转字典

分成两组

现要按照是否大于18岁把狗子分成两组,正常的写法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public Map<Boolean, List<DogDO>> groupByAge(List<DogDO> dogDOList) {
Map<Boolean, List<DogDO>> map = new HashMap<>();
map.put(true, new ArrayList<>());
map.put(false, new ArrayList<>());
if (dogDOList == null || dogDOList.isEmpty()) {
return map;
}
for (DogDO dogDO : dogDOList) {
if (dogDO == null) {
continue;
}
map.get(dogDO.getAge() > 18).add(dogDO);
}
return map;
}
// {false=[DogDO{name='Shaun', age=18}], true=[DogDO{name='Spring', age=19}, DogDO{name='Timmy', age=20}]}

Lambda 写法

1
2
3
4
public Map<Boolean, List<DogDO>> groupByAge1(List<DogDO> dogDOList) {
return Optional.ofNullable(dogDOList).orElse(Collections.emptyList()).stream().
filter(Objects::nonNull).collect(Collectors.partitioningBy(p -> p.getAge() > 18));
}
分成多组

现要将狗列表按照毛色分成若干组,正常写法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public Map<String, List<DogDO>> groupByColor(List<DogDO> dogDOList) {
Map<String, List<DogDO>> map = new HashMap<>();
if (dogDOList == null || dogDOList.isEmpty()) {
return map;
}
for (DogDO dogDO : dogDOList) {
if (dogDO == null) {
continue;
}
if (!map.containsKey(dogDO.getColor())) {
map.put(dogDO.getColor(), new ArrayList<>());
}
map.get(dogDO.getColor()).add(dogDO);
}
return map;
}
// {white=[DogDO{name='Shaun', age=18}, DogDO{name='Spring', age=19}], yellow=[DogDO{name='Timmy', age=20}]}

Lambda 写法

1
2
3
public Map<String, List<DogDO>> groupByColor1(List<DogDO> dogDOList) {
return Optional.ofNullable(dogDOList).orElse(Collections.emptyList()).stream().filter(Objects::nonNull).collect(Collectors.groupingBy(DogDO::getColor));
}

聚合查询

取集合中年龄最大的两只狗

1
2
List<DogDO> top2Dogs = Optional.ofNullable(dogDOList).orElse(Collections.emptyList()).stream().filter(Objects::nonNull)
.sorted(Comparator.comparingInt(DogDO::getAge)).limit(2).collect(Collectors.toList());

更多聚合查询见:Java8之22个lambda表达式用法入门示例超简单,这还不会你就out了

参考

JAVA8之妙用Optional解决判断Null为空的问题

干货,一文彻底搞懂 Java 的 Optional

Java8之22个lambda表达式用法入门示例超简单,这还不会你就out了

Java 中的 Lambda List 转 Map 的多种方法详解