Lambda适用于只有一个抽象方法的接口 即函数式接口
Lambda 表达式是一种匿名函数(不是匿名内部类),简单地说,它是没有声明的方法,也即没有访问修饰符、返 回值声明和名字。它实质属于函数式编程的概念。
语法:
(parameters) -> expression或 (parameters) ->{ statements; }
参数:要重写的方法的形参列表
-> :lambda运算符
表达式/语句体:要实现的方法的方法体
先定义一个只有抽象方法的接口 其实际上是一个函数式接口 可在接口前面加上@FunctionalInterface注解进行验证
@FunctionalInterface
interface Fu{
void add();
}
再使用匿名内部类实现接口
public class LambdaTest {
public static void main(String[] args) {
//匿名内部类
Fu f = new Fu() {
@Override
public void add() {
System.out.println("f");
}
};
f.add(); //f
}
}
由于函数式接口中只必须实现一个方法 那么我们就可使用lambda将此方法名省略
public class LambdaTest {
public static void main(String[] args) {
//匿名内部类
Fu f = new Fu() {
@Override
public void add() {
System.out.println("f");
}
};
f.add(); //f
//lambda表达式
Fu fl = ()->{
System.out.println("lambda");
};
//Fu fl = ()->System.out.println("lambda");
//多态调用
fl.add(); //lambda
}
}
()相当于add参数位置 当只有一个参数时可省略 {} 相当于方法体 当只有一句时return和{}可省略 它可看作是上面匿名类的简写
public class LambdaTestB {
public static void main(String[] args) {
//Fu2 fu = (a)->{return a*5};
Fu2 fu = a->a*5;
System.out.println(fu.add(100));
}
}
interface Fu2{
int add(int a);
}
集合的forEach是最常用lambda的地方 以它为例
查看forEach源码 可以看到是一个Consumer类型的参数 ctrl+左键进到Consumer中 可看到是一个函数式接口 到这一步可以看到跟我们上面自定义的接口几乎没什么区别
public class LambdaTestC {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<>();
Collections.addAll(list, 1,2,4,5,12,56,121);
list.forEach(v-> System.out.println(v));
//forEach源码方法
public void forEach(Consumer<? super E> action) {}
// Consumer 源码
@FunctionalInterface
public interface Consumer<T> {
/**
* Performs this operation on the given argument.
*
* @param t the input argument
*/
void accept(T t);
}
}
}
使用内部类和lambda实现
public class LambdaTestC {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<>();
Collections.addAll(list, 1,2,4,5,12,56,121);
System.out.println("===========内部匿名类===============");
Consumer<Integer> co = new Consumer<Integer>() {
@Override
public void accept(Integer integer) {
System.out.println(integer);
}
};
list.forEach(co);
//简写
System.out.println("=============lambda================");
Consumer<Integer> co1 = v-> System.out.println(v);
list.forEach(co1);
System.out.println("=============lambda2================");
//省略赋值操作最终简写
list.forEach(v-> System.out.println(v));
}
}
函数式接口:接口中只能有一个抽象方法,其他的可以有default、static、Object里继承的方法等。
作用:在Java中主要用在Lambda表达式和方法引用(想使用Lambda表达式, 接口必须为函数式接口
)。
JDK8专门提供了@FunctionalInterface
注解,用来进行编译检查。
@FunctionalInterface
public interface FuncInterface {
//只有一个抽象方法
public void method1();
//default方法不计
default void method2(){
}
//static方法不计
static void method3(){
}
//从Object继承的方法不计
public boolean equals(Object obj);
}
JDK 也提供了大量的内置函数式接口,使得 Lambda 表达式的运用更加方便、高效。这些内置的函数式接口已经可以解决我们开发过程中绝大部分的问题,只有一小部分比较特殊得情况需要我们自己去定义函数式接口。在这里特别介绍四个函数式接口。
Consumer:消费型接口(void accept(T t))。有参数,无返回值 (上文forEach的参数类型就是Consumer)
Supplier:供给型接口(T get())。只有返回值,没有入参
Function
Predicate:断言型接口(boolean test(T t))。输入一个参数,输出一个boolean类型得返回值
函数式接口 | 方法名 | 输入参数 | 输出参数 | 参数/吃草 返回/挤奶 |
---|---|---|---|---|
消费型接口Consumer | void accept(T t) | T | void | 只吃草不挤奶 |
供给型接口Supplier | T get() | void | T | 只挤奶不吃草 |
函数型接口Function | R apply(T t) | T | R | 又吃草又挤奶 |
断言型接口Predicate | boolean test(T t) | T | boolean | Boolean类型 |
public class TestFunctional1 {
public static void main(String[] args) {
List<Integer > list = new ArrayList<>();
Collections.addAll(list,34,56,89,65,87);
//使用匿名内部类实现
Consumer consumer = new Consumer<Integer>() {
@Override
public void accept(Integer elem) {
System.out.println(elem);
}
};
list.forEach(consumer);
//使用Lambda表达式
//list.forEach((elem)->{System.out.println(elem);});
list.forEach((elem)->System.out.println(elem));
}
}
public class TestFunctional2 {
public static void main(String[] args) {
List<Integer > list = new ArrayList<>();
Collections.addAll(list,34,56,89,65,87);
//使用匿名内部类实现
System.out.println(list);
Predicate predicate = new Predicate<Integer>(){
@Override
public boolean test(Integer i) {
if(i<60){
return true;
}
return false;
}
};
list.removeIf(predicate);
System.out.println(list);
//使用Lambda表达式实现
list.removeIf((i)->{
if(i > 80) {
return true;
}
return false;
});
//list.removeIf(i->i>80);
System.out.println(list);
}
}
有时候,Lambda体可能仅调用一个已存在方法,而不做任何其它事,对于这种情况,通过一个方法名字来引用这个已存在的方法会更加清晰。方法引用是一个更加紧凑,易读的 Lambda 表达式,注意方法引用是一个 Lambda 表达式,方法引用操作符是双冒号 “::”。
public class LambdaTestC {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<>();
Collections.addAll(list, 1,2,4,5,12,56,121);
System.out.println("===========内部匿名类===============");
Consumer<Integer> co = new Consumer<Integer>() {
@Override
public void accept(Integer integer) {
System.out.println(integer);
}
};
list.forEach(co);
//简写
System.out.println("=============lambda================");
Consumer<Integer> co1 = v-> System.out.println(v);
list.forEach(co1);
System.out.println("=============lambda2================");
//省略赋值操作最终简写
list.forEach(v-> System.out.println(v));
//方法引用
list.forEach(System.out::println);
}
}
方法引用2
public class FunctionalTestA {
public static void main(String[] args) {
Comparator<Integer> co = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1, o2);
// return o1-o2;
}
};
int i = co.compare(1, 20);
System.out.println(i);
System.out.println("===========lambda=============");
Comparator<Integer> co2 = (x,y)->Integer.compare(x,y);
System.out.println(co2.compare(1, 20));
System.out.println("=============方法引用=================");
Comparator<Integer> co3 = Integer::compare;
System.out.println(co3.compare(1, 20));
;
}
}
方法引用有下面几种方式:
对象引用::实例方法名
类名::静态方法名
类名::实例方法名
类名::new (也称为构造方法引用)
类型[]::new (也称为数组引用)
未完待续…