前言
public interface Student {
void study(String subject);
void run();
}
@Test
public void test() {
Student student = new Student() {
@Override
public void study(String subject) {
System.out.println("学习" + subject);
}
@Override
public void run() {
System.out.println("跑步");
}
};
student.study("英语");
student.run();
}
你可能不了解Lambda,但是你一定见过上面的写法(匿名内部类
)。那么Java在一定程度上,通过Lambda
对于这种匿名内部类
进行了优化。但是,Lambda只针对于函数式接口
。
函数式接口有一个最大的特点,只能有一个公共抽象类
。
// 伪函数式接口
public interface Student {
void study(String subject);
}
@Test
public void test() {
Student student = new Student() {
@Override
public void study(String subject) {
System.out.println("学习" + subject);
}
};
student.study("英语");
System.out.println("********下面通过Lambda改造********");
Student stu = (subject) -> System.out.println("学习" + subject);
stu.study("语文");
}
Java提供一个注解@FunctionalInterface
来标记该接口是函数式接口,强制规定
接口中仅有一个公共抽象类。
@FunctionalInterface
public interface Student {
// 有两个公共抽象类,则会编译异常:
// Multiple non-overriding abstract methods found in interface com.shang.lambda.Student
void study(String subject);
void run();
}
函数式接口
Java内置
四种基本的函数式接口,如下。
1. 消费型接口( Consumer<T>
) : void accept(T t)
2. 供给型接口(Supplier<T>
) :T get()
3. 函数型接口(Function<T, R>
) : R apply(T t)
4. 断言型接口(Predicate<T>
) : boolean test(T t)
@Test
public void test2() {
consumer(500.00, (money) -> System.out.println("赵公子消费" + money + "元"));
}
public void consumer(Double money, Consumer<Double> c) {
c.accept(money);
}
在上面的示例中,(money) -> System.out.println("赵公子消费" + money + "元")
有一个明显的特征,传入一个值,没有返回值
,显然它符合消费型接口( Consumer<T>
),所以可以传一个函数体给它。其它函数式接口类似。
语法糖
上面都是通过Lambda实现
抽象类,自定义实现体
。那么对于已经实现的方法,我们只需要直接使用,而不是实现。恰好这些已经实现的方法符合函数式接口的形式
,我们就可以通过语法糖
直接调用。
方法引用 | 构造器引用 |
---|---|
对象::实例方法名 | 类::new |
类::静态方法名 | 类[]::new |
类::实例方法名 |
// 1. 对象::实例方法
Consumer<String> com = str -> System.out.println(str);
// 等效于 Consumer<String> com = System.out::println;
com.accept("北京");
// 2. 类::静态方法
Comparator<Integer> com = (t1,t2) -> t1.compareTo(t2);
// 等效于 Comparator<Integer> com = Integer::compareTo;
com.compare(12,20);
// 3. 类::实例方法
Comparator<String> com = (s1,s2) -> s1.compareTo(s2);
// 等效于 Comparator<String> com = String::compareTo;
com.compare("abc","bcd");
Function<Teacher, String> fun = t -> t.getName;
// 等效于 Function<Teacher, String> fun = Teacher::getName;
fun.apply(teacher)
// 4. 类::new
Supplier<Teacher> sup = Teacher::new; // 无参构造器
Teacher teacher = sup.get();
Function<String, Teacher> sup1 = (name) -> new Teacher(name);
// 等效于 Function<String, Teacher> sup1 = Teacher::new // 1个参数构造器
sup1.apply("张老师");
BiFunction<String,Integer,Teacher> sup1 = (name,age) -> new Teacher(name,age);
// 等效于 BiFunction<String,Integer,Teacher> sup1 = Teacher::new // 2个参数构造器
sup1.apply("张老师",30);
能够使用语法糖
,需要满足两点要求
:第一点
,方法已经被实现。第二点
:方法符合函数式接口特征。
结尾
除了基本的四种函数式接口外,Java还有一些变种
。
1. BiFunction<T, U, R>
: R apply(T t, U u)
2. UnaryOperator<T>
:T apply(T t)
3. BinaryOperator<T>
:T apply(T t1, T t2)
4. BiConsumcr(T, U)
:void accept(T t, U u)
5. ToIntFunction<T>、ToLongFunction<T>、ToDoubleFunction<T>
:int applyAsInt(T value)、long applyAsLong(T value)、double applyAsDouble(T value)
6. IntFunction<R>、LongFunction<R>、DoubleFunction<R>
:R apply(int value)、R apply(long value)、R apply(double value)