上周学了方法引用基础。今天深入学习数组引用、方法引用组合操作,以及在博客项目中用方法引用让 Stream 代码更加优雅。
一、数组引用
数组也有构造器引用,语法是 Type[]::new:
// IntFunction<int[]>: (n) -> new int[n]
IntFunction<int[]> intArray = int[]::new;
int[] numbers = intArray.apply(5); // [0, 0, 0, 0, 0]
最常用的场景:Stream.toArray()
List<String> words = Arrays.asList("Java", "Lambda", "Stream");
// Lambda 写法
String[] array1 = words.stream().toArray(n -> new String[n]);
// 方法引用写法
String[] array2 = words.stream().toArray(String[]::new);
// 结果: ["Java", "Lambda", "Stream"]
二维数组引用
IntFunction<int[][]> matrix = int[][]::new;
int[][] m = matrix.apply(2); // int[2][]
二、方法引用组合
方法引用可以和函数式接口的 andThen、compose、and、or 等方法组合使用。
Function.andThen
Function<String, Integer> parseInt = Integer::parseInt;
Function<Integer, String> toHex = Integer::toHexString;
// 先 parseInt,再 toHexString
Function<String, String> compose = parseInt.andThen(toHex);
compose.apply("255"); // "ff"
Predicate.and / or
Predicate<String> isLong = s -> s.length() > 4;
Predicate<String> startsWithJ = s -> s.startsWith("J");
Predicate<String> combined = isLong.and(startsWithJ);
List<String> words = Arrays.asList("Java", "Lambda", "JavaScript");
words.stream()
.filter(combined) // 长度>4 且 以J开头
.collect(toList()); // ["JavaScript"]
BinaryOperator 组合
BinaryOperator<Integer> max = Integer::max;
List<Integer> nums = Arrays.asList(3, 7, 2, 9, 1);
int maxVal = nums.stream().reduce(0, max); // 9
三、博客项目进阶重构
1. 提取所有标签(flatMap + List::stream)
// 重构前
List<String> allTags = blogs.stream()
.flatMap(blog -> blog.getTags().stream())
.distinct()
.sorted()
.collect(toList());
// 重构后
List<String> allTags = blogs.stream()
.map(BlogPost::getTags)
.flatMap(List::stream)
.distinct()
.sorted()
.collect(toList());
// 结果: [API, Docker, Java8, Lambda, Optional, Stream, ...]
2. 标签词云(统计出现次数)
Map<String, Long> tagCloud = blogs.stream()
.map(BlogPost::getTags)
.flatMap(List::stream)
.collect(Collectors.groupingBy(s -> s, Collectors.counting()));
// 结果: {Java8=4, Lambda=2, Stream=1, ...}
3. 按分类获取标题列表
Map<String, List<String>> byCategory = blogs.stream()
.collect(Collectors.groupingBy(
BlogPost::getCategory,
Collectors.mapping(BlogPost::getTitle, Collectors.toList())
));
// 结果: {Java=[Lambda 入门, Stream 详解, ...], 前端=[Vue3 API], ...}
4. 热门/普通文章分类
Map<Boolean, List<BlogPost>> hotSplit = blogs.stream()
.collect(Collectors.partitioningBy(BlogPost::isHot));
System.out.println("热门文章: " + hotSplit.get(true).size() + " 篇");
System.out.println("普通文章: " + hotSplit.get(false).size() + " 篇");
5. 格式化输出
// 重构前
blogs.stream()
.filter(blog -> blog.isPublished())
.map(blog -> blog.formatSummary())
.forEach(summary -> System.out.println(summary));
// 重构后
blogs.stream()
.filter(BlogPost::isPublished)
.map(BlogPost::formatSummary)
.forEach(System.out::println);
四、运行结果
=== 数组引用 ===
int[5]: [0, 0, 0, 0, 0]
toArray(String[]::new): [Java, Lambda, Stream]
int[2][3]: 2 行
=== 方法引用组合 ===
parseInt.andThen(toHexString): ff
length>4 且以J开头: [JavaScript]
Integer::max 求最大值: 9
=== 博客项目进阶重构 ===
所有标签: [API, Docker, Java8, Lambda, Optional, Stream, Vue, 前端, 基础, 空指针, 进阶, 部署, 集合]
标签词云: {Java8=4, Lambda=2, 基础=2, ...}
分类标题: {Java=[Lambda 入门, Stream 详解, 方法引用, Optional 实践], 运维=[Docker 部署], 前端=[Vue3 API]}
热门文章: 2 篇
普通文章: 4 篇
[Java] Lambda 入门 (200 阅读)
[Java] Stream 详解 (350 阅读)
[前端] Vue3 API (180 阅读)
[Java] 方法引用 (120 阅读)
[Java] Optional 实践 (300 阅读)
五、方法引用速查表
| Lambda 写法 | 方法引用写法 |
|---|---|
s -> s.length() | String::length |
s -> s.toUpperCase() | String::toUpperCase |
s -> Integer.parseInt(s) | Integer::parseInt |
() -> System.currentTimeMillis() | System::currentTimeMillis |
x -> System.out.println(x) | System.out::println |
() -> new ArrayList<>() | ArrayList::new |
s -> new StringBuilder(s) | StringBuilder::new |
n -> new int[n] | int[]::new |
blog -> blog.getTitle() | BlogPost::getTitle |
blog -> blog.isPublished() | BlogPost::isPublished |
list -> list.stream() | List::stream |
六、本周学习总结
第七周我们学习了方法引用与构造器引用,完整路线:
周二:方法引用::: 双冒号的四种用法
周四:构造器引用 & 数组引用 & 方法引用组合(本篇)
周六:重构博客项目:方法引用让代码更简洁
核心收获:
| 方法引用类型 | 语法 | 适用场景 |
|---|---|---|
| 对象::实例方法 | obj::method | Lambda 调用已有对象的方法 |
| 类::静态方法 | Class::staticMethod | Lambda 调用类的静态方法 |
| 类::实例方法 | Class::instanceMethod | Lambda 的第一个参数是调用者 |
| 类::new | Class::new | Lambda 只创建一个对象 |
| 数组::new | Type[]::new | 创建数组,最常用在 toArray() |
关键原则:
- 方法引用不是新功能,只是 Lambda 的语法糖
- 只在 Lambda 体只做一件事时使用
- 可读性优先,不要为了用方法引用而用
七、下周预告
第八周进入 默认方法 & 静态接口方法,了解接口如何拥有方法体,以及多继承冲突如何解决。
系列文章导航:
更多请关注我的微信公众号,感谢!