一.什么是函数式接口
最近在开发过程中,发现许多Java8新特性的应用及其广泛,很多代码如果不了解这些知识是看不懂的,所以打算总结一下。
- 函数式接口(Functional Interface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。
- 函数式接口可以被隐式转换为 lambda 表达式
lambda表达式介绍: lambda表达式介绍
代码示例:
@FunctionalInterface
interface GreetingService
{
void sayMessage(String message);
}
目前个人理解:函数式接口其实就是一种接口而已,为什么它如此特殊是因为它只有一个抽象方法,方便我们用Lambda表达式等方式来写代码
比如上面的接口可以这样使用:
GreetingService greetService1 = message -> System.out.println("Hello " + message);
二.四大函数式接口
java.util.function 它包含了很多类,用来支持 Java的 函数式编程,其中有许多函数式接口,但是比较基本比较常用的有四种,分别是Function,Consumer,Predicate,Supplier。下面就让我们一起来学习一下
附常见的泛型类型:
使用大写字母A,B,C,D......X,Y,Z定义的,就都是泛型,把T换成A也一样,这里T只是名字上的意义而已
? 表示不确定的java类型
T (type) 表示具体的一个java类型
K V (key value) 分别代表java键值中的Key Value
E (element) 代表Element
1.Function功能型函数式接口
表示接受一个参数并产生结果的函数
@FunctionalInterface
public interface Function<T, R> {
/**
* 接收一个参数,进行操作后将结果返回
*/
R apply(T t);
/**
* 返回一个 先执行before函数对象apply方法,再执行当前函数对象apply方法的 函数对象
*/
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
/**
* 返回一个 先执行当前函数对象apply方法, 再执行after函数对象apply方法的 函数对象
*/
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
/**
* 返回一个执行了apply()方法之后只会返回输入参数的函数对象
*/
static <T> Function<T, T> identity() {
return t -> t;
}
}
可以看出来Function接口的核心就是apply这个方法。
代码示例:
public class FunctionDemo {
static int calValue(int value, Function<Integer, Integer> function) {
return function.apply(value);
}
public static void main(String[] args) {
int value = 10;
//lambda表达式
int res = calValue(value, (x) -> {return value + 10;});
System.out.println(res);
}
}
calValue作为类的静态方法,传入一个Function接口作为参数,返回值是经过函数计算的结果。在main方法中用lambda表达式实现了这个接口,这样让函数的扩展性更强了。
2.Predicate断言型函数式接口
接受一个输入参数,返回一个布尔值结果。
@FunctionalInterface
public interface Predicate<T> {
/**
* 评估当前参数
*/
boolean test(T t);
/**
* 对应了java的连接符号&&
*/
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
/**
* 对应了java的连接符号!
*/
default Predicate<T> negate() {
return (t) -> !test(t);
}
/**
* 对应了java的连接符号||
*/
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);
}
}
除了主要的抽象方法test外,另外三个方法其实都是用于逻辑判断的,可以让我们对断言进行排列组合,方便编程
int[] numbers= {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
List<Integer> list=new ArrayList<>();
for(int i:numbers) {
list.add(i);
}
Predicate<Integer> p1=i->i>5;
Predicate<Integer> p2=i->i<20;
Predicate<Integer> p3=i->i%2==0;
List test=list.stream().filter(p1.and(p2).and(p3)).collect(Collectors.toList());
System.out.println(test.toString());
/** print:[6, 8, 10, 12, 14]*/
需求是输出偶数,只需要通过stream流式编程然后定义三个Predicate进行过滤即可。
3.Consumer消费型函数式接口
代表了 接受一个输入参数并且无返回的操作
public static void modifyTheValue(int value, Consumer<Integer> consumer) {
consumer.accept(value);
}
v
public static void main(String[] args) {
// (x) -> System.out.println(x * 2)接受一个输入参数x
// 直接输出,并没有返回结果
// 所以该lambda表达式可以实现Consumer接口
modifyTheValue(3, (x) -> System.out.println(x * 2));
}
输出结果为6
4.Supplier供给型函数式接口
无参数,返回一个结果
public static String supplierTest(Supplier<String> supplier) {
return supplier.get();
}
public static void main(String args[]) {
String name = "冷冷";
// () -> name.length() 无参数,返回一个结果(字符串长度)
// 所以该lambda表达式可以实现Supplier接口
System.out.println(supplierTest(() -> name.length() + ""));
}
三.总结
函数式接口为Java赋予了函数式编程的能力。
“函数式编程"是一种"编程范式”(programming paradigm),也就是如何编写程序的方法论。它属于"结构化编程"的一种,主要思想是把运算过程尽量写成一系列嵌套的函数调用,有许多的好处。