Lambda表达式是Java SE 8中引入的一个重要特性,它允许我们通过表达式来代替功能接口。Lambda表达式提供了一个正常的参数列表和一个使用这些参数的主体。Lambda表达式的引入使得Java的集合库得到了增强,Java SE 8添加了两个用于对集合数据进行批量操作的包:java.util.function和java.util.stream。
Lambda表达式的作用和使用场景如下:
- 代替匿名内部类:Lambda表达式可以简化匿名内部类的写法,使代码更加简洁易读。
- 函数式编程:Lambda表达式可以将函数作为参数传递给其他方法,实现函数式编程的思想。
- 并行处理:通过Stream API结合Lambda表达式,可以方便地进行并行处理,提高程序的性能.
Lambda表达式的语法如下:
基本语法: (parameters) -> expression 或 (parameters) ->{ statements; }
(parameter1, parameter2, ...) -> {
// Lambda表达式的主体
}
Lambda表达式的参数列表可以为空,也可以有多个参数,主体部分可以是一个表达式或一个代码块。如果主体部分是一个表达式,则可以省略大括号和return关键字;如果主体部分是一个代码块,则需要使用大括号,并且需要使用return关键字返回结果。
Lambda表达式引用局部变量时,该变量必须是final或事实上的final(即不可修改的)。
下面是一个使用Lambda表达式的例子:
List<String> list = Arrays.asList("apple", "banana", "orange");
list.forEach(item -> System.out.println(item));
这个例子中,我们使用Lambda表达式遍历了一个字符串列表,并打印出每个字符串。
简单示例:
// 1. 不需要参数,返回值为 5
() -> 5
// 2. 接收一个参数(数字类型),返回其2倍的值
x -> 2 * x
// 3. 接受2个参数(数字),并返回他们的差值
(x, y) -> x – y
// 4. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)
(String s) -> System.out.print(s)
String[] atp = {"Ruby", "Jason", "Candy", "David"};
List<String> players = Arrays.asList(atp);
// 以前的循环方式
for (String player : players) {
System.out.print(player + "; ");
}
// 使用 lambda 表达式以及函数操作(functional operation)
players.forEach((player) -> System.out.print(player + "; "));
// 在 Java 8 中使用双冒号操作符(double colon operator) 此现象较静态引用。
players.forEach(System.out::println);
方法引用:
方法引用是用来直接访问类或者实例的已经存在的方法或者构造方法。
注意方法引用是一个Lambda表达式,其中方法引用的操作符是双冒号"::"。有以下几种情况:
1. 类名::静态方法名
public class Student {
private String name;
private int score;
public Student(){
}
public Student(String name,int score){
this.name = name;
this.score = score;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
public static int compareStudentByScore(Student student1,Student student2){
return student1.getScore() - student2.getScore();
}
public static int compareStudentByName(Student student1,Student student2){
return student1.getName().compareToIgnoreCase(student2.getName());
}
}
Student student1 = new Student("zhangsan",80);
Student student2 = new Student("lisi",70);
Student student3 = new Student("wangwu",60);
List<Student> students = Arrays.asList(student1,student2,student3);
students.sort((c1, c2) -> c1.getScore() - c2.getScore());
students.forEach(student -> System.out.println(student.getScore()));
以下使用 类名::静态方法名 方法引用替换lambda表达式 :
students.sort(Student::compareStudentByScore);
students.forEach(student -> System.out.println(student.getScore()));
2. 对象::实例方法名
定义一个用于比较Student元素的类
public class StudentComparator {
public int compareStudentByScore(Student student1,Student student2){
return student2.getScore() - student1.getScore();
}
}
StudentComparator中定义了一个非静态的实例方法compareStudentByScore,同样该方法的定义满足Comparator接口的compare方法定义,所以这里可以直接使用 对象::实例方法名 的方式使用方法引用来替换lambda表达式:
StudentComparator studentComparator = new StudentComparator();
students.sort(studentComparator::compareStudentByScore);
students.forEach(student -> System.out.println(student.getScore()));
3. 类名::实例方法名
无论是通过类名调用静态方法还是通过对象调用实例方法这都是符合Java的语法。实例方法:
public int compareByScore(Student student){
return this.getScore() - student.getScore();
}
接收一个Student对象和当前调用该方法的Student对象的分数进行比较即可。现在我们就可以使用 类名::实例方法名 这种方式的方法引用替换lambda表达式了
students.sort(Student::compareByScore);
students.forEach(student -> System.out.println(student.getScore()));
类名::实例方法名 这种方法引用的特殊之处:当使用 类名::实例方法名 方法引用时,是lambda表达式所接收的第一个参数来调用实例方法,如果lambda表达式接收多个参数,其余的参数作为方法的参数传递进去。最初的lambda表达式是这样的:
students.sort((c1, c2) -> c1.getScore() - c2.getScore());
那使用 类名::实例方法名 方法引用时,一定是c1来调用了compareByScore实例方法,并将c2作为参数传递进来进行比较。
4. 对象的超类方法引用语法: super::methodname
public class Example extends BaseExample{
public void test() {
List<String> list = Arrays.asList("aaaa", "bbbb", "cccc");
//对象的超类方法语法: super::methodName
list.forEach(super::print);
}
}
class BaseExample {
public void print(String content){
System.out.println(content);
}
}
5. 类构造器引用语法: classname::new 例如:ArrayList::new
public class Example {
private String name;
Example(String name){
this.name = name;
}
public static void main(String[] args) {
InterfaceExample com = Example::new;
Example bean = com.create("hello world");
System.out.println(bean.name);
}
}
interface InterfaceExample{
Example create(String name);
}
6. 数组构造器引用语法: typename[]::new 例如: String[]:new
public class Example {
public static void main(String[] args) {
Function <Integer, Example[]> function = Example[]::new;
Example[] array = function.apply(4); //这里的4是数组的大小
for(Example e:array){
System.out.println(e); //如果输出的话,你会发现会输出4个空对象(null)
}
}
}