lambda出现的背景
Java 是一流的面向对象语言,除了部分简单数据类型,Java 中的一切都是 对象,即使数组也是一种对象,每个类创建的实例也是对象。在 Java 中定义的函数或方法不可能完全独立,也不能将方法作为参数或返回一个方法给实例。在 Java 8 以前,若我们想要把某些功能传递给某个方法,总要去写匿名类。
简而言之,在 Java 里将普通的方法或函数像参数一样传值并不简单,为此,Java 8 增加了一个语言级的新特性,名为 Lambda 表达式。
lambda表达式简介
lambda表达式是匿名函数(独立的),我们可以把 lambda 表达式理解为一段可以传递的代码(将代码段像数据一样传递)。使用它可以写出更简洁, 更灵活的代码。作为一种更紧凑的代码风格,使 java 语言的表达式能力得到的提升。
Lambda 表达式的本质只是一个"语法糖",由编译器推断并帮你转换包装为常规的代码,因此你可以使用更少的代码来实现同样的功能。
public class Student {
private int no;
private String name;
public Student(int no, String name) {
this.no = no;
this.name = name;
}
@Override
public String toString() {
return "Student{" +
"no=" + no +
", name='" + name + '\'' +
'}';
}
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class Demo {
/*
lambda表达式是匿名函数(独立的)
*/
public static void main(String[] args) {
Student s1 = new Student(101, "jim1");
Student s2 = new Student(102, "jim2");
Student s3 = new Student(103, "jim3");
Student s4 = new Student(104, "jim4");
Student s5 = new Student(105, "jim5");
ArrayList<Student> students = new ArrayList<>();
students.add(s2);
students.add(s3);
students.add(s1);
students.add(s5);
students.add(s4);
System.out.println(students);//按照23154存储内容输出
}
}
-
students.sort(); Arrays.sort(); Collections.sort();
sort方法中传入Comparator<? super E> c -
Comparator是一个排序比较接口,里面定义了一个比较的方法,但是没有实现。
有4种做法:
1.写一个Comparator接口的实现类(单独的类,此类只用于学生排序)/* 自定义一个学生排序类,实现sort方法中的接口 */ public class StudentComparator implements Comparator<Student> { @Override public int compare(Student o1, Student o2) { return o1.getNo()-o2.getNo(); } } public class Demo { public static void main(String[] args) { Student s1 = new Student(101, "jim1"); Student s2 = new Student(102, "jim2"); Student s3 = new Student(103, "jim3"); Student s4 = new Student(104, "jim4"); Student s5 = new Student(105, "jim5"); ArrayList<Student> students = new ArrayList<>(); students.add(s2); students.add(s3); students.add(s1); students.add(s5); students.add(s4); students.sort(new StudentComparator()); //对其进行排序 System.out.println(students); //按顺序输出 } }
2.将学生排序的功能写成一个内部类,将功能封装在类的内部,内部类也是需要定义一个类的。
/* 这叫一个.java文件中,写了两个类 */ class Demo1{ } class Demo2{ }
public class Demo { public static void main(String[] args) { Student s1 = new Student(101, "jim1"); Student s2 = new Student(102, "jim2"); Student s3 = new Student(103, "jim3"); Student s4 = new Student(104, "jim4"); Student s5 = new Student(105, "jim5"); ArrayList<Student> students = new ArrayList<>(); students.add(s2); students.add(s3); students.add(s1); students.add(s5); students.add(s4); students.sort(new StudentComparator()); System.out.println(students); } /* 内部类也是属于外部类的成员,也需要是静态的 */ static class StudentComparator implements Comparator<Student> { @Override public int compare(Student o1, Student o2) { return o1.getNo()- o2.getNo(); } } }
3.在内部类的基础上,为了进一步的简化语法,java中推出了匿名内部类。
new + 接口名/抽象类名 都不是在创建接口/抽象类对象,是在创建一个匿名的类的对象,有一个匿名的类实现了此接口。
外部类、内部类、匿名内部类,核心都是对排序比较的方法进行实现,将方法包装在一个对象中,传递给
了sort()方法。public class Demo { public static void main(String[] args) { Student s1 = new Student(101, "jim1"); Student s2 = new Student(102, "jim2"); Student s3 = new Student(103, "jim3"); Student s4 = new Student(104, "jim4"); Student s5 = new Student(105, "jim5"); ArrayList<Student> students = new ArrayList<>(); students.add(s2); students.add(s3); students.add(s1); students.add(s5); students.add(s4); students.sort(new Comparator<Student>() { @Override public int compare(Student o1, Student o2) { return o1.getNo()- o2.getNo(); } }); System.out.println(students); } }
4.java8之后,对匿名内部类的写法进行了简化,可以将函数直接作为参数传递。
public class Demo { /* lambda表达式是匿名函数(独立的) */ public static void main(String[] args) { Student s1 = new Student(101, "jim1"); Student s2 = new Student(102, "jim2"); Student s3 = new Student(103, "jim3"); Student s4 = new Student(104, "jim4"); Student s5 = new Student(105, "jim5"); ArrayList<Student> students = new ArrayList<>(); students.add(s2); students.add(s3); students.add(s1); students.add(s5); students.add(s4); //lambda表达式 students.sort((o1,o2)->{return o1.getNo()- o2.getNo(); }); //上式等同于下式 //常规代码 Comparator<Student> c = (o1,o2)->{ return o1.getNo()- o2.getNo(); }; students.sort(c); System.out.println(students); } }
lambda的基本语法
最简答的lambda表达式,没有方法也没有返回值。
使用lambda 要求是接口/抽象类中只能有一个抽象的方法,用于类型推断。
()参数列表 ->{ } 函数体
无参:
@FunctionalInterface //修饰的是功能接口,其中只能有一个抽象方法
public interface LambdaInterface {
public abstract void test();
public static void testStatic(int a ){
}
}
public class TestLambda {
public static void main(String[] args) {
//对void test方法进行了实现,且只能有一个抽象方法,并对其进行修饰
LambdaInterface lam = ()->{
System.out.println("aaaaaa");
};
}
}
有参:
public interface LambdaInterface {
public abstract void test(int a ,int b);
}
public class TestLambda {
public static void main(String[] args) {
LambdaInterface lam = (a,b)->{
System.out.println("aaaaaa"+a+b);
};
}
}
有返回值:
public interface LambdaInterface {
public abstract int test(int a ,int b);
}
public class TestLambda {
public static void main(String[] args) {
LambdaInterface lam = (a,b)->{
return a+b;
};
}
}
总结:
- Lambda 表达式可以具有零个,一个或多个参数。
- 可以显式声明参数的类型,也可以由编译器自动从上下文推断参数的类型。 例如 (int a,int b)与 (a,b)相同。
- 参数用小括号括起来,用逗号分隔。例如 (a, b) 或 (int a, int b) 或 (String a, int b, float c)。
- 空括号用于表示一组空的参数。例如 () -> 42。
- 当有且仅有一个参数时,如果不显式指明类型,则不必使用小括号。 例如 a -> return a*a。
- Lambda 表达式的正文可以包含零条,一条或多条语句。
- 如果 Lambda 表达式的正文只有一条语句,则大括号可不用写,且表达式 的返回值类型要与匿名函数的返回类型相同。
- 如果 Lambda 表达式的正文有一条以上的语句必须包含在大括号(代码块)中,且表达式的返回值类型要与匿名函数的返回类型相同。
lambda的应用:
//创建线程,用lambda实现
new Thread(
()->{
System.out.println("线程要做得事情");
}
).start();
//GUI组件添加事件监听
JButton jb = new JButton("按钮");
jb.addActionListener((e)->{
});
功能接口
Lambda 表达式只支持函数式接口 也就是只有一个抽象方法的接口.功能接口是 java 8 中的新增功能,它们只允许一个抽象方法。这些接口也称为单抽 象方法接口。Java 8 也引入了一个注释,即@FunctionalInterface,当你注释的接口违反了 Functional Interface 的契约时,它可以用于编译器级错误。