1.前言
2.什么是函数式接口 @FunctionalInterface
@FunctionalInterface
用于函数式接口类型声明的信息注解类型,这些接口的实例被 Lambda 表达式、方法引用或者构造器引用创建。函数式接口只能有一个抽象方法,并排除接口默认方法以及声明中覆盖 Object 的公开方法的统计。同时,@FunctionalInterface 不能标注在注解、类以及枚举上。如果违背以上规则,那么接口不能视为函数式接口,当标注 @FunctionalInterface 后,会引起编译错误。
不过,如果任意接口满足以上函数式接口的要求,无论接口是否声明中是否标注 @FunctionalInterface ,均能被编译器视作函数式接口。
示例
public
class
FunctionalInterfaceDemo {
public
static
void
main(String[] args) {
Function1 function1 = ()->{
};
FunctionalInterfaceWithoutAnnotation function2 = ()->{
};
}
@FunctionalInterface
public
interface
Function1 {
void
execute();
default
String getDescription(){
return
String.valueOf(
this
);
}
}
// @FunctionalInterface 并非必选
public
interface
FunctionalInterfaceWithoutAnnotation{
void
execute();
}
}
Function1 中可以看到,如果接口中有多个方法,保留一个接口抽象方法,其他方法必须添加 default 默认实现
通过上面的例子我们似乎看到了一点点 Lambda 和 @FunctionalInterface 的联系,接下来我们将一步一步来了解 Java 8 中内置的几种函数式接口类型。
3.函数式接口类型
提供类型 - Supplier<T>
消费类型 - Consumer<T>
转换类型 - Function<T,R>
断定类型 - Predicate<T>
隐藏类型 - Action
4.举例说明
泛型类型参数命名约定
E:表示集合元素(Element)
V:表示数值(Value)
K:表示键(Key)
T:表示类型(Type)
R:表示结果(Result)
S:表示来源(Source)
4.1 Supplier<T>
读音 /səˈplaɪər/
4.1.1 Supplier 接口定义
基本特点:只出不进
编程范式:作为方法/构造参数、方法返回值
使用场景:数据来源,代码替代接口
4.1.2 Supplier 接口源码
@FunctionalInterface
public
interface
Supplier<T> {
T get();
}
4.1.3 示例
public
class
SupplierDemo {
public
static
void
main(String[] args) {
Supplier<Long> supplier = getLong();
System.out.println(supplier.get());
}
/**
* 第一种写法
* @return
*/
public
static
Supplier<Long> getLong(){
return
()->{
return
System.currentTimeMillis();
};
}
/**
* 第二种写法
* @return
*/
public
static
Supplier<Long> getLongOther(){
return
System::currentTimeMillis;
}
}
4.1.4 设计
普通版本
public
class
SupplierDesignDemo {
public
static
void
main(String[] args) {
ehco(
"Hello,World"
);
}
public
static
void
ehco(String message) {
System.out.println(message);
}
}
Supplier+Lambda 表达式
private
static
void
level2() {
Supplier<String> supplyMessage = () -> {
return
"lambda-Hello,World"
;
};
ehco(supplyMessage.get());
}
Supplier 作为 ehco 方法参数
private
static
void
level3() {
ehco(SupplierDesignDemo::getMessage);
}
public
static
void
ehco(Supplier<String> message) {
System.out.println(message.get());
}
public
static
String getMessage() {
return
"lazy-Hello,World"
;
}
执行区别
private
static
void
level4() {
getMessage();
//及时执行
Supplier<String> message = supplyMessage();
//待执行状态
message.get();
//实际执行
}
4.1.5 中台2.0设计
public
Stream<RealtimeVideoWarning> realtimeWarningOf(Supplier<RealtimeVideoWarning> supplier,
Map<String, List<String>> typeTaskIdMap, Map<String, String> strategyTypeMap) {
return
typeTaskIdMap
.entrySet()
.stream()
.map(entry -> {
// 实际执行
RealtimeVideoWarning warning = supplier.get();
warning.setStrategyTypeId(entry.getKey());
warning.setStrategyTypeName(strategyTypeMap.get(entry.getKey()));
warning.setAlarmStrategyIds(entry.getValue());
return
warning;
});
}
调用代码
capture::toWarning 为 Supplier 模式+返回值 RealtimeVideoWarning
public
Stream<RealtimeVideoWarning> build(ResultService service) {
// toWarning构造告警数据,warningOf为每条告警记录设置strategyType和alarmStrategyIds
Stream<RealtimeVideoWarning> warnings = service
.realtimeWarningOf(capture::toWarning, typeTaskIdMap, strategyTypeMap);
// 实时车牌识别
if
(compare !=
null
) {
Stream<RealtimeVideoWarning> warningsLicense = service
.warningOf(capture::toWarning, compare, strategyTypeMap);
warnings = Stream.concat(warnings, warningsLicense);
}
原始写法
private
RealtimeVideoCapture capture;
public
Stream<RealtimeVideoWarning> realtimeWarningOf(
Map<String, List<String>> typeTaskIdMap, Map<String, String> strategyTypeMap) {
return
typeTaskIdMap
.entrySet()
.stream()
.map(entry -> {
RealtimeVideoWarning warning = capture.toWarning();
warning.setStrategyTypeId(entry.getKey());
warning.setStrategyTypeName(strategyTypeMap.get(entry.getKey()));
warning.setAlarmStrategyIds(entry.getValue());
return
warning;
});
}
看起来好像原始写法更简单些,也容易理解,那么 Supplier 优势在哪里?
Supplier 这种设计的优势在于 Supplier 作为一个参数传递进来,Supplier 的具体方法的实现可以非常灵活,只要是这种 Supplier 模式,并且返回值是 RealtimeVideoWarning 就可以;而原始写法这个地方是写死的,即使是用设计模式,这个地方可能也要加入一定量的代码,但是用函数式设计可以很优雅。
4.1.6 Spring 5.0+
public
interface
ObjectProvider<T>
extends
ObjectFactory<T>, Iterable<T> {
T getObject(Object... args)
throws
BeansException;
@Nullable
T getIfAvailable()
throws
BeansException;
default
T getIfAvailable(Supplier<T> defaultSupplier)
throws
BeansException {
T dependency = getIfAvailable();
return
(dependency !=
null
? dependency : defaultSupplier.get());
}
...
使用
ObjectProvider<User> beanProvider = applicationContext.getBeanProvider(User.
class
);
System.out.println(beanProvider.getIfAvailable(User::createUser));
运来这一步可能使用 beanFactory.getBean(User.class)
直接获取 Spring IoC 容器中的 User 对象,如果容器中没有就会报错;但是使用 beanProvider.getIfAvailable(User::createUser)
,相当于给了一个默认值(方法),如果容器没有的话就使用 User::createUser
来创建 User 对象,并返回。
4.2 Consumer<T>
4.2.1 Consumer<T> 接口定义
基本特点:只进不出
编程范式:作为方法/构造参数
使用场景:执行 Callback
4.2.2 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); };
}
}
普通版本
public
static
void
level1() {
System.out.println(
"xwf"
);
}
Consumer
public
static
void
level2() {
Consumer<String> consumer = System.out::println;
consumer.accept(
"xwf"
);
}
自定义方法
public
static
void
level3() {
Consumer<String> consumer = ConsumerDemo::echo;
consumer.accept(
"xwf"
);
}
public
static
void
echo(String str) {
System.out.println(
"echo1:"
+ str);
}
Consumer#andThen
public
static
void
displayAndThen() {
Consumer<String> consumer2 = ConsumerDemo::echo2;
Consumer<String> consumer3 = ConsumerDemo::echo3;
Consumer<String> consumer1 = ConsumerDemo::echo;
// Fluent API
consumer1.andThen(consumer2).andThen(consumer3).accept(
"xwf"
);
}
public
static
void
echo(String str) {
System.out.println(
"echo1:"
+ str);
}
public
static
void
echo2(String str) {
System.out.println(
"echo2:"
+ str);
}
public
static
void
echo3(String str) {
System.out.println(
"echo3:"
+ str);
}
执行结果
echo1:xwf
echo2:xwf
echo3:xwf
4.2.3 Spring
public
interface
ObjectProvider<T>
extends
ObjectFactory<T>, Iterable<T> {
...
default
void
ifAvailable(Consumer<T> dependencyConsumer)
throws
BeansException {
T dependency = getIfAvailable();
if
(dependency !=
null
) {
dependencyConsumer.accept(dependency);
}
}
...
T 作为参数传递给 Consumer,然后来执行
beanProvider.ifAvailable(System.out::println);
4.3 Function<T,R>
4.3.1 Function<T,R> 接口定义
基本特点:有进有出
编程范式:作为方法/构造参数
使用场景:类型转换、业务处理等
4.3.2 源码
将类型 T 转化为类型 R
@FunctionalInterface
public
interface
Function<T, R> {
R apply(T t);
default
<V> Function<V, R> compose(Function<?
super
V, ?
extends
T> before) {
Objects.requireNonNull(before);
return
(V v) -> apply(before.apply(v));
}
default
<V> Function<T, V> andThen(Function<?
super
R, ?
extends
V> after) {
Objects.requireNonNull(after);
return
(T t) -> after.apply(apply(t));
}
static
<T> Function<T, T> identity() {
return
t -> t;
}
}
4.3.3 示例
public
class
FunctionalDemo {
public
static
void
main(String[] args) {
displayCompose();
}
/**
* String -> Integer
*/
public
static
void
level1() {
Function<String, Integer> function = Integer::valueOf;
Integer res = function.apply(
"1"
);
System.out.println(res);
}
/**
* Long -> String
*/
public
static
void
level2() {
Function<Long, String> function = String::valueOf;
String res = function.apply(13L);
System.out.println(res);
}
/**
* compose
*/
public
static
void
displayCompose() {
Function<String, Integer> function = Integer::valueOf;
// 1 -> "1" -> 1
Integer value = function.compose(String::valueOf).apply(
1
);
System.out.println(value);
}
}
典型应用
<R> Stream<R> map(Function<?
super
T, ?
extends
R> mapper);
示例
class
User {
private
String name;
private
Integer age;
public
User(String name, Integer age) {
this
.name = name;
this
.age = age;
}
public
User() {
}
public
String getName() {
return
name;
}
public
void
setName(String name) {
this
.name = name;
}
public
Integer getAge() {
return
age;
}
public
void
setAge(Integer age) {
this
.age = age;
}
public
static
List<User> getUsers() {
List<User> users =
new
ArrayList<>();
for
(
int
i =
0
; i <
10
; i++) {
users.add(
new
User(
"person"
+ i, i));
}
return
users;
}
}
将 User 集合转化成 User 的 name 集合,通过 map(User::getName)
。
private
static
void
map() {
List<String> userNames = User.getUsers().stream().map(User::getName)
.collect(Collectors.toList());
System.out.println(userNames);
}
执行结果
[person0, person1, person2, person3, person4, person5, person6, person7, person8, person9]
4.3.4 中台2.0分页
public
class
Page<T> {
private
final
long
pageNo;
private
final
long
pageSize;
private
final
long
totalPage;
private
final
long
totalRecords;
private
final
long
showPage;
private
final
long
showRecords;
private
final
List<T> records;
public
<U> Page<U> map(Function<T, U> function) {
return
new
Page<>(
this
.pageNo,
this
.pageSize,
this
.totalPage,
this
.totalRecords,
this
.showPage,
this
.showRecords,
this
.records
.stream()
.map(function)
.collect(toList())
);
}
}
将 Stream 的 map 方法嫁接到 Page 中使用。
public
Page<CameraPageVo> queryCameraAll(CameraQueryAllRequest request) {
PageUtil.PageBuilder pageBuilder = PageUtil.of(request.getPageNo(), request.getPageSize());
ISelect select = adminSearch(request);
Page<WeekendSqlDemo.Camera> page = pageBuilder.doSelect(select,
"create_time desc"
);
return
page.map(camera -> {
CameraPageVo vo =
new
CameraPageVo();
BeanUtils.copyProperties(camera, vo);
return
vo;
});
}
将 Dto 转成 Vo。
4.3.5 Spring
org.springframework.core.convert.converter.Converter
public
interface
Converter<S, T> {
T convert(S source);
}
4.4 Predicate<T>
4.4.1 Predicate<T>接口定义
基本特点:有进有出
编程范式:作为方法/构造参数
使用场景:类型转换、业务处理等
4.4.2 源码
@FunctionalInterface
public
interface
Predicate<T> {
boolean
test(T t);
default
Predicate<T> and(Predicate<?
super
T> other) {
Objects.requireNonNull(other);
return
(t) -> test(t) && other.test(t);
}
default
Predicate<T> negate() {
return
(t) -> !test(t);
}
default
Predicate<T> or(Predicate<?
super
T> other) {
Objects.requireNonNull(other);
return
(t) -> test(t) || other.test(t);
}
static
<T> Predicate<T> isEqual(Object targetRef) {
return
(
null
== targetRef)
? Objects::isNull
: object -> targetRef.equals(object);
}
}
4.4.3 示例
public
class
PredicateDemo {
public
static
void
main(String[] args) {
Predicate<File> predicate = FileFilter::accpet;
System.out.println(predicate.test(
new
File(
"/aaa"
)));
}
static
class
FileFilter {
static
boolean
accpet(File path) {
return
true
;
}
}
}
典型应用
Stream<T> filter(Predicate<?
super
T> predicate);
4.4.4 设计
public
class
PredicateDesignDemo {
public
static
void
main(String[] args) {
List<Integer> numbers = Arrays.asList(
1
,
2
,
3
,
4
,
5
);
Collection<Integer> even = filter(numbers, PredicateDesignDemo::condition);
even.forEach(System.out::println);
}
private
static
boolean
condition(Integer number) {
if
(number %
2
==
0
) {
return
false
;
}
else
{
return
true
;
}
}
private
static
<E> Collection<E> filter(Collection<E> source, Predicate<E> predicate) {
// 集合类操作,请不要直接利用参数
List<E> copy =
new
ArrayList<>(source);
Iterator<E> iterator = copy.iterator();
while
((iterator).hasNext()) {
E element = iterator.next();
if
(predicate.test(element)) {
iterator.remove();
}
}
return
Collections.unmodifiableList(copy);
}
}
以上代码等同于
List<Integer> collect = Stream.of(
1
,
2
,
3
,
4
,
5
).filter(num -> {
return
num %
2
==
0
;
}).collect(Collectors.toList());
4.5 Action
4.5.1 示例
public
class
ActionDemo {
public
static
void
main(String[] args) {
Runnable runnable =
new
Runnable() {
@Override
public
void
run() {
System.out.println(
"Hello,World"
);
}
};
// invokedynamic 指令 @since jdk 1.7
// java.lang.invoke.MethodHandle
// java.lang.invoke.InvokeDynamic
Runnable runnable2 = () -> {
System.out.println(
"Hello,World"
);
};
runnable.run();
}
}
5.总结
综上所述,函数式接口就是将我们一些特殊的接口方法进行了分类,根据方法参数和返回值来确定属于哪一类型
提供类型 - Supplier<T>
消费类型 - Consumer<T>
转换类型 - Function<T,R>
断定类型 - Predicate<T>
隐藏类型 - Action
示例
public
class
LambdaDemo {
public
static
void
main(String[] args) {
// 只出不进
Supplier<String> supplier = LambdaDemo::getMessage;
// 只进不出
Consumer<String> consumer = LambdaDemo::printlnMessage;
// 有进有出
Function<Integer,String> function = LambdaDemo::integerToString;
// 有进有出+判断
Predicate<Integer> predicate = LambdaDemo::existNumber;
// Action 隐藏类型 不进不出
Runnable runnable = ()->{
};
}
public
static
String getMessage() {
return
"xwf"
;
}
public
static
void
printlnMessage(String msg) {
System.out.println(msg);
}
public
static
String integerToString(Integer number) {
return
String.valueOf(number);
}
public
static
Boolean existNumber(Integer number) {
return
true
;
}
}
应用场景
函数式接口提供 lambda 表达式和方法引用的目标类型
函数式接口可以匹配或适配为 lambda 表达式的参数和返回类型
将函数式接口作为方法的参数来进行使用,增加程序设计的灵活性