函数式接口 (Functional Interface)
函数式接口主要指的是只包含一个抽象方法的接口,例如:java.lang.Runnable、java.util.Cpmparator接口等等。
Java8提供@FunctionalInterface注解来定义函数式接口,若定义的接口不符合函数式的规范,则会报错。在Java8中增加了java.util.function包(包内提供了大量的函数式接口):
匿名内部类
没有名字的内部类
语法格式:
父类/接口类型 引用变量名 = new 父类/接口类型(参数列表){
方法的重写
};
Lambda表达式
Lambda表达式是实现函数式接口的重要方式,利用Lambda表达式可以使代码变得更加简洁。
语法格式:(参数列表) -> { 方法体 };
函数式接口 与 匿名内部类、lambda表达式 (代码)
简单封装一个Person类备用
public class Person {
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void show(){
System.out.println("~(@^_^@)~咻咻咻");
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
下面的代码就是函数式接口的相关使用
在使用函数式内部类时,需要确定自己要使用的带不带参数,带几个参数,需不需要返回值。一些常用的函数式接口如下:
接口名称 | 方法声明及功能介绍 |
---|---|
Consumer | void accept(T t) ;根据指定的参数执行操作 |
Supplier | T get() ; 得到一个返回值 |
Function<T,R> | R apply(T t) ;根据指定的参数执行操作并返回 |
Predicate | boolean test(T t) ;判断指定的参数是否满足条件 |
测试代码如下:
public class FunctionalInterface {
public static void main(String[] args) {
// 1. 匿名内部类的语法格式: 父类/接口类型 引用变量名 = new 父类/接口类型(){ 方法的重写 }
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("我是既没有参数又没有返回值的方法");
}
};
runnable.run();
// 2.使用lambda表达式实现函数式接口对象的实现
// 一个参数可省略参数类型和小括号
// 只有一条语句时可省略大括号
// 只有一条语句且是return时,可省略大括号及return
Runnable runnable1 = () -> System.out.println("lambda表达式实现的既没有参数又没有返回值的方法");
runnable1.run();
System.out.println("-----------------------------");
Consumer consumer = new Consumer() {
@Override
public void accept(Object o) {
System.out.println( o +"有参但没有返回值的方法");
}
};
consumer.accept("友情提示1:");
Consumer consumer1 = (Object o) -> System.out.println( o +"有参但没有返回值的方法");
Consumer consumer2 = (o) -> System.out.println( o +"有参但没有返回值的方法");
Consumer consumer3 = o -> System.out.println( o +"有参但没有返回值的方法");
consumer1.accept("友情提示2");
System.out.println("-----------------------------");
Supplier supplier = new Supplier() {
@Override
public Object get() {
return "我是一个无参有返回值的函数式接口方法";
}
};
System.out.println(supplier.get());
Supplier supplier1 = () -> {return "我是一个无参有返回值的函数式接口方法";};
Supplier supplier2 = () -> "我是一个无参有返回值的函数式接口方法";
supplier1.get();
System.out.println("------------------------------");
Function function = new Function() {
@Override
public Object apply(Object o) {
return o;
}
};
System.out.println(function.apply("Function<T,r>是一个有参有返回值的函数式接口"));
Function function1 = o -> o;
System.out.println(function1.apply("11"));
}
}
方法的引用
方法引用主要指通过方法的名字来指向一个方法而不需要为方法引用提供方法体,该方法的调用交给函数式接口执行。就是我通过类名或者对象名,直接指向该类或者该对象中的某一个方法。
匿名内部类、lambda和方法引用其实是相通的,从匿名内部类到lambda到方法引用是一个进化的过程,是一个简化的过程,更加是一个从抽象的过程。作用都是实现接口方法,换句话说就是实现接口;只是这个接口只有一个抽象方法。
方法的引用使用一对 :: 通过类或对象指向方法,通常使用方式如下:
- 对象的非静态方法引用 ObjectName :: MethodName
- 类的静态方法引用 ClassName ::StaticMethodName
- 类的非静态方法引用 ClassName :: MethodName
- 构造器的引用 ClassName :: new
- 数组的引用 TypeName[] :: new
方法引用是在特定场景下lambda表达式的一种简化表示,可以进一步简化代码的编写使代码更加
紧凑简洁,从而减少冗余代码。
对应代码如下(跟课程练习时写的代码,太长了,慎看…):
public static void main(String[] args) {
// 1.使用匿名内部类的方式通过函数式接口Runnable中的方法实现对Person中show方法的调用
Person person = new Person("章法",13);
Runnable runnable = new Runnable() {
@Override
public void run() {
person.show();
}
};
runnable.run(); // ~(@^_^@)~咻咻咻
System.out.println("--------------------------------------------------");
// 2.使用lambda表达式的方式通过函数式接口Runnable中的方法实现对Person中show方法的调用
Runnable runnable1 = () -> person.show();
runnable1.run();// ~(@^_^@)~咻咻咻
System.out.println("--------------------------------------------------");
// 3.使用方法引用的方式实现Person类中show方法的调用
Runnable runnable2 = person::show; // 方法引用
runnable2.run();
System.out.println("--------------------------------------------------");
// 4.使用函数内部类的方式实通过函数式接口Consumer中的方法实现Person中setName方法的使用
Consumer<String> consumer = new Consumer<String>() {
@Override
public void accept(String s) {
person.setName(s);
}
};
consumer.accept("guanyu");
System.out.println("Person = " + person);
System.out.println("--------------------------------------------------");
// 5.使用lambda表达式的方法实现Person类中setName方法的使用
Consumer<String> consumer1 = s -> person.setName(s);
consumer1.accept("liubei");
System.out.println("Person = " + person);
System.out.println("--------------------------------------------------");
// 6.使用 方法引用 的方式使用Person类中serName方法的使用
Consumer<String> consumer2 = person::setName;
consumer2.accept("zhangfei");
System.out.println("Person = " + person);
System.out.println("--------------------------------------------------");
// 7.使用函数内部类的方式实通过函数式接口Supplier中的方法实现Person中getName方法的使用
Supplier<String> stringSupplier = new Supplier<String>() {
@Override
public String get() {
return person.getName();
}
};
System.out.println(stringSupplier.get());
Supplier<String> stringSupplier1 = () -> person.getName();
System.out.println(stringSupplier1.get());
Supplier<String> stringSupplier2 = person::getName;
System.out.println(stringSupplier2.get());
System.out.println("--------------------------------------------------");
// 8.(类的静态方法引用)使用匿名内部类的方式通过函数式接口Function中的方法实现Integer类中parseInt方法(将字符串转换为整数)的调用
Function<String,Integer> function = new Function<String, Integer>() {
@Override
public Integer apply(String s) {
return Integer.parseInt(s);
}
};
System.out.println(function.apply("12345"));// 12345
Function<String,Integer> function1 = s -> Integer.parseInt(s);
System.out.println(function1.apply("12345"));// 12345
Function<String,Integer> function2 = Integer::parseInt;
System.out.println(function2.apply("12345")); // 12345
System.out.println("--------------------------------------------------");
// 9.(类的静态方法引用)使用匿名内部类的方式通过函数式接口Comparator中的方法实现Integer类中compare方法的调用
Comparator<Integer> comparator = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1,o2);
}
};
System.out.println(comparator.compare(1, 2)); // -1
Comparator<Integer> comparator1 = (o1,o2) -> Integer.compare(o1,o2);
System.out.println(comparator1.compare(1, 2)); // -1
Comparator<Integer> comparator2 = Integer::compare;
System.out.println(comparator2.compare(1, 2)); // -1
System.out.println("--------------------------------------------------");
// 10.(类的静态方法引用)使用匿名内部类的方式通过类名来调用非静态方法
// 其中一个参数作为调用对象来调用方法时,可以使用上述方式 更加抽象
Comparator<Integer> comparator3 = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1.compareTo(o2);
}
};
System.out.println(comparator3.compare(1, 2)); // -1
Comparator<Integer> comparator4 = (o1, o2) -> o1.compareTo(o2);
System.out.println(comparator4.compare(1, 2)); // -1
Comparator<Integer> comparator5 = Integer::compareTo;
System.out.println(comparator5.compare(1, 2)); // -1
System.out.println("--------------------------------------------------");
// 11.(构造器的引用)使用匿名内部类的方式通过Supplier函数式接口采用无参方式创建Person类型的对象并返回
Supplier<Person> supplier = new Supplier<Person>() {
@Override
public Person get() {
return new Person();
}
};
System.out.println(supplier.get()); // Person{name='null', age=0}
Supplier<Person> supplier1 = () -> new Person();
System.out.println(supplier1.get()); // Person{name='null', age=0}
Supplier<Person> supplier2 = Person::new;
System.out.println(supplier2.get()); // Person{name='null', age=0}
System.out.println("--------------------------------------------------");
// 12.(构造器的引用)使用匿名内部类的方式通过BiFunction函数式接口采用有参方式创建Person类型的对象并返回
BiFunction<String,Integer,Person> biFunction = new BiFunction<String, Integer, Person>() {
@Override
public Person apply(String s, Integer integer) {
return new Person(s,integer);
}
};
System.out.println(biFunction.apply("zhanfei", 30)); // Person{name='zhanfei', age=30}
BiFunction<String,Integer,Person> biFunction1 = (s,integer)->new Person(s,integer);
System.out.println(biFunction1.apply("liubei", 40)); // Person{name='liubei', age=40}
BiFunction<String,Integer,Person> biFunction2 = Person::new;
System.out.println(biFunction2.apply("guanyu", 35)); // Person{name='guanyu', age=35}
System.out.println("--------------------------------------------------");
// 12.(数组的引用)使用匿名内部类的方式通过Function函数式接口采用创建指定数量的Person类型的对象数组并返回
Function<Integer,Person[]> function3 = new Function<Integer, Person[]>() {
@Override
public Person[] apply(Integer integer) {
return new Person[integer];
}
};
System.out.println(Arrays.toString(function3.apply(3))); // [null, null, null]
Function<Integer,Person[]> function4 = integer -> new Person[integer];
System.out.println(Arrays.toString( function4.apply(4))); // [null, null, null, null]
Function<Integer,Person[]> function5 = Person[]::new;
System.out.println(Arrays.toString(function5.apply(5))); // [null, null, null, null, null]
}