一、函数式接口
1.1 概念
函数式接口:有且仅有一个抽象方法的接口,并被 @FunctionalInterface 修饰。
要学习lambda表达式,要先了解函数式接口。
1.2 JDK8中接口的变化
public interface MyInterface1 {
void f1(); //普通抽象方法
static void f2() { //被static修饰的方法允许有方法体
}
default void f3() { //被default修饰的方法允许有方法体
}
}
得出结论:jdk8允许接口中写实现的方法,但是必须被 static 或者 default 修饰。
1.3 编写一个函数式接口
@FunctionalInterface
public interface MyInterface2 {
void f1();
}
//满足:有且仅有一个抽象方法
1.4 使用匿名内部类继承实现函数式接口
MyInterface2 my = new MyInterface2() {
@Override
public void f1() {
System.out.println("f1...");
}
};
为什么使用匿名内部类呢?一句话:方便。
在仅调用一次的场景下,匿名内部类的方式就非常方便,不用去新建一个类实现该接口后再去重写方法。
但是,我们会发现,在函数式接口的背景下,使用匿名内部类仍然不是很简化。所以,我们使用lambda表达式来进一步简化代码。
二、lambda表达式
2.1 概念
Lambda 表达式(lambda expression)是一个匿名函数,Lambda表达式基于数学中的λ演算得名,直接对应于其中的lambda抽象(lambda abstraction),是一个匿名函数,即没有函数名的函数。
一句话:在java中主要用于简化 函数式接口的匿名内部类的编写。
2.2 语法
(参数列表)->{
方法体
}
2.3 代码实现
2.3.1 无参无返回值的方法
@FunctionalInterface
public interface MyInterface {
//无参无返回值
void f1();
}
//1.使用匿名内部类实现
MyInterface1 myInterface1 = new MyInterface1() {
@Override
public void f1() {
System.out.println("f1...");
}
};
//2.使用lambda表达式进行实现(省略new接口和方法签名的部分,中间用 -> 连接 )
MyInterface1 myInterface1 =() -> {
System.out.println("f1...");
};
//进一步简化:方法体仅有一个行代码 {} 可以省略
MyInterface1 myInterface1 =() -> System.out.println("f1...");
2.3.2 无参有返回值的方法
@FunctionalInterface
public interface MyInterface1 {
//无参有返回值
int f2();
}
//1.匿名内部类实现
MyInterface1 myInterface1 = new MyInterface1() {
@Override
public int f2() {
return 0;
}
};
//2.lambda表达式实现
MyInterface1 myInterface1 = () -> return 0;
//当方法体仅有一行代码,return 也可以省略
MyInterface1 myInterface1 = () -> 0;
2.3.3 有参无返回值的方法
@FunctionalInterface
public interface MyInterface1 {
//有参无返回值
void f3(int a);
}
//1.匿名内部类实现
MyInterface1 myInterface1 = new MyInterface1() {
@Override
public void f3(int a) {
System.out.println(a);
}
};
//2.lambda表达式实现
MyInterface1 myInterface1 = (int a) -> System.out.println(a);
//有参时,参数的类型可以省略
MyInterface1 myInterface1 = (a) -> System.out.println(a);
//当参数仅有一个时,()可以省略
MyInterface1 myInterface1 = a -> System.out.println(a);
2.3.4 有参有返回值的方法
@FunctionalInterface
public interface MyInterface1 {
//有参有返回值
int f4(int a,int b);
}
//1.匿名内部类实现
MyInterface1 myInterface1 = new MyInterface1() {
@Override
public int f4(int a, int b) {
return a+b;
}
};
//2.lambda表达式实现
MyInterface1 myInterface1 = (int a, int b) -> {
return a+b;
};
//最终简化为:多个参数时()不能省略
MyInterface1 myInterface1 = (a, b) -> a+b ;
三、lambda表达式中使用调用方法
3.1 调用构造方法
需求:将字符串转为Integer
@FunctionalInterface
public interface MyInterface {
//将字符串转为Integer
Integer pasreInt(String str);
}
//1.匿名内部类实现
MyInterface myInterface = new MyInterface() {
@Override
public Integer pasreInt(String str) {
return new Integer(str);
}
};
//2.lambda表达式实现
MyInterface myInterface = str -> new Integer(str);
//继续简化:
MyInterface myInterface = Integer::new; //语法为: 类名::new
3.2 调用静态方法
需求:把字符串转为 int
@FunctionalInterface
public interface MyInterface {
//将字符串转为int
int parse(String str);
}
//1.匿名内部类实现
MyInterface myInterface = new MyInterface() {
@Override
public int parse(String str) {
//将字符串转为:int
return Integer.parseInt(str);
}
};
//2.lambda表达式实现
MyInterface myInterface = str -> Integer.parseInt(str);
//继续简化:
MyInterface myInterface = Integer::parseInt; //语法: 类名::静态方法名
3.3 调用实例方法
需求:判断字符串是不是以 .mp4 结尾 , 这里咱们用到一个由java提供的函数式接口 Function 来完成。
String str = "1.mp4";
Function<String, Boolean> fun = new Function<String, Boolean>(){
@Override //判断str是不是以 .mp4 结尾
public Boolean apply(String t) {
return str.endsWith(t);
}
};
System.out.println(fun.apply(".mp4"));
//lambda表达式简化:
String str = "1.mp4";
Function<String, Boolean> fun = t -> str.endsWith(t);
System.out.println(fun.apply(".mp4"));
//继续简化:
String str = "1.mp4";
Function<String, Boolean> fun = str::endsWith; // 语法为: 对象名::方法名
System.out.println(fun.apply(".mp4"));
实例方法的特殊情况:
需求:判断字符串是否为空。
Function<String, Boolean> function = new Function<String, Boolean>(){
@Override
public Boolean apply(String t) {
return t.isEmpty();
}
};
//lambda表达式简化:
Function<String, Boolean> function = t -> t.isEmpty();
//继续简化:
Function<String, Boolean> function = String::isEmpty; //语法: 类名::实例方法名 (语法和静态方法很像要注意区分)
四、做个练习巩固一下
需求:遍历List集合
List<Integer> list = Arrays.asList(1,2,3,4);
//list集合给我们提供了一个forEach()方法可以遍历集合,实现函数式接口Consumer
//匿名内部类的方式:
list.forEach(new Consumer<Integer>() {
@Override
public void accept(Integer t) {
System.out.println(t);
}
});
//使用lambda简化:
list.forEach( t -> System.out.println(t) );
//再简化:满足lambda中调用实例方法的规则
list.forEach(System.out::println);
如果你掌握了lambda,接着你就可以去看看Stream流了,点击:学习Stream流