Java8中的流式处理,让集合操作变得简单,通常需要用多行代码才能完成的操作,而使用Lambda表达式处理可能仅需要一行代码即可实现。比如,如果我们对一个整数的集合,需要挑选出3的倍数,然后将其组装成一个集合返回。在Java8之前,需要这样做
public class Test {
public static void main(String[] args) {
// 初始化数据
List<Integer> numList = new ArrayList<Integer>() {
{
add(1);
add(2);
add(3);
add(4);
add(5);
add(6);
}
};
// 最终返回的结果集合
List<Integer> result = new ArrayList<>();
// 筛选3的倍数
for (Integer num : numList) {
if (num % 3 == 0) {
result.add(num);
}
}
System.out.println(result);
}
}
使用Lambda表达式处理,可以这么写
public class Test {
public static void main(String[] args) {
// 初始化数据
List<Integer> numList = new ArrayList<Integer>() {
{
add(1);
add(2);
add(3);
add(4);
add(5);
add(6);
}
};
// 使用Lambda表达式处理
List<Integer> result = numList.stream().filter(num -> num % 3 == 0).collect(Collectors.toList());
System.out.println(result);
}
}
JDK为Lambda表达式内置了非常丰富的函数式接口
函数式接口 | 描述符 | 原始类型 |
---|---|---|
Predicate<T> | T -> boolean | IntPredicate, LongPredicate, DoublePredicate |
Consumer<T> | T -> void | IntConsumer, LongConsumer, DoubleConsumer |
Funcation<T, R> | T -> R | IntFuncation<R>, IntToDoubleFunction, IntToLongFunction<R>, LongFuncation… |
Supplier<T> | () -> T | BooleanSupplier, IntSupplier, LongSupplier, DoubleSupplier |
UnaryOperator<T> | T -> T | IntUnaryOperator, LongUnaryOperator, DoubleUnaryOperator |
BinaryOperator<T> | (T, T) -> T | IntBinaryOperator, LongBinaryOperator, DoubleBinaryOperator |
BiPredicate<L, R> | (L, R) -> boolean | |
BiConsumer<T, U> | (T, U) -> void | |
BiFunction<T, U, R> | (T, U) -> R |
Lambda表达式应用(代码示例)
数据初始化(数据准备)
@AllArgsConstructor
@NoArgsConstructor
@ToString
@Data
public class Region {
/*** id */
private long id;
/*** 地区*/
private String regionName;
/*** 编码 */
private int code;
/*** 等级 */
private int level;
/*** 专业 */
private String major;
/*** 学校 */
private String school;
}
private static List<Region> regions = new ArrayList<Region>() {{
add(new Region(20160001, "南京", 20, 1, "土木工程", "南京大学"));
add(new Region(20160002, "苏州", 21, 2, "信息安全", "南京大学"));
add(new Region(20160003, "无锡", 22, 3, "经济管理", "南京大学"));
add(new Region(20160004, "常州", 21, 2, "信息安全", "南京大学"));
add(new Region(20161001, "镇江", 21, 2, "机械与自动化", "江苏大学"));
add(new Region(20161002, "南通", 23, 4, "土木工程", "江苏大学"));
add(new Region(20161003, "扬州", 23, 4, "计算机科学", "江苏大学"));
add(new Region(20162001, "泰州", 22, 3, "土木工程", "泰州学院"));
add(new Region(20162002, "淮安", 23, 4, "计算机科学", "泰州学院"));
add(new Region(20163001, "徐州", 24, 5, "土木工程", "中国矿业大学"));
}};
private static List<Integer> numbers = new ArrayList<Integer>() {{
add(1);
add(2);
add(3);
add(4);
add(5);
add(6);
add(7);
add(8);
}};
filter
// 筛选出所有南京大学的区域
List<Region> result = regions.stream()
.filter(region -> "南京大学".equals(region.getSchool()))
.collect(Collectors.toList());
distinct
// 筛选出所有不重复的偶数
List<Integer> result = numbers.stream()
.filter(num -> num % 2 == 0)
.distinct()
.collect(Collectors.toList());
limit
// 筛选出南京大学的区域,取前两个
List<Region> result = regions.stream()
.filter(region -> "南京大学".equals(region.getSchool()))
.limit(2)
.collect(Collectors.toList());
sorted
// 筛选出南京大学的区域,取前两个,并且按照等级排序
List<Region> result = regions.stream()
.filter(region -> "南京大学".equals(region.getSchool()))
.sorted(Comparator.comparingInt(Region::getLevel))
.limit(2)
.collect(Collectors.toList());
skip
// 筛选出南京大学的区域,并且按照等级排序,然后跳过前两条数据
List<Region> result = regions.stream()
.filter(region -> "南京大学".equals(region.getSchool()))
.sorted(Comparator.comparingInt(Region::getLevel))
.skip(2)
.collect(Collectors.toList());
map
// 筛选出所有专业为计算机科学的区域名称
List<String> result = regions.stream()
.filter(region -> "计算机科学".equals(region.getMajor()))
.map(Region::getRegionName)
.collect(Collectors.toList());
// 筛选出所有专业为计算机科学的区域,并计算其code之和
int result = regions.stream()
.filter(region -> "计算机科学".equals(region.getMajor()))
.mapToInt(Region::getCode)
.sum();
flatMap
String[] arr = {"java8", "is", "easy", "to", "use"};
// 输出构成这一数组的所有非重复字符
List<String[]> result = Arrays.stream(arr)
.map(str -> str.split(""))
.distinct()
.collect(Collectors.toList());
List<String> result = Arrays.stream(arr)
.map(str -> str.split(""))
.flatMap(Arrays::stream)
.distinct()
.collect(Collectors.toList());
allMatch
检测是否全部都满足指定的参数行为。
// 检测所有区域等级都是大于5
boolean allMatch = regions.stream()
.allMatch(region -> region.getLevel() > 5);
anyMatch
检测是否存在一个或多个满足指定的参数行为。
// 检测是否有南京大学的区域
boolean anyMatch = regions.stream()
.anyMatch(region -> "南京大学".equals(region.getSchool()));
noneMatch
检测是否不存在满足指定行为的元素。
// 检测是否不存在专业为计算机科学的区域
boolean noneMatch = regions.stream()
.noneMatch(region -> "计算机科学".equals(region.getMajor()));
findFirst
返回满足条件的第一个元素。
// 查找专业为土木工程且拍在第一的区域
Optional<Region> first = regions.stream()
.filter(region -> "土木工程".equals(region.getMajor()))
.findFirst();
findAny
findAny相对于findFirst的区别在于,findAny不一定返回第一个,而是返回任意一个。
// 查找专业为土木工程的任意一个区域
Optional<Region> any = regions.stream()
.filter(region -> "土木工程".equals(region.getMajor()))
.findAny();
归约
收集器提供了相应的归约操作,但是与reduce在内部实现上是有区别的,收集器更加适用于可变容器上的归约操作,这些收集器广义上均基于Collectors.reducing()实现。
// 区域总和
regions.stream().collect(Collectors.counting());
regions.stream().count();
// 区域编码的最大值和最小值
Optional<Region> maxResult = regions.stream()
.collect(Collectors.maxBy((c1, c2) -> c1.getCode() - c2.getCode()));
Optional<Region> maxResult2 = regions.stream()
.collect(Collectors.maxBy(Comparator.comparing(Region::getCode)));
Optional<Region> maxResult3 = regions.stream()
.max(Comparator.comparing(Region::getCode));
Optional<Region> minResult = regions.stream()
.min(Comparator.comparing(Region::getCode));
// 区域code之和
Integer sum = regions.stream()
.collect(Collectors.summingInt(Region::getCode));
Integer sum2 = regions.stream()
.mapToInt(Region::getCode)
.sum();
// 区域平均等级
Double average = regions.stream()
.collect(Collectors.averagingInt(Region::getLevel));
// 区域等级的最大值、最小值、平均值、总和、个数
IntSummaryStatistics statistics = regions.stream()
.collect(Collectors.summarizingInt(Region::getLevel));
// 字符串拼接
String names = regions.stream()
.map(Region::getRegionName)
.collect(Collectors.joining());
String names2 = regions.stream()
.map(Region::getRegionName)
.collect(Collectors.joining(","));
分组
// 按照学校名称分组
Map<String, List<Region>> groups = regions.stream()
.collect(Collectors.groupingBy(Region::getSchool));
// 多级分组
Map<String, Map<String, List<Region>>> groups2 = regions.stream()
// 一级分组
.collect(Collectors.groupingBy(Region::getSchool,
// 二级分组
Collectors.groupingBy(Region::getMajor)));
// 分组完后,统计每组个数
Map<String, Long> groupCount = regions.stream()
.collect(Collectors.groupingBy(Region::getSchool,
// 该参数不添加,会默认是Collectors.toList()
Collectors.counting()));
分区
分区可以看做是分组的一种特殊情况,在分区中key只有两种情况,true或false,目的是将待分区集合按照条件一分为二,Java8的流式处理利用collectors.partitioningBy()方法实现分区,该方法接收一个谓词。
// 按照学校将区域分为有南京大学的,和没有南京大学的
Map<Boolean, List<Region>> partition = regions.stream()
.collect(Collectors.partitioningBy(student -> "南京大学".equals(student.getSchool())));