Lambda表达式是函数式编程的风格,是为了给SAM接口(唯一的抽象方法)的变量和形参赋值的一种语法。很多语言都支持Lambda表达式,比如Java、c、c++ 目的:减少代码的冗余,增加可读性。
示例1: 开启一个线程,这个线程的任务:打印“hello” 要求用实现Runnable接口的方式来创建多线程
@Test public void test01(){ // 非Lambda表达式方式实现,并且有名字的实现类实现 MyRunnable my = new MyRunnable(); Thread t = new Thread(my); t.start(); } } class MyRunnable implements Runnable{ @Override public void run() { System.out.println("hello"); }改成匿名的内部类实现,有对象名字
@Test public void test02(){ //匿名内部类,对象有名字 Runnable my = new Runnable(){ @Override public void run() { System.out.println("hello"); } }; Thread t = new Thread(my); t.start(); }匿名内部类,匿名对象
@Test public void test03(){ //匿名内部类,匿名对象 Thread t = new Thread(new Runnable(){ @Override public void run() { System.out.println("hello"); } }); t.start(); } //或者写为 @Test public void test04(){ //匿名内部类,匿名对象 new Thread(new Runnable(){ @Override public void run() { System.out.println("hello"); } }).start(); }使用Lambda实现。 Runnable接口符合SAM特征: public abstract void run();
@Test public void test05(){ //使用Lambda表达式 new Thread(()->System.out.println("hello")).start(); } //很简洁 //因为Runnable接口符合SAM特征: public abstract void run();所以可以省略示例二: 有一个数组,存储了5个学生对象,这个学生类的自然排序是按照编号排序。但是我希望这个数组是按照姓名排序 Comparator符合SAM接口的特征: public abstract int compare(T t1, T t2)
class Student implements Comparable<Student>{ private int id; private String name; public Student(int id, String name) { super(); this.id = id; this.name = name; } public Student() { super(); } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Student [id=" + id + ", name=" + name + "]"; } @Override public int compareTo(Student o) { return this.id - o.id; } } @Test public void test01(){ Student[] arr = new Student[5]; arr[0] = new Student(1,"zhangsan"); arr[1] = new Student(2,"lisi"); arr[2] = new Student(3,"wangwu"); arr[3] = new Student(4,"zhaoliu"); arr[4] = new Student(5,"qianqi"); Arrays.sort(arr);//按照元素的自然顺序排列 for (Student student : arr) { System.out.println(student); } }以上代码是自然排序按照编号排序, 按照姓名排序(需要定制排序)
class NameComparator implements Comparator<Student>{ @Override public int compare(Student o1, Student o2) { return o1.getName().compareTo(o2.getName()); } } @Test public void test02(){ Student[] arr = new Student[5]; arr[0] = new Student(1,"zhangsan"); arr[1] = new Student(2,"lisi"); arr[2] = new Student(3,"wangwu"); arr[3] = new Student(4,"zhaoliu"); arr[4] = new Student(5,"qianqi"); Arrays.sort(arr, new NameComparator());//按照元素的姓名定制排序 for (Student student : arr) { System.out.println(student); } }改为匿名内部类实现
@Test public void test03(){ Student[] arr = new Student[5]; arr[0] = new Student(1,"zhangsan"); arr[1] = new Student(2,"lisi"); arr[2] = new Student(3,"wangwu"); arr[3] = new Student(4,"zhaoliu"); arr[4] = new Student(5,"qianqi"); Arrays.sort(arr, new Comparator<Student>(){ @Override public int compare(Student o1, Student o2) { return o1.getName().compareTo(o2.getName()); } });//按照元素的姓名定制排序 for (Student student : arr) { System.out.println(student); } }改为Lambda实现
@Test public void test04(){ Student[] arr = new Student[5]; arr[0] = new Student(1,"zhangsan"); arr[1] = new Student(2,"lisi"); arr[2] = new Student(3,"wangwu"); arr[3] = new Student(4,"zhaoliu"); arr[4] = new Student(5,"qianqi"); Arrays.sort(arr, (o1, o2)-> o1.getName().compareTo(o2.getName()));//按照元素的姓名定制排序 for (Student student : arr) { System.out.println(student); } }代码更简洁
Lambda表达式是对匿名内部类的简化,且匿名内部类是实现SAM的接口的匿名内部类才行
函数式接口:SAM接口 Single Abstract Method,即该接口中只有一个抽象方法需要实现,当然该接口可以包含其他非抽象方法(默认方法和静态方法,或者是从Object继承的方法)。
回忆之前学过的接口: (1)Runnable (2)Comparable (3)Comparator (4)Iterable (5)Iterator (6)Collection,Set,List,Map,Queue,Deque… (7)Serializable (8)Externalizable (9)FileFilter (10)InvocationHandler …
哪些是符号SAM特征的呢? (1)Runnable public void run() (2)Comparable public int compareTo(T t) (3)Comparator public int compare(T t1, T t2) (4)Iterable public Iterator iterator() (5)FileFilter public boolean accept(File pathname); (6)InvocationHandler public Object invoke(Object proxy, Method method, Object[] args)
按照语法来说,只要符号SAM特征的接口,都可以使用Lambda表达式。 但是Java建议只针对标记了@FunctionalInterface这注解的SAM接口使用Lambda表达式
上面哪些标记了@FunctionalInterface注解: (1)Runnable public void run() (3)Comparator public int compare(T t1, T t2) (5)FileFilter public boolean accept(File pathname);
如果没有标记@FunctionalInterface注解的,说明它考虑了以后可能增加抽象方法。目前使用没问题,就是以后可能有风险。