Lambda 表达式可简化创建匿名内部类对象;
Lambda 表达式=匿名方法;
Lambda 表达式用于实现抽象方法的方法体;
Lambda 表达式三部分:
形参列表:形参列表允许省略类型;如果形参列表中只有一个参数,可以省略形参列表括号
箭头:(->)
代码块:代码块只有一条语句可省略花括号;代码块只有一条 return 语句可以省略 return
class LambdaQs {
public void eat(Eating e) {
System.out.println(e);
e.taste();
}
public void fly(Flying f) {
System.out.println(f);
f.fly("Sunny");
}
public void calc(Adding add) {
System.out.println("5 + 3 = " + add.add(5, 3));
}
public static void main(String[] args) {
LambdaQs lq = new LambdaQs();
// Lambda 表达式的代码块只有一句,因此省略了花括号
lq.eat(() -> System.out.println("Taste great"));
// Lambda 表达式的形参只有一个参数,因此省略了圆括号
lq.fly(weather -> {
// 对接口中抽象方法 fly 的重写
System.out.println("Weather today is " + weather);
System.out.println("Everything well!");
});
// Lambda 表达式只有一条语句,即使该表达式需要返回值,也可以省略 return
lq.calc((a, b) -> a + b);
// 如果不用 Lambda 表达式,就需要如下匿名类的方式去重写抽象方法
lq.calc(new Adding() {
@Override
public int add(int a, int b) {
return a + b;
}
});
}
}
Lambda 表达式的目标类型必须是函数式接口:
函数式接口代表只包含一个抽象方法的接口;
函数式接口可以包含多个默认方法、类方法,但仅能声明一个抽象方法。
Lambda 表达式目标类型强制转换为函数式接口:
Lambda 表达式赋值给函数式接口类型的变量;
Lambda 表达式作为函数式接口类型的参数传给某个方法;
使用函数式接口对 Lambda 表达式进行强制类型转换。
interface Runnable {
void run();
}
class Running{
Runnable r = () -> {
for (int i = 0; i < 100; i++) {
System.out.println(i);
}
};
// False
Object obj = () -> {
for (int i = 0; i < 100; i++) {
System.out.println(i);
}
};
}
interface Runnable {
void run();
}
class Running{
Runnable r = () -> {
for (int i = 0; i < 100; i++) {
System.out.println(i);
}
};
// Right
Object obj1 = (Runnable)() -> {
for (int i = 0; i < 100; i++) {
System.out.println(i);
}
};
}
1. 消费型接口:Consumer< T> void accept(T t)有参数,无返回值的抽象方法;
2. 供给型接口:Supplier < T> T get() 无参有返回值的抽象方法;
3. 断定型接口: Predicate< T> boolean test(T t):有参,但是返回值类型是固定的boolean
4. 函数型接口: Function< T,R> R apply(T t)有参有返回值的抽象方法;
Lambda 表达式的代码块只有一条代码,可以在代码中使用方法引用和构造器引用使 Lambda 表达式的代码块更加简洁。方法引用和构造器引用都需要使用两个英文冒号 ::。
| 种类 | 示例 | 说明 | 对应的 Lambda 表达式 | |
|---|---|---|---|---|
| 类 | 类名::类方法 | 全部参数传给该类方法作为参数 | (a,b,...) -> 类名.类方法(a,b,...) | |
| 特定对象的实例 | 特定对象::实例方法 | 全部参数传给该方法作为参数 | (a,b,...) -> 特定对象.实例方法(a,b,...) | |
| 某类对象的实例 | 类名::实例方法 | 第一个参数作为调用者后面的参数全部传给该方法作为参数 | (a,b,...) -> a.实例方法(b,...) | |
| 构造器 | 类名::new | 全部参数传给该构造器作为参数 | (a,b,...) -> new 类名(a,b,...) | |
| --- | --- | |||
public class LambdaDemo {
public static void main(String[] args){
// 1.引用类方法
Converter converter1 = from -> Integer.valueOf(from);
Integer val1 = converter1.convert("111");
System.out.println(val1);
// 全部参数传给类方法作为参数
Converter converter2 = Integer::valueOf;
Integer val2 = converter2.convert("222");
System.out.println(val2);
// 2.引用特定对象的实例方法
Converter converter3 = from -> "hello world".indexOf(from);
Integer val3 = converter3.convert("h");
System.out.println(val3);
// 调用 "hello world"::indexOf() 实例方法
// 全部参数传给该方法作为参数
Converter converter4 = "hello world"::indexOf;
Integer val4 = converter4.convert("l");
System.out.println(val4);
// 3.引用某类对象的实例方法
MyTest mt1 = (a, b, c) -> a.substring(b, c);
String str1 = mt1.test("Hello world", 1, 3);
System.out.println(str1);
// 第一个参数作为调用者
// 后面的参数全部传给该方法作为参数
MyTest mt2 = String::substring;
String str2 = mt2.test("Hello world", 1, 3);
System.out.println(str2);
// 4.引用构造器
YourTest yt1 = a -> new JFrame(a);
JFrame jf1 = yt1.win("Windows");
// 使用引用构造器进行替换
// 全部参数传给该构造器作为参数
YourTest yt2 = JFrame::new;
JFrame jf2 = yt2.win("Windows");
}
}
Lambda 表达式调用Arrays的类方法
class LambdaArrays {
public static void main(String[] args) {
String[] arr1 = new String[]{"java", "python", "rust", "go"};
Arrays.parallelSort(arr1, (o1, o2) -> o1.length() - o2.length());
System.out.println(Arrays.toString(arr1));
int[] arr2 = {3, -4, 25, 16, 30, 18};
// left 代表数组中前一个索引处的元素,计算第一个元素时,left 为 1;
// right 代表数组中的当前索引处的元素
Arrays.parallelPrefix(arr2, (left, right) -> left * right);
System.out.println(Arrays.toString(arr2));
long[] arr3 = new long[5];
// a 代表正在计算的元素索引
Arrays.parallelSetAll(arr3, a -> a * 5);
System.out.println(Arrays.toString(arr3));
// 等价于用匿名内部类重写 applyAsLong 抽象方法
Arrays.parallelSetAll(arr3, new IntToLongFunction() {
@Override
public long applyAsLong(int value) {
return value * 5;
}
});
System.out.println(Arrays.toString(arr3));
}
}
Lambda 表达式类型
class TestLambda {
public static void main(String[] args) {
// 无参无返回值
new Thread(() -> System.out.println("Hello"));
// 有参无返回值
ArrayList<String> list = new ArrayList<>();
list.add("AAAAA");
list.add("BBBBB");
list.add("CCCCC");
list.add("DDDDD");
// 形参的类型是确定的,可省略;只有一个形参,()可以省略;
list.forEach(t -> System.out.print(t + "\t"));
// 更简洁
list.forEach(System.out::println);
// 有参有返回值
Collator collator = Collator.getInstance();
TreeSet<Student> set = new TreeSet<>((s1, s2) -> collator.compare(s1.getName(),s2.getName()));
set.add(new Student(10,"AAAAA"));
set.add(new Student(3,"BBBBB"));
set.add(new Student(1,"CCCCC"));
set.forEach(student -> System.out.println(student));
}
}
class Student{
private int id;
private String name;
public Student(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public int setId(int id) {
return id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}