jdk8开始新增
函数式编程: 使用Lambda函数替代某些匿名内部类对象,从而让程序代码更简洁,可读性更好
7.1 Lambda函数简介
可以用于替代某些匿名内部类对象,从而让程序更简洁,可读性更好
(被重写方法的形参列表) -> {
被重写方法的方法体代码
}
注意 : Lambda表达式只能替代函数式接口的匿名内部类!
!什么是函数式接口?
有且仅有一个抽象方法的接口
注意:将来我们见到的大部分函数式接口,上面都可能会有一个@FunctionalInterface的注解,该注解用于约束当前接口必须是函数式接口
示例:
java
// 1. 定义一个函数式接口(有且仅有一个抽象方法)
@FunctionalInterface
interface Calculator {
int add(int a, int b);
}
public class LambdaBasicDemo {
public static void main(String[] args) {
// 【传统写法】匿名内部类
Calculator oldWay = new Calculator() {
@Override
public int add(int a, int b) {
return a + b;
}
};
// 【Lambda写法】简洁明了
Calculator lambdaWay = (int a, int b) -> {
return a + b;
};
System.out.println(lambdaWay.add(3, 5)); // 输出: 8
}
}
7.2 Lambda表达式的省略规则
作用:用于进一步简化Lambda表达式的写法
具体规则:
- 参数类型全部可以省略不写
- 如果只有一个参数,参数类型省略的同时"()"也可以省略,但多个参数不能省略"()"
- 如果Lambda表达式中只有一行代码,大括号可以不写,同时要省略分号";"如果这行代码是return语句,也必须去掉return
示例:
java
import java.util.Arrays;
import java.util.List;
public class LambdaOmissionDemo {
public static void main(String[] args) {
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
// 【完整写法】
// names.forEach((String name) -> { System.out.println(name); });
// 【省略规则演示】
// 1. 省略参数类型 String
// 2. 只有一个参数,省略小括号 ()
// 3. 只有一行代码,省略大括号 {}、分号 ;
names.forEach(name -> System.out.println(name));
}
}
7.3 方法引用
进一步简化 Lambda 表达式
以下4中特定场景才能用方法引用
7.3.1 静态方法引用
格式:类名::静态方法
使用场景:如果某个Lambda表达式里只是调用一个静态方法,并且"→"前后参数的形式一致,就可以使用静态方法引用
示例:
java
import java.util.Arrays;
import java.util.List;
public class StaticMethodRefDemo {
// 自定义静态方法,参数与Consumer.accept(T)一致
public static void printUpperCase(String s) {
System.out.println(s.toUpperCase());
}
public static void main(String[] args) {
List<String> list = Arrays.asList("hello", "world");
// Lambda写法: list.forEach(s -> StaticMethodRefDemo.printUpperCase(s));
// 静态方法引用: 前后参数形式一致,直接引用
list.forEach(StaticMethodRefDemo::printUpperCase);
}
}
7.3.2 实例方法引用
格式:对象名::实例方法
使用场景:如果某个Lambda表达式里只是通过对象名称调用一个实例方法,并且"→"前后参数的形式一致,就可以使用实例方法引用
示例:
java
import java.util.Arrays;
import java.util.List;
public class InstanceMethodRefDemo {
public void printWithPrefix(String s) {
System.out.println(">> " + s);
}
public static void main(String[] args) {
InstanceMethodRefDemo obj = new InstanceMethodRefDemo();
List<String> list = Arrays.asList("Java", "Lambda");
// Lambda写法: list.forEach(s -> obj.printWithPrefix(s));
// 实例方法引用: 通过已有对象调用实例方法
list.forEach(obj::printWithPrefix);
}
}
7.3.3 特定类的方法引用
格式:特定类的名称::方法
使用场景:如果某个Lambda表达式里只是调用一个特定类型的实例方法,并且前面参数列表中的第一个参数是作为方法的主调,后面的所有参数都是作为该实例方法的入参的,则此时就可以使用特定类型的方法引用
示例:
java
import java.util.Arrays;
import java.util.List;
public class ClassMethodRefDemo {
public static void main(String[] args) {
List<String> list = Arrays.asList("hello", "WORLD", "Java");
// Lambda写法: list.forEach(s -> s.toLowerCase())
// 这里 s 是第一个参数,同时也是 toLowerCase() 的调用者
// 符合"特定类的方法引用"场景
list.forEach(String::toLowerCase);
// 注意:上面这行只是演示语法,实际forEach需要Consumer
// 更常见的实际使用场景是在Stream中:
list.stream()
.map(String::toUpperCase) // s -> s.toUpperCase()
.forEach(System.out::println);
}
}
7.3.4 构造器引用
格式:类名::new
使用场景:如果某个Lambda表达式里只是在创建对象,并且"→"前后参数情况一致,就可以使用构造器引用
示例:
java
import java.util.function.Function;
import java.util.function.Supplier;
class User {
private String name;
// 无参构造
public User() { this.name = "Default"; }
// 有参构造
public User(String name) { this.name = name; }
@Override
public String toString() { return "User{name='" + name + "'}"; }
}
public class ConstructorRefDemo {
public static void main(String[] args) {
// 【无参构造器引用】 对应 Supplier<User>
// Lambda: () -> new User()
Supplier<User> userSupplier = User::new;
System.out.println(userSupplier.get()); // User{name='Default'}
// 【有参构造器引用】 对应 Function<String, User>
// Lambda: name -> new User(name)
Function<String, User> userFunction = User::new;
System.out.println(userFunction.apply("张三")); // User{name='张三'}
}
}