前言:针对与jdk1.8的新特性(流),java.util.function包下的函数式接口的学习是必不可少的。lambda表达式的入参除了普通的入参,大部分都是以lambda表达式作为方法的入参。如{(a, b) -> a + b}。本文通过我对部分函数式接口的理解以及自我测试,总结出部分函数式接口的基本使用方式。
Java 8 中的 Streams API 详解 新手入门可观看Stream使用详解以及Stream的介绍。
函数式接口
Function
jdk1.8介绍
@FunctionalInterface
public interface Function
表示接受一个参数并产生结果的函数。
这是一个functional interface的功能方法是
apply(Object)
。
T -> 函数接收参数的类型
R -> 函数返回结果的类型
// TODO 接收T类型的参数,返回R类型的结果
R apply(T t); // Function默认的调用方式
Function<Object, String> function = (s) -> {
return s.toString().UpperCase();
}
function.apply("function");
// 输出结果:"FUNCTION"
UnaryOperator
jdk1.8介绍
@FunctionalInterface
public interface UnaryOperator
extends Function<T,T>
表示对单个操作数产生与其操作数相同类型的结果的操作。对于操作数和结果是相同类型的情况,这是Function的
Function
。这是一个functional interface的功能方法是
Function.apply(Object)
。
// TODO 接收T类型的参数,返回T类型的结果
T apply(T t); // UnaryOperator 默认的调用方式
// TODO 接收一个String类型的参数,返回一个String类型的值。既是生产者又是消费者
UnaryOperator<String> unaryOperator = (s) -> {
return s.trim().toUpperCase();
}
unartOperator.apply(" test "); // 输出结果:"TEST";
BiFunction
jdk1.8介绍
@FunctionalInterface
public interface BiFunction
表示接受两个参数并产生结果的函数。这是
Function
的二元专业化 。这是一个functional interface的功能方法是
apply(Object, Object)
。
T -> 函数接收第一个参数的类型
U -> 函数接收第二个参数的类型
R -> 函数返回结果的类型
// TODO 接收T类型和U类型的参数,返回R类型的结果
R apply(T t, U u); // BiFunction 默认的调用方式
// TODO 打印输入两个参数的字符长度
BiFunction<Object, String, Integer> biFunction = (s1, s2) -> {
return s1.toString().length() + s2.length();
};
Integer result = biFunction.apply("woshi", "xiaohei");
System.out.println(result); // 输出结果:12
BinaryOperator
jdk1.8介绍
@FunctionalInterface
public interface BinaryOperator
extends BiFunction
表示对同一类型的两个操作数的操作,产生与操作数相同类型的结果。对于操作数和结果都是相同类型的情况,这是BiFunction的专业化 。
这是一个functional interface的功能方法是
BiFunction.apply(Object, Object)
。
// TODO 接收两个T类型的参数,返回T类型的结果
T apply(T t1, T t2); // BinaryOperator 默认的调用方式
// TODO 例子:拼接接收的两个String参数
BinaryOperator<String> binaryOperator = (s1, s2) -> s1 + s2;
String result = binaryOperator.apply("a", "b");
// 输出结果:“ab”;
从接口的定义来说,BiFunction比Function多了一个入参,也使得BiFunction在一些业务场景上更灵活些。但其实本质上,他们的调用方式都是使用apply()进行调用
Predicate
jdk1.8介绍
@FunctionalInterface
public interface Predicate
表示一个参数的谓词(布尔值函数)。
这是一个functional interface的功能方法是
test(Object)
。
简述:Predicate表达式 <==> 逻辑判断语句
// TODO 接收T类型参数,返回boolean类型的结果
boolean test(T t); // Predicate 默认的调用方式
// TODO Predicate接收返回boolean类型的逻辑表达式。
Predicate predicate = pre -> "aa".equals(pre);
boolean result = predicate2.test("aa");
System.out.println(result);
Supplier
jdk1.8介绍
@FunctionalInterface
public interface Supplier
代表结果供应商。
没有要求每次调用供应商时都会返回新的或不同的结果。
这是一个functional interface的功能方法是
get()
。
// Teacher{"name":"", "school":"", "subject":""}
// TODO 使用Supplier函数式接口创建一个默认的Teacher对象。
// TODO 不接受任何参数,但是返回一个类型的对象。 ==> 生产者
Supplier<Teacher> teacherSupplier = () -> {
Teacher t = new Teacher();
t.setName("张三");
t.setSchool("某市一中");
t.setSubject("语文");
return t;
}
// 获取一个默认的Teacher对象。
// 默认信息为Teacher{"name":"张三", "school":"某市一中", "subject":"语文"}
teacherSupplier.get();
// 使用Teacher::new创建Supplier<Teacher>对象。
Supplier<Teacher> teacherSupplier2 = Teacher::new;
// teacherSupplier2.get() 获取到的Teacher对象默认信息为null
teacherSupplier2.get();
Consumer
jdk1.8介绍
@FunctionalInterface
public interface Consumer
表示接受单个输入参数并且不返回结果的操作。与大多数其他功能界面不同, Consumer预计将通过副作用进行操作。
这是一个functional interface的功能方法是
accept(Object)
。
// TODO 接收T类型
void accept(T t); // Consumer 默认的调用方式
// TODO Consumer :该函数式接口接收一个参数,但不返回任何类型的值。==>消费者
Consumer<String> consumer = (s) -> {
System.out.println(s.trim().toUpperCase());
}
consumer.accept(" consumer ");
// 输出结果:"CONSUMER"
函数式接口总结
接口 | 参数 | 返回类型 | 调用方法 | 描述 |
---|---|---|---|---|
Predicate |
T | boolean | test(T t) | 默认接收返回boolean参数类型的值 |
BinaryOperator |
T | T | apply(T t1, T t2) | extends BiFunction<T, T, T>。接收两个T类型的参数,返回T类型的数据 |
Supplier |
none | T | get(); | 生产者。不接受任何参数,但是返回T类型的参数 |
Consumer |
T | none | accept(T t); | 消费者。接收T类型的参数,但是不返回任何数据 |
UnaryOperator |
T | T | apply(T t); | extends Function<T, T>。接收T类型的参数,返回T类型的数据 |
Function<T, R> | T | R | apply(T t); | 接收T类型的参数,返回R类型的数据 |
BiFunction<T, U, R> | T, U | R | apply(T t, U u) | 接收T类型和U类型的两个参数,返回R类型的结果 |
总结:通过对上述的函数式接口的定义和调用方式,来达到对函数式接口的认识,也希望这篇文档能帮助读者了解lambda表达式和函数式接口。理解有误的地方麻烦指正,谢谢。