介绍
lambda表达式是在Java 8版本才有的,lambda表达式是代码变得更加简单紧凑、优美。
语法:
1、(param)->expression;
2、(param)->{expression;};
3、参数声明可选,如:(a,b)->a+b; 或 (int a,int b)->a+b;
4、参数圆括号可选,只有一个参数时可以不需要括号,但无参或多个参数时需要用括号,如:
()->3;
a->a;
(a)->a;
(a,b)->a+b;
5、主体大括号可选,当主体只有一个语句时,可以不需要大括号,超过一个语句时需要大括号,如:
(a,b)->a+b;
(a,b)->{System.out.println(a);return a+b;};
lambda实例
并不是所有接口都能用lambda表达式的,是必须只有一个抽象方法的接口才可以。如果确定一个接口用lambda表达式使用,最好用@FunctionalInterface注解标识这个接口类,这注解的作用是允许这个接口只能有一个抽象方法,当有多个抽象方法时会编译不通过,但可以有多个非抽象方法,如default和static修饰的方法,而只有一个抽象方法的接口也称为函数式接口或功能性接口。
首先定义一个函数式接口:
@FunctionalInterface
public interface IMath {
/**
* 抽象方法
* @param a
* @param b
* @return
*/
int math(int a, int b);
}
public class Main {
public static void main(String[] args) {
//加法实现
IMath sum = (a, b) -> a + b;
//减法实现
IMath sub = (int a, int b) -> a - b;
//除法
IMath div = (a, b) -> {
System.out.println("a=" + a);
System.out.println("b=" + b);
return a / b;
};
System.out.println(sum.math(1, 2));
System.out.println(sub.math(3, 2));
System.out.println(div.math(6, 2));
//乘法,作为参数
System.out.println(math(3, 2, (a, b) -> a * b));
}
public static int math(int a, int b, IMath math) {
return math.math(a, b);
}
}
作用域
在lambda表达式外的变量具有隐性的final语义,即变量不可变。而在lambda表达式主体内定义变量和普通变量一样。如下面的两处要修改变量c,这是不允许的。
int c = 3;
IMath math = (a,b)->{
//1、不允许改变
c=5;
System.out.println(c);
return a+b;
};
//2、不允许改变
c=5;
静态方法和默认方法
上面提到用@FunctionalInterface修饰的接口类是可以添加静态方法和默认方法的,但在lambda表达式的主体内是无法调用自身的默认方法的,而匿名类可以调用默认方法,这是为什么呢?下面例子来演示:
@FunctionalInterface
public interface IMath {
/**
* 抽象方法
* @param a
* @param b
* @return
*/
int math(int a, int b);
/**
* 默认方法
*/
default void m(){
System.out.println("default");
}
/**
* 静态方法
*/
static void m2() {
System.out.println("static");
}
}
public class Main {
public static void main(String[] args) {
Main main = new Main();
main.math();
}
public void math() {
System.out.println("当前类:"+this);
IMath div = (a, b) -> {
System.out.println("lambda当前类:"+this);
//调用静态方法
IMath.m2();
return a / b;
};
div.math(4,2);
//匿名类
IMath sum = new IMath() {
@Override
public int math(int a, int b) {
System.out.println("内部类当前类:"+this);
//调用默认方法
m();
return a+b;
}
};
sum.math(2,3);
}
}
输出结果:
当前类:com.fs.test.lambda.Main@2d554825
lambda当前类:com.fs.test.lambda.Main@2d554825
static
内部类当前类:com.fs.test.lambda.Main$1@4157f54e
default
显然在lambda表达式内的this地址还是Main,而内部类的this是内部类地址,而调用自身的方法相当于this.方法名(),lambda表达式的this还是当前类地址,也就没有对应的默认方法。
函数式接口
函数式接口:只有一个抽象方法的接口为函数式接口,可以有多个非抽象方法,如default何static修饰的方法。
在jdk 的java.util.function包下就定义了很多函数式接口,可以用于不同的场景,而主要的有下面几个:
接口 | 描述 |
---|---|
Consumer<T> | 接受一个T对象,无返回值,消费某个对象,如集合的forEach方法 |
Function<T, R> | 接受一个T对象,经过函数处理返回另一个对象 |
Predicate<T> | 接受一个T对象,返回Boolean结果,用于断言判断 |
Supplier<T> | 无参数,返回一个对象,用于创建对象,如工厂类 |
网友评论