Lambda表达式是Java SE 8中一个重要的新特性。lambda表达式允许你通过表达式来代替功能接口。 lambda表达式就和方法一样,它提供了一个正常的参数列表和一个使用这些参数的主体(body,可以是一个表达式或一个代码块)。 Lambda 表达式(Lambda expression)可以看作是一个匿名函数,基于数学中的λ演算得名,也可称为闭包(Closure)
换句简单的话说: Lambda表达式允许你直接把一个代码块赋值给一个变量
2、语法
基本写法:(args1, args2, …)->{方法体}
语法小结
参数类型可以省略,如果需要省略,每个参数的类型都要省略。
参数的小括号里面只有一个参数,那么小括号可以省略
如果方法体当中只有一句代码,那么大括号可以省略
如果方法体中只有一条语句,其是return语句,那么大括号可以省略,且去掉return关键字
无参数无返回值
public class Main {
public static void main(String[] args) {
// 接口的常规使用
NoParameterNoReturn test = new NoParameterNoReturn() {
@Override
public void test() {
System.out.println("test");
}
};
test.test();
// lambda简化写法 只有一条语句,花括号可以省略
NoParameterNoReturn test2 = () -> System.out.println("test2");
test2.test();
}
public interface NoParameterNoReturn {
void test();
}
}
多参数无返回值
public class Main {
public static void main(String[] args) {
MoreParameterNoReturn moreParameterNoReturn = (r,t) -> {
System.out.println(r);
System.out.println(t);
System.out.println(r+t);
};
moreParameterNoReturn.test(2,4);
}
public interface MoreParameterNoReturn {
void test(int a,int b);
}
}
有参有返回值
public class Main {
public static void main(String[] args) {
// 写法1:完整写法
MoreParameterReturn moreParameterReturn = (int r,int t) -> {
return r+t;
};
int test = moreParameterReturn.test(2, 4);
System.out.println(test);
// 写法2:省略参数类型
MoreParameterReturn moreParameterReturn1 = (r,t) -> {
return r+t;
};
int test1 = moreParameterReturn1.test(2, 4);
System.out.println(test1);
// 写法3:省略方法体 + reture
MoreParameterReturn moreParameterReturn2 = (int r,int t) -> r+t;
int test2 = moreParameterReturn2.test(2, 4);
System.out.println(test2);
}
public interface MoreParameterReturn {
int test(int a,int b);
}
}
3、变量捕捉
3-1、实例1
简单写了一个匿名内部类,并且尝试捕获main函数中的变量a,下述代码正常执行
public class Main {
public static void main(String[] args) {
int a = 10;
Test test = new Test() {
@Override
public void func() {
System.out.println("我是内部类,并且重写func()");
System.out.println("捕获变量:"+a);
}
};
test.func();
}
public static class Test {
public void func(){
System.out.println("func()");
}
}
}
3-2、实例2
发现这里报错了:从内部类引用的本地变量必须是最终变量或实际上的最终变量
在匿名内部类中,捕获外部的变量前提是——该变量没有发生修改,或该变量本身是个常量
public class Main {
public static void main(String[] args) {
int a = 10;
a = 1;
Test test = new Test() {
@Override
public void func() {
System.out.println("我是内部类,并且重写func()");
System.out.println("捕获变量:"+a);
}
};
test.func();
}
public static class Test {
public void func(){
System.out.println("func()");
}
}
}
3-3、解决方案
方案1:添加一个不修改的临时变量
public class Main {
public static void main(String[] args) {
int a = 10;
a = 1;
int finalA = a;
Test test = new Test() {
@Override
public void func() {
System.out.println("我是内部类,并且重写func()");
System.out.println("捕获变量:"+ finalA);
}
};
test.func();
}
}
方案2:将变量置为final
public class Main {
public static void main(String[] args) {
final int a = 10;
Test test = new Test() {
@Override
public void func() {
System.out.println("我是内部类,并且重写func()");
System.out.println("捕获变量:"+ a);
}
};
test.func();
}
}
public class Main {
public static void main(String[] args) {
List<String> list = Arrays.asList("a", "b", "c");
// 写法1: lambda
list.forEach((x) -> Main.print(x));
// 写法2:双冒号
list.forEach(Main::print);
}
//静态方法
public static void print(String s) {
System.out.println(s);
}
}
4-2、引用对象实例方法
public class Main {
public static void main(String[] args) {
List<String> list = Arrays.asList("a", "b", "c");
// 写法1: lambda
list.forEach((x) -> new Main().print(x));
// 写法2:双冒号
list.forEach(new Main()::print);
}
//静态方法
public void print(String s) {
System.out.println(s);
}
}
4-3、引用超类实例方法
public class Main extends SuperMain {
public void test(){
List<String> list = Arrays.asList("a","b","c");
//实例方法引用 instanceRef::methodName
Consumer<String> print = super::print;
list.forEach(print);
}
public static void main(String[] args) {
new Main().test();
}
}
public class SuperMain {
public void print(String s){
System.out.println(s);
}
}
4-4、引用类构造方法
似懂非懂,待研究
public class Main {
public static void main(String[] args) {
// 无参构造方法引用
PersonEmpty personEmpty = Person::new;
Person person = personEmpty.createPerson();
System.out.println(person);
// 有参构造方法引用
PersonNoEmpty personNoEmpty = Person::new;
Person person2 = personNoEmpty.createPerson("zhangsan",12);
System.out.println(person2);
}
}
public class Person {
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public interface PersonEmpty {
Person createPerson();
}
public interface PersonNoEmpty {
Person createPerson(String name, int age);
}