一、函数式接口说明
1、函数式接口条件
(1)、只包含一个抽象方法的接口,称为函数式接口。
(2)、你可以通过Lambda表达式来创建该接口的对象。(若Lambda表达式抛出一个受检异常,那么该异常需要在目标接口的抽象方法上进行声明)。
(3)、我们可以在任意函数式接口上使用@FunctionalInterface注解,这样做可以检查它是否是一个函数式接口,同时javadoc也会包含一条声明,说明这个接口是一个函数式接口。
2、@FunctionalInterface 注解说明
- 1.此注解表明该接口是一个函数式接口,所谓的函数式接口,是指“有且只有一个抽象方法”
- 2.接口中的静态方法,默认方法(default修饰),以及java.lang.Object类中的方法都不算抽象方法。
- 3.如果接口符合函数式接口的定义,则此注解加不加无所谓,加了会方便编译器检查。如果不符合函数式接口定义,则此注解会报错。
函数式接口其实是继承于Object的。
3、Lambda 简写/省略规则
示例:
该示例来自第二步骤
// 简写前
(Integer t) -> { return t * 2; };
// 简写后
t -> t * 2;
简写:
1、传入参数可以省略类型,如: (t) -> { return t * 2; };
2、传入参数如果只有一个,可以省略括号,如: t -> { return t * 2; };
3、返回参数没有复杂业务,一行代码可完成逻辑,可以省略 大括号+分号+ return,如: t -> { t * 2 };
缺点:
当然,Lambda表达式虽然简洁,也是有缺点的:就是降低了代码的可读性,比如一眼看不出来原来的函数式接口是什么。所以什么情况用Lambda,要多写多练才会用的恰当。
4、使用函数式接口及 Lambda 创建一个线程
// 创建线程
new Thread(() -> {
// 业务逻辑
System.out.println("666");
}).start();
// 简单业务逻辑--可简写为
new Thread(() -> System.out.println("666")).start();
可以看出 Runnable 接口是一个函数式接口,可以使用Lambda 来创建异步线程
5、四大内置函数式接口(+其他)
只包含一个抽象方法的接口,称为函数式接口。
可以通过 Lambda 表达式来创建该接口的对象。(若Lambda表达式抛出一个受检异常,那么该异常需要在目标接口的抽象方法上进行声明)。
我们可以在任意函数式接口上使用@FunctionalInterfaceFunctionalInterface注解,这样做可以检查它是否是一个函数式接口,同时 javadoc 也会包含一条声明,说明这个接口是一个函数式接口。
其他接口
二、函数式接口创建
1、创建函数式接口
@FunctionalInterface
interface Fun3 {
// 抽象方法,必须只有一个
Integer run(Integer num);
}
2、使用
(t) -> t * 2
为使用run方法实现,()中的为传递的参数,-> 后的为run 方法的实现逻辑( t * 2 )
class Test3 {
// TODO 测试
public static void main(String[] args) {
Fun3 fun3 = (t) -> t * 2;
// 调用刚定义的实现逻辑
Integer num = fun3.run(5);
System.out.println("n * 2 = " + num); // 输出10
}
}
// 简写: Fun3 fun3 = (t) -> t * 2;
--> 完整写法: Fun3 fun4 = (t) -> { return t * 2; };
三、创建类似于 forEach 的函数式接口 (函数式接口作为参数)
1、创建函数式接口
@FunctionalInterface
interface Fun<T> {
void run(T t);
}
/**
* TODO 创建类,使用函数式接口作为参数,并调用函数式接口中的 run 方法
*/
class FunClass {
public <T> void forEach(List<T> list, Fun fun) {
for (T t : list) {
fun.run(t);
}
}
}
2、使用
(t) = run(T t) 的参数 t
, 调用时 (t)
可任意命名, 但实际参数内容等于 run(T t) 的参数的 t
class Test {
// TODO 测试
public static void main(String[] args) {
ArrayList<String> lists = new ArrayList<>();
lists.add("665");
lists.add("666");
lists.add("667");
// 使用
new FunClass().forEach(lists, (t) -> {
System.out.println(t);
});
// 省略写法
new FunClass().forEach(lists, t -> System.out.println(t));
// 继续省略写法
new FunClass().forEach(lists, System.out::println);
// 输出
// 665
// 666
// 667
}
}
四、使用函数式接口进行参数转换 (固定参数类型)
1、创建函数式接口
@FunctionalInterface
interface FunConverter2<F, T> {
//加 - 使用static 关键字默认实现的方法不算抽象方法。
static double add(int a, int b) {
return a + b;
}
//减 - default 关键字默认实现的方法不算抽象方法。
default double subtract(int a, int b) {
return a - b;
}
// 抽象方法,必须只有一个,该抽象方法传入F 类型的数据,返回T类型的数据
T convert(F from);
}
2、使用
class FunConverterTest {
// TODO 测试
public static void main(String[] args) {
// 将传入的String-from,转为Integer
FunConverter2<String, Integer> converter = (from) -> Integer.valueOf(from);
Integer converted = converter.convert("123");
System.out.println(converted); // 123 整型
// 将传入的Integer-from,转为 String
FunConverter2<Integer, String> converter2 = (from) -> String.valueOf(from);
String converted2 = converter2.convert(123);
System.out.println(converted2); // 123 字符串
// 将获取传入值的2次方
FunConverter2<Integer, Integer> converter3 = (from) -> from * from;
Integer converted3 = converter3.convert(2);
System.out.println(converted3); // 4
// 将传入字符串转为小写
FunConverter2<String, String> converter4 = (from) -> from.toLowerCase();
String converted4 = converter4.convert("ABC");
System.out.println(converted4); // abc
// 将传入字符串转为大写
FunConverter2<String, String> converter5 = (from) -> from.toUpperCase();
String converted5 = converter5.convert("abc");
System.out.println(converted5); // ABC
}
}
五、使用四大接口之–函数型接口 Function<T, R> 示例
Function<T, R> 为函数型接口,T 为传入参数类型,R为返回参数类型
package interfaceTest;
import java.util.function.Function;
public class Test4 {
// 定义一个方法用于对数组求和
public static Integer getSum(int[] arr) {
int sum = 0;
for (int i : arr) {
sum += i;
}
return sum;
}
// 表示传入int数组,返回Integer
public static Integer test(Function<int[], Integer> fun, int[] arr) {
return fun.apply(arr);
}
}
class Test5 {
public static void main(String[] args) {
// Fun<Consumer<int[]>> consumerFun = Test4::test;
int[] arr = {1, 2, 4, 5, 6, 2, 3};
Integer num = Test4.test(Test4::getSum, arr);
System.out.println(num); // 23
//Function<int[], Integer> fun = Test4::getSum;
}
}