参考链接 Java 函数式编程
基本概念
函数式接口:只含有一个抽象方法的接口。
@FunctionalInterface 接口声明:表示这是一个函数式接口,修改接口时编译器将会检查是否符合函数式接口规则。
方法引用: 形如构造器方法引用 Customer::new 或者普通方法 customer::pay (前面Customer是Java类,后者customer是实例),这种写法被称为方法引用。
方法引用遵循一般方法调用规则(构造器方法引用固定为::new),如 静态方法可以直接经由类名调出,普通方法须由实例调出。
Lambda 表达式:形如 (p1, p2)-> { expression } 的code形式被称为 Lambda 表达式,这种形式是对函数式接口的快速实现。
最繁琐写法: (Class1 p1, Class2 p2)-> { expression }
省略类型写法:(p1, p2)-> { expression }
一个参数时省略小括号写法 p -> { expression }
实现方法只有一句时去掉花括号: p -> expression
代码分析
来看一段代码
List<String> list = new ArrayList<>();
list.forEach(System.out::println);
焦点在 System.out::println ,原貌是这样的:
(String s) -> System.out.print(s)
分析:
ArrayList forEach 方法源码:
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
看看 Consumer 接口定义:
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
}
看出没,Consumer 接口是一个函数式接口,唯一抽象方法 accept 接受一个任意对象,返回为空,而表达式
(String s) -> System.out.print(s)
就是对这个接口的实现,回到 forEach 方法,看到 for 循环中 调用此方法:
action.accept(t);
介绍两个有意思的小工具
● optional
java.util.Optional 一个容器对象,用于容纳非空对象。常见于 JPA 查询 (如默认方法 findById)中。这里有一些有趣的方法:
- isPresent() 返回boolean,判断目标对象是否为空。
- get() 如果目标对象存在,则返回该对象,否则报错。
- ifPresent(Consumer<? super T> consumer) 如果目标对象存在,则执行传入的方法。
- empty() 返回一个空的optional对象
- 更多详情参见官方手册 Java 8 Optional
● stream
Java 8 特性之一,流处理技术,stream对象代表了来自某个源的对象的序列。生成方法:
- collection.stream() 产生最常见的连续流
- collection.parallelStream() 返回支持多核处理的并行流
stream对象一些有意思的处理方法:
- forEach(Consumer<? super T> action) 遍历流中的数据
- map(Function<? super T, ? extends R> mapper) 进行唯一遍历,相同元素只遍历一次
- filter(Predicate<? super T> predicate) 返回符合过滤条件的元素组成的流
- limit(long maxSize) 限制流的大小
- sorted(Comparator<? super T> comparator) 对元素进行排序,不输入排序方法则使用默认排序
结束流:
- collect(Collector collector) 使用 java.util.stream.Collectors 可以快速收集元素,如 toList 、toSet 等,例:
ArrayList<Integer> numbers = new ArrayList<>();
numbers.add(1);
List<Integer> collect = numbers.stream().map(n -> {
System.out.println(n);
return n;
}).collect(Collectors.toList());
统计:
- mapToInt(n -> n).summaryStatistics() 由普通流转化为整型流,并得到统计数据,例:
ArrayList<Integer> numbers = new ArrayList<>();
numbers.add(1);
IntSummaryStatistics statistics = numbers.stream().mapToInt(n -> n).summaryStatistics();
System.out.println(statistics.getMax()); // 最大值
System.out.println(statistics.getSum()); // 总和