目录
Lambda表达式介绍
Java8的一个大亮点是引入Lambda表达式,使用它设计的代码更加简洁。通过Lambda表达式,可以替代我们以前经常写的匿名内部类来实现接口。Lambda表达式本质是一个匿名函数。
Lambda表达式体验
通过一个小例子来体验一下Lambda表达式。
public class TestLambda {
public static void main(String[] args) {
Cal cal = new Cal() {
@Override
public int add(int a, int b) {
return a+b;
}
};
int c = cal.add(1,2);
System.out.println("输出结果:" + c);
}
interface Cal{
int add(int a,int b);
}
}
这是我们以前的实现,匿名内部类,然后调用执行。
我们现在使用Lambda表达式来改写一下这段代码,如下
public class TestLambda {
public static void main(String[] args) {
Cal cal = (int a,int b)->{
return a+b;
};
int c = cal.add(1,2);
System.out.println("输出结果:" + c);
}
interface Cal{
int add(int a,int b);
}
}
我们发现,使用Lambda表达式来编写这段代码,代码变的更加简洁了。
Lambda表达式语法
我们来看一下这个Lambda表达式:
(int a,int b)->{return a+b;};
一般的函数类似如下:
int add(int a,int b){
return a + b;
}
有返回值、方法名、参数列表、方法体
Lambda表达式函数的话,只有参数列表和方法体;
(参数列表)-> {方法体}
说明:
() : 用来描述参数列表;
{} : 用来描述方法体;
-> : Lambda运算符,可以叫做箭头符号,或者叫goes to
案例:
接口方法参数,无参,单个参数,两个参数,有返回值,没有返回值这六种情况
public class TestLambda {
public static void main(String[] args) {
/**
* 无参数无返回值
*/
Cal1 cal1=()->{
System.out.println("无参数无返回值");
};
cal1.test();
/**
* 单个参数无返回值
*/
Cal2 cal2=(int a)->{
System.out.println("单个参数无返回值 a=" + a);
};
cal2.test(5);
/**
* 两个参数无返回值
*/
Cal3 cal3=(int a,int b)->{
System.out.println("两个参数无返回值 a+b=" + (a+b));
};
cal3.test(1,5);
/**
* 无参数有返回值
*/
Cal4 cal4=()->{
return 4;
};
System.out.println("无参数有返回值 " + cal4.test());
/**
* 单个参数有返回值
*/
Cal5 cal5=(int a)->{
return a;
};
System.out.println("单个参数有返回值 a=" +cal5.test(8));
/**
* 两个参数有返回值
*/
Cal6 cal6=(int a,int b)->{
return a + b;
};
System.out.println("两个参数有返回值 a+b=" + cal6.test(2,7));
}
interface Cal1{
/**
* 无参数无返回值
*/
void test();
}
interface Cal2{
/**
* 单个参数无返回值
* @param a
*/
void test(int a);
}
interface Cal3{
/**
* 两个参数无返回值
* @param a
* @param b
*/
void test(int a,int b);
}
interface Cal4{
/**
* 无参数有返回值
* @return
*/
int test();
}
interface Cal5{
/**
* 单个参数有返回值
* @param a
* @return
*/
int test(int a);
}
interface Cal6{
/**
* 两个参数有返回值
* @param a
* @param b
* @return
*/
int test(int a,int b);
}
}
运行结果:
Lambda精简语法
语法注意点:
- 参数类型可以省略。
- 假如只有一个参数,()括号可以省略。
- 如果方法体只有一条语句,{}大括号可以省略。
- 如果方法体中唯一的语句是return返回语句,那省略大括号{}的同时return也要省略。
改写实例:
参数类型可以省略
public class TestLambda {
public static void main(String[] args) {
/**
* 参数类型可以省略
*/
Cal5 cal5=(a)->{
return a;
};
System.out.println("参数类型可以省略 a=" +cal5.test(8));
}
interface Cal5{
/**
* 参数类型可以省略
* @param a
* @return
*/
int test(int a);
}
}
假如只有一个参数,()括号可以省略
public class TestLambda {
public static void main(String[] args) {
/**
* 假如只有一个参数,()括号可以省略
*/
Cal5 cal5=a->{
return a;
};
System.out.println("输出 a=" +cal5.test(8));
}
interface Cal5{
/**
* 假如只有一个参数,()括号可以省略
* @param a
* @return
*/
int test(int a);
}
}
如果方法体只有一条语句,{}大括号可以省略
public class TestLambda {
public static void main(String[] args) {
/**
* 如果方法体只有一条语句,{}大括号可以省略
*/
Cal1 cal1=()->System.out.println("如果方法体只有一条语句,{}大括号可以省略");
cal1.test();
/**
* 如果方法体只有一条语句,{}大括号可以省略
*/
Test.Cal2 cal2=(a)->System.out.println("单个参数无返回值 a=" + a);
cal2.test(5);
}
interface Cal1{
/**
* 如果方法体只有一条语句,{}大括号可以省略
*/
void test();
}
interface Cal2{
/**
* 如果方法体只有一条语句,{}大括号可以省略
* @param a
*/
void test(int a);
}
}
如果方法体中唯一的语句是return返回语句,那省略大括号{}的同时return也要省略
public class TestLambda {
public static void main(String[] args) {
/**
* 无参数有返回值
*/
Cal4 cal4=()->4;
System.out.println("无参数有返回值 " + cal4.test());
/**
* 单个参数有返回值
*/
Cal5 cal5=a->a;
System.out.println("单个参数有返回值 a=" +cal5.test(8));
/**
* 两个参数有返回值
*/
Cal6 cal6=(a, b)->a + b;
System.out.println("两个参数有返回值 a+b=" + cal6.test(2,7));
}
interface Cal4{
/**
* 无参数有返回值
* @return
*/
int test();
}
interface Cal5{
/**
* 单个参数有返回值
* @param a
* @return
*/
int test(int a);
}
interface Cal6{
/**
* 两个参数有返回值
* @param a
* @param b
* @return
*/
int test(int a,int b);
}
}
方法引用
有时候多个Lambda表达式实现函数是一样的话,我们可以封装成通用方法,以便于维护。
这个时候可以用方法引用实现:
语法是: 对象::方法
假如是static方法,可以直接 类名::方法
实例如下:
public class TestLambda {
public static void main(String[] args) {
TestLambda tl = new TestLambda();
Cal5 cal5=tl::TestA;
System.out.println("输出结果" + cal5.test(5));
Cal5 cal=TestLambda::TestB;
System.out.println("输出结果" + cal5.test(10));
}
public int TestA(int a){
return a - 2;
}
public static int TestB(int a){
return a - 3;
}
interface Cal5{
/**
* 单个参数有返回值
* @param a
* @return
*/
int test(int a);
}
}
构造方法引用
如果函数式接口的实现恰好可以通过调用一个类的构造方法来实现,那么就可以使用构造方法引用。
语法: 类名::new
实例:
先定义一个实体User,实现无参和有参构造方法
public class User {
private String name;
private String age;
public User(){
System.out.println("无参构造方法");
}
public User(String name,String age){
System.out.println("有参构造方法");
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age='" + age + '\'' +
'}';
}
}
在定义两个接口
public class TestService {
public static void main(String[] args) {
/*UserService user = ()->{
return new User();
};
System.out.println(user.getUser());*/
/*UserService user = ()->new User();
System.out.println(user.getUser());*/
UserService user = User::new;
System.out.println(user.getUser());
UserService2 user2 = User::new;
System.out.println(user2.getUser("张三","30"));
}
/**
* 接口一
*/
interface UserService {
User getUser();
}
/**
* 接口二
*/
interface UserService2 {
User getUser(String name,String age);
}
}
测试结果输出:
综合案例实现
先定义一个实体User,实现无参和有参构造方法
public class User {
private String name;
private int age;
public User(){
System.out.println("无参构造方法");
}
public User(String name,int age){
System.out.println("有参构造方法");
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age='" + age + '\'' +
'}';
}
}
测试结果输出:
public class TestService {
public static void main(String[] args) {
List<User> list = new ArrayList<>();
list.add(new User("张三",30));
list.add(new User("李四",28));
list.add(new User("王五",35));
list.add(new User("李思思",28));
list.add(new User("舞王",32));
System.out.println("lambda表达式集合排序");
list.sort((u1,u2)->u1.getAge() - u2.getAge());
System.out.println(list);
System.out.println("lambda表达式遍历集合");
list.forEach(System.out::println);
}
}
@Functionallnterface注解
@Functionallnterface注解;
这个注解是函数式接口注解,所谓的函数式接口,当然首先是一个接口,然后就是这个接口里面只能有一个抽象方法。
这种类型的接口也称为SAM接口,即 Single Abstract Method interfaces
特点:
- 接口有且仅有一个抽象方法。
- 允许定义静态方法。
- 允许定义默认方法。
- 允许java.lang.Object中的public方法
- 该注解不是必须的,如果一个接口符合“函数式接口”定义,那么加不加该注解都没有影响。加上该注解能够更好地让编译器进行检查。如果编写的不是函数式接口,但是加上了@Functionallnterface,那么编译器会报错。
系统内置函数式接口
Java8推出,是以Lambda重要特性,一起推出的,其中系统内置了一系列函数式接口。
在JDK的java.util.function包下,有一系列的内置函数式接口: