目录
写在前面
本文主要是介绍jdk8自带的函数接口,默认认为读者已经了解或接触过lambda函数基础。
学习jdk8自带的函数接口,主要是为了进一步学习stream流式编程。
在 Java8 中为了让现在有的函数能够更加友好的使用 Lambda 表达式,因此引入了函数式接口这个概念。其是一个仅有一 个抽象方法的普通接口。如果声明多个抽象方法则会报错。 但是默认方法和静态方法在此接口中可以定义多个。
一、常见写法
interface Interface1 {
int doubleNum(int i);
}
public static void main(String[] args) {
Interface1 i1 = (i) -> i * 2;
Interface1 i2 = i -> i * 2;
Interface1 i3 = (int i) -> i * 2;
Interface1 i4 = (int i) -> {
System.out.println("-----");
return i * 2;
};
}
二、@FunctionalInterface注解
lambda表达式实现的接口,必须有且仅有一个要实现的方法,使用@FunctionalInterface注解标注之后,如果不符合lambda接口格式,会编译报错。
@FunctionalInterface
public interface MyFunctionalInterface {
void exec();
}
@Test
public void exec(){
//jdk8之前
demo(new MyFunctionalInterface(){
@Override
public void exec() {
System.out.println("jdk8 before");
}
});
//jdk8 lambda
demo(()-> System.out.println("jdk8 later"));
}
三、default方法
java8可以在接口中编写default默认实现的方法。
若两个接口,都有一个相同的名称、参数的default方法,两个接口被同一个类实现之后,这个类必须要重写这个default方法(编译期就会报错)。
@FunctionalInterface
interface Interface1 {
int doubleNum(int i);
default int add(int x, int y) {
return x + y;
}
}
四、jdk8自带的函数接口(重点)
在 Java8 的类库设计中,已经引入了几个函数式接口: Predicate、 Consumer 、 Function 、 Supplier,以及这几个的扩展。
jdk提供了很多基本数据类型的类,可以直接使用不需要加泛型:
1、Predicate
Predicate 接口是 Java8 定义的一个函数式接口,属于 java.util.function 包下,用于进行判断操作,内部定义一个 抽象方法test 、三个默认方法 and , negate , or 、一个静态方法isEqual。
核心方法:
boolean test(T t);
输入一个任意类型的参数,输出一个boolean类型。
// 将符合条件的学生放入集合中,并将集合最终返回
public class MyPredicateDemo {
public static List<Student> filter(List<Student> studentList, Predicate<Student> predicate){
List<Student> list = new ArrayList<>();
studentList.forEach(s->{
if (predicate.test(s)){
list.add(s);
}
});
return list;
}
public void demo(){
int port = 8086;
Runnable runnable = ()-> System.out.println(port);
}
public static void main(String[] args) {
List<Student> students = new ArrayList<>();
students.add(new Student(1,"张三","M"));
students.add(new Student(2,"李四","M"));
students.add(new Student(3,"王五","F"));
List<Student> result = filter(students, (s) -> s.getSex().equals("F"));
System.out.println(result.toString());
}
}
2、Consumer
Consumer 也是 JDK8 提供的函数式接口,用于进行获取数据 的操作,其内部定义了一个抽象方法accept 、一个默认方法 andThen。
核心方法:
void accept(T t);
输入一个任意类型的参数,无输出。
对于 accept() 方法来说,它接受一个泛型 T 对象。如果现在需要访问类型T 对象,并对其进行某些操作的话,就可以使用这 个接口。
public class MyConsumerDemo {
public static void foreach(List<String> list, Consumer<String> consumer){
list.forEach(v->consumer.accept(v));
}
public static void main(String[] args) {
List<String> arrays = new ArrayList<>();
arrays.add("java");
arrays.add("python");
arrays.add("go");
arrays.add("hive");
foreach(arrays,(s)-> System.out.println(s+","));
}
}
3、Function
Function 主要用于进行类型转换的操作。内部提供一个抽象 方法apply 、两个默认方法 compose , andThen 、一个静态 方法identity。
核心方法:
R apply(T t);
输入一个任意类型的参数,输出一个任意类型的参数。
public class MyFunctionDemo {
public static Integer convert(String value, Function<String,Integer> function){
return function.apply(value);
}
public static void main(String[] args) {
String value ="666";
Integer result = convert(value, (s) -> Integer.parseInt(value) + 222);
System.out.println(result);
}
}
4、Supplier
Supplier 也是用来进行值获取操作,内部只有一个抽象方法 get。
核心方法:
T get();
无输入参数,输出一个任意类型的参数。
public class MySupplierDemo {
public static Integer getMin(Supplier<Integer> supplier){
return supplier.get();
}
public static void main(String[] args) {
int[] arr = {100,20,50,30,99,101,-50};
Integer result = getMin(() -> {
int min = arr[0];
for (int i : arr) {
if (i < min) {
min = i;
}
}
return min;
});
System.out.println(result);
}
}
5、BiFunction
核心方法:
R apply(T t, U u);
输入两个参数,输出一个任意类型的参数。
实例
import java.text.DecimalFormat;
import java.util.function.Function;
class MyMoney {
private final int money;
public MyMoney(int money) {
this.money = money;
}
// jdk8自带的接口,Integer为入参,String为出参
public void printMoney(Function<Integer, String> moneyFormat) {
System.out.println("我的存款:" + moneyFormat.apply(this.money));
}
}
public class MoneyDemo {
public static void main(String[] args) {
MyMoney me = new MyMoney(99999999);
Function<Integer, String> moneyFormat = i -> new DecimalFormat("#,###")
.format(i);
// 函数接口链式操作
me.printMoney(moneyFormat.andThen(s -> "人民币 " + s));
}
}
// 执行结果:
// 我的存款:人民币 99,999,999
public static void main(String[] args) {
// 断言函数接口
IntPredicate predicate = i -> i > 0;
System.out.println(predicate.test(-9));
// IntConsumer,jdk中自带一些基本数据类型的,就不需要写泛型了
// 消费函数接口
Consumer<String> consumer = s -> System.out.println(s);
consumer.accept("输入的数据");
}