函数式编程
- 函数式编程(Functional Programming)是把函数作为基本运算单元,函数可以作为变量,可以接收函数,还可以返回函数。(参考js匿名函数)
历史上研究函数式编程的理论是Lambda演算,所以我们经常把支持函数式编程的编码风格称为Lambda表达式。
Lambda基础
(s1, s2) -> {
return s1.compareTo(s2);
}
Arrays.sort(array, (s1, s2) -> s1.compareTo(s2));
Tip
- 单方法接口被称为FunctionalInterface。
- 接收FunctionalInterface作为参数的时候,可以把实例化的匿名类改写为Lambda表达式,能大大简化代码。
方法引用
-
方法引用,指如果某个方法签名和接口恰好一致,就可以直接传入方法引用。
-
方法签名相同:即方法参数一致,返回类型相同
// 传入class Main的cmp方法
Arrays.sort(array, Main::cmp);
Tip
注意,实例方法有一个隐含的this参数
构造方法引用
public class Main {
public static void main(String[] args) {
List<String> names = List.of("Bob", "Alice", "Tim");
// 先转换为steam 然后引用Person构造方法,collect成List
List<Person> persons = names.stream().map(Person::new).collect(Collectors.toList());
System.out.println(persons);
}
}
Tip
- 构造方法隐士返回this实例
- 构造方法引用写法时 类名::new
使用Stream
| java.io | java.util.stream | |
|---|---|---|
| 存储 | 顺序读写的byte或char | 顺序输出的任意Java对象实例 |
| 用途 | 序列化至文件或网络 | 内存计算/业务逻辑 |
- 特点:流式处理的抽象序列 / 支持函数式编程和链式操作
创建Stream
- Stream.of()
Stream<String> stream = Stream.of("A", "B", "C", "D");
- 基于数组或Collection
Stream<String> stream1 = Arrays.stream(new String[] { "A", "B", "C" });
Stream<String> stream2 = List.of("X", "Y", "Z").stream();
Tip
Collection指(List、Set、Queue等)
- 基于Supplier
Stream<String> s = Stream.generate(Supplier<String> sp);
- 其他(Files类的lines()方法/pattern对象的splitAsStream())
try (Stream<String> lines = Files.lines(Paths.get("/path/to/file.txt"))) {
...
}
Pattern p = Pattern.compile("\\s+");
Stream<String> s = p.splitAsStream("The quick brown fox jumps over the lazy dog");
s.forEach(System.out::println);
- 基本类型 IntStream、LongStream和DoubleStream。
// 将int[]数组变为IntStream:
IntStream is = Arrays.stream(new int[] { 1, 2, 3 });
// 将Stream<String>转换为LongStream:
LongStream ls = List.of("1", "2", "3").stream().mapToLong(Long::parseLong);
常用方法
map / filter / reduce : 类似 js的同名方法
tip
注意reduce reduce 返回类型是Optional对象, 需要进一步判断是否存在(例如 0个元素的情况)
Optional<Integer> opt = stream.reduce((acc, n) -> acc + n);
if (opt.isPresent()) {
System.out.println(opt.get());
}
public class Main {
public static void main(String[] args) {
// 设置初始值 为 1
int s = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9).reduce(1, (acc, n) -> acc * n);
System.out.println(s); // 362880
}
}
输出集合
- 输出为List: collect()方法并传入Collectors.toList()
stream.filter(s -> s != null && !s.isBlank()).collect(Collectors.toList());
- 输出为数组 - toArray()方法
List<String> list = List.of("Apple", "Banana", "Orange");
String[] array = list.stream().toArray(String[]::new);
- 输出为map collect()方法并传入Collectors.toMap()
Stream<String> stream = Stream.of("APPL:Apple", "MSFT:Microsoft");
Map<String, String> map = stream
.collect(Collectors.toMap(
// 把元素s映射为key:
s -> s.substring(0, s.indexOf(':')),
// 把元素s映射为value:
s -> s.substring(s.indexOf(':') + 1)));
- 分组输出 collect 方法传入 Collectors.groupingBy()
public class Main {
public static void main(String[] args) {
List<String> list = List.of("Apple", "Banana", "Blackberry", "Coconut", "Avocado", "Cherry", "Apricots");
Map<String, List<String>> groups = list.stream()
.collect(Collectors.groupingBy(s -> s.substring(0, 1), Collectors.toList()));
System.out.println(groups);
}
}
Tip groupingBy需要提供两个函数:
- 一个是分组的key,这里使用s -> s.substring(0, 1),表示只要首字母相同的String分到一组,
- 第二个是分组的value,这里直接使用Collectors.toList(),表示输出为List
其他操作
-
Stream提供的常用操作有:
-
转换操作:map(),filter(),sorted(),distinct();
-
合并操作:concat(),flatMap();
-
并行处理:parallel();
-
聚合操作:reduce(),collect(),count(),max(),min(),sum(),average();
-
其他操作:allMatch(), anyMatch(), forEach()。
- sorted()
public class Main {
public static void main(String[] args) {
List<String> list = List.of("Orange", "apple", "Banana")
.stream()
.sorted()
.collect(Collectors.toList());
System.out.println(list);
}
}
List<String> list = List.of("Orange", "apple", "Banana")
.stream()
.sorted(String::compareToIgnoreCase)
.collect(Collectors.toList());
Tip
要求Stream的每个元素必须实现Comparable接口
- 去重distinct(),
List.of("A", "B", "A", "C", "B", "D")
.stream()
.distinct()
.collect(Collectors.toList()); // [A, B, C, D]
- 截取skip()/limit(),
List.of("A", "B", "C", "D", "E", "F")
.stream()
.skip(2) // 跳过A, B
.limit(3) // 截取C, D, E
.collect(Collectors.toList()); // [C, D, E]
- 合并concat(),
Stream<String> s1 = List.of("A", "B", "C").stream();
Stream<String> s2 = List.of("D", "E").stream();
// 合并:
Stream<String> s = Stream.concat(s1, s2);
System.out.println(s.collect(Collectors.toList())); // [A, B, C, D, E]
- flatMap()
- 并行parallel()
Stream<String> s = ...
String[] result = s.parallel() // 变成一个可以并行处理的Stream
.sorted() // 可以进行并行排序
.toArray(String[]::new);