函数式接口
函数式接口在Java中是指:有且仅有一个抽象方法的接口。(可以包括多个其他方法)。
修饰符 interface 接口名称 {
public abstract 返回值类型 方法名称(可选参数信息);
// 其他非抽象方法内容
}
接口当中抽象方法的public abstract
是可以省略的,所以定义一个函数式接口为:
@FunctionalInterface
public interface MyFunctionalInterface {
void myMethod();
}
注解@FunctionalInterface
,该注解用于标志该接口是一个函数式接口。
使用Lambda作为参数和返回值
Java中的Lambda表达式可以被当作是匿名内部类的替代品。如果方法的参数是一个函数式接口类型,那么可以用Lambda表达式进行替代。使用Lambda表达式作为方法参数,其实就是使用函数式接口作为方法参数。java.lang.Runable
接口就是一个函数式接口,里边只有一个run抽象方法。
public class DemoRunnable {
private static void startThread(Runnable task) {
new Thread(task).start();
}
public static void main(String[]args) {
startThread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
});
startThread(()->System.out.println(Thread.currentThread().getName()));
}
}
一个方法的返回值类型是一个函数式接口,那么就可以直接返回一个Lambda表达式。当需要通过一个方法来获取一个java.util.Comparator
接口类型的对象作为排序器时,就可以调该方法获取。
public class DemoComparator {
private static Comparator<String> newComparator() {
return (a, b) -> b.length() - a.length();
}
public static void main(String[] args) {
String[] array = {"abc", "ab", "adfc"};
System.out.println(Arrays.toString(array));
Arrays.sort(array, newComparator());
System.out.println(Arrays.toString(array));
}
}
常见的函数式接口
Supplier接口
java.util.function.Supplier<T>
接口仅包含一个无参的方法:T get()
。用来获取一个泛型参数指定类型的对象数据。这是一个函数式接口,对应的Lambda表达式需要“对外提供”一个符合泛型类型的对象数据。Supplier<T>
接口被称之为生产型接口,指定接口的泛型是什么类型,那么接口中的get
方法就会产生什么类型的数据。
public class Demo01Supplier {
//定义一个方法,方法的参数传递Supplier<T>接口,泛型执行String,get方法就会返回一个String
public static String getString(Supplier<String> sup) {
return sup.get();
}
public static void main(String[] args) {
//调用getString方法,方法的参数Supplier是一个函数式接口,所以可以传递Lambda表达式
String s = getString(()->"Java");
System.out.println(s); //Java
}
}
Consumer接口
java.util.function.Consumer<T>
接口则正好与Supplier接口相反,它不事生产一个数据,而是消费一个数据,其数据类型由泛型决定。
抽象方法:accept
Consumer接口中包含抽象方法void accept(T t)
,意为消费一个指定泛型的数据。具体怎么消费,由自己决定。
public class Demo01Consumer {
/*
定义一个方法
方法的参数传递一个字符串的姓名
方法的参数传递Consumer接口,泛型使用String
可以使用Consumer接口消费字符串的姓名
*/
public static void method(String name, Consumer<String> con) {
con.accept(name);
}
public static void main(String[] args) {
method("java",(name) -> {
//对传递的字符串进行消费
//消费方式:直接输出字符串
System.out.println(name);
//消费方式:把字符串进行反转输出
String reName = new StringBuffer(name).reverse().toString();
System.out.println(reName);
});
}
}
默认方法:andThen
如果一个方法的参数和返回值全都是Consumer类型,那么就可以实现效果:消费数据的时候,首先做一个操作,然后再做一个操作,实现组合。而这个方法就是Consumer接口中的default方法andThen。
要想实现组合,需要两个或多个Lambda表达式即可,而andThen得语义正是“一步接一步”操作。例如两个步骤组合的情况:
public class Demo01andThen {
//定义一个方法,方法的参数传递一个字符串和两个Consumer接口,Consumer接口的泛型使用字符串
public static void method(String s, Consumer<String> con1, Consumer<String> con2) {
// con1.accept(s);
// con2.accept(s);
con1.andThen(con2).accept(s);
}
public static void main(String[] args) {
method("Hello", (t)->{
//消费方式:把字符串转换为大写输出
System.out.println(t.toUpperCase());
}, (t)-> {
//消费方式:把字符串转换为小写输出
System.out.println(t.toLowerCase());
});
}
}
Predicate接口
有时候我们需要对某种类型的数据进行判断,从而得到一个boolean值结果。这时可以使用java.util.function.Predicate<T>
接口。
抽象方法:test
Predicate接口中包含一个抽象方法:boolean test(T t)。用于条件判断的场景:
public class Demo01Predicate {
public static void method(Predicate<String> pre) {
boolean veryLong = pre.test("HelloWorld");
System.out.println(veryLong);
}
public static void main(String[] args) {
method(s -> s.length() > 5);
}
}
默认方法:and
将两个Predicate
条件使用“与”逻辑连接起来实现“并且”的效果时,可以使用default方法and
。
public class Demo01Predicate_and {
public static void main(String[] args) {
method_and(s -> s.contains("H"),
s -> s.contains("W"));
}
private static void method_and(Predicate<String> one, Predicate<String> two) {
boolean isVaild = one.and(two).test("HelloWorld");
System.out.println(isVaild);
}
}
默认方法:or
默认方法or
实现逻辑关系中的“或”。
public class Demo01Predicate_and {
public static void main(String[] args) {
method_and(s -> s.contains("H"),
s -> s.contains("W"));
}
private static void method_and(Predicate<String> one, Predicate<String> two) {
boolean isVaild = one.or(two).test("HelloWorld");
System.out.println(isVaild);
}
}
默认方法:negate
实现逻辑关系中的“非”。
public class Demo01Predicate {
public static void method(Predicate<String> pre) {
//判断字符串的长度是否不大于5,相当于!test(t)
boolean veryLong = pre.negate().test("HelloWorld");
System.out.println(veryLong);
}
public static void main(String[] args) {
method(s -> s.length() > 5);
}
}
Function接口
java.util.function.Function<T, R>
接口用来根据一个类型的数据得到另一个类型的数据,前者称为前置条件,后者称为后置条件。
抽象方法:applyFunction
接口中最主要的抽象方法为:R apply(T t)
,根据类型T的参数获取类型R的结果。
public class Demo01Function {
public static void main(String[] args) {
String s = "12345";
method(s, s1 -> Integer.parseInt(s1));
}
private static void method(String s, Function<String, Integer> fun) {
Integer in = fun.apply(s);
System.out.println(in);
}
}
默认方法:andThenFunction
接口中有一个默认的andThen
方法,用来进行组合操作。该方法用于“先做什么,后做什么”的场景。
public class Demo01Function {
public static void main(String[] args) {
String s = "12345";
method(s, s1 -> Integer.parseInt(s1) + 10,
s2 -> s2 + "");
}
private static void method(String s, Function<String, Integer> fun1, Function<Integer, String> fun2) {
String in = fun1.andThen(fun2).apply(s);
System.out.println(in);
}
}