1.概念
lambda表达式是特殊的匿名内部类,语法更简洁。
lambda表达式允许把函数作为一个方法的参数(函数作为方法参数传递),将代码像数据一样传递。
2.语法
<函数式接口><变量名>=(参数1,参数2)->{ 方法体 }
函数式接口:接口中只有一个抽象方法。
参数1,参数2:抽象方法的参数。
->:分隔符。
{ }:表示抽象方法的实现。
public class Test { public static void main(String[] args) { My my=new My(); // 该构造方法需要传递一个线程任务对象--Runnable类型 Thread t1=new Thread(my); t1.start(); // 第二种:匿名内部类 Runnable task=new Runnable() { public void run() { System.out.println("匿名内部类的任务对象"); } }; Thread t2=new Thread(task); t2.start(); // 第三种:lambda表达式 Runnable task2= ()-> { System.out.println("lambda表达式"); }; Thread t3=new Thread(task2); t3.start(); } } //第一种:创建类并实现Runnable接口 class My implements Runnable{ public void run() { System.out.println("自定义任务接口类"); } }
无参数值
public class Test { public static void main(String[] args) { // 匿名内部类 Swimmable swimmable=new Swimmable() { @Override public void swimming() { System.out.println("匿名内部类"); } }; // 需要一个函数接口可以使用匿名内部类 fun(swimmable); // lambda表达式 /* Swimmable swimmable1=()->{ System.out.println("lambda表达式"); }; fun(swimmable1);*/ fun(()->{ System.out.println("使用lambda表达式"); }); } // 自定义的方法并调用了Swimmable接口 public static void fun(Swimmable w){ w.swimming(); } } //自定义函数式接口 @FunctionalInterface//强制是一个接口,检查是不是一个函数 interface Swimmable{ void swimming(); }
有参数值
public class Test02 { public static void main(String[] args) { List<Person> list=new ArrayList<>(); list.add(new Person("刘陌",23,160)); list.add(new Person("吴铭",26,180)); list.add(new Person("姜娇娇",22,168)); list.add(new Person("张文莉",23,165)); list.add(new Person("王芯妍",21,160)); // 对集合中的元素进行排序,按照年龄从大到小 // 传统做法:Comparator:排序规则接口 Comparator<Person> comparator=new Comparator<Person>() { // int:0表示新加的元素和集合中原来的比对系统 // 1:o2比o1小 // -1:o2比o1大 @Override public int compare(Person o1, Person o2) { return o2.getAge()- o1.getAge(); } }; Collections.sort(list,comparator); for (Person p:list){ System.out.println(p); } System.out.println("==============================lambda========================"); // 使用lambda将年龄从小到大排序 Comparator<Person> personComparator=( o1, o2)->{ return o1.getAge()- o2.getAge(); }; Collections.sort(list,personComparator); for (Person p:list){ System.out.println(p); } } } @Data @NoArgsConstructor @AllArgsConstructor class Person{ private String name; private int age; private int height; public Person(int height, int age, String name) { this.height = height; this.age = age; this.name = name; } public Person(String name) { this.name = name; } }
注意:
形参列表的数据类型会自动推断
如果形参列表为空,只需保留()
如果形参只有1个,()可以省略,只需要参数的名称即可
如果执行语句只有一句,且无返回值,{ }可以省略,若有返回值,则若想省去{ },则必须同时省略return,且执行语句也保证只有一句
lambda不会生成一个单独的内部类文件
3.函数式接口
什么是接口:如果一个接口只有一个抽象方法,则该接口称之为函数式接口,函数式接口可以使用lambda表达式,lambda表达式会被匹配到这个抽象方法上。
@Functionallnterface注解:检测接口是否符合函数式接口
public class Test { public static void main(String[] args) { Operater o=arr -> { int sum=0; for(int n:arr){ sum+=n; } System.out.println("数组的和:"+sum); }; fun(o); } public static void fun(Operater operater){ int[] arr={2,4,5,7,8,23,1}; operater.getSum(arr); } } @FunctionalInterface interface Operater{ public abstract void getSum(int[] arr); }
4.常见的函数式接口
消费型:Consumer<T>--有参无返回值
public class Test { public static void main(String[] args) { Consumer<Double> c=t->{ System.out.println("吃饭花费了:"+t); }; fun01(c,200); } public static void fun01(Consumer<Double> consumer,double money){ consumer.accept(money); } }
供给型:Supplier<T>--无参有返回结果的函数式接口时
public class Test02 { public static void main(String[] args) { Supplier<Integer> s=()->{ return new Random().nextInt(10); }; fun(s); } public static void fun(Supplier<Integer> supplier){ Integer i = supplier.get(); System.out.println("随机生成数字:"+i); } }
函数式接口:Function<T,R>--有参有返回结果时
T:参数类型的泛型
R:函数返回结果的泛型
public class Test03 { // 要求传入的小写字符串转成大写 public static void main(String[] args) { fun((t)->{ return t.toUpperCase(); },"hello world"); } public static void fun(Function<String,String> function,String str){ String apply = function.apply(str); System.out.println("转化结果为:"+apply); } }
断言型:Predlicate<T>--当传入一个参数时,需要对该参数进行判断时
public class Test04 { public static void main(String[] args) { fun(n->{ return n.length()>3?true:false; },"迪丽热巴"); } public static void fun(Predicate<String> predicate,String name){ boolean test = predicate.test(name); System.out.println("该名字的长度是否大于3:"+test); } }
4.方法引用
lambda表达式的冗余
public class Test { public static void main(String[] args) { Consumer<Integer[]> c=t->{ int sum=0; for (int i:t){ sum+=i; } System.out.println("数组的和:"+sum); }; fun(c); } public static void fun(Consumer<Integer[]> consumer){ Integer[] arr={2,5,3,45}; consumer.accept(arr); } public static void sum(Integer[] arr){ int sum=0; for (int a:arr){ sum+=a; } System.out.println("数组的和:"+ sum); } }
分析:如果我们在lambda中所指定的功能,已经有其他方法存在相同方案,那是否还有必要写重复逻辑?直接引用过去就好了:--方法引用
public class Test { public static void main(String[] args) { Consumer<Integer[]> c=Test::sum; fun(c); } public static void fun(Consumer<Integer[]> consumer){ Integer[] arr={2,5,3,45}; consumer.accept(arr); } public static void sum(Integer[] arr){ int sum=0; for (int a:arr){ sum+=a; } System.out.println("数组的和:"+ sum); } }
5.什么是方法引用
方法引用是lambda表达式的一种简写形式,如果lambda表达式方法体中只有是调用一个特定的已经存在的方法,则可以使用方法引用。
常见形式:
对象::实例方法
类::静态方法
类::实例方法
类::new
6.方法引用的分类
静态方法引用
public class Test { public static void main(String[] args) { List<Integer> list=new ArrayList<>(); list.add(1); list.add(30); list.add(5); list.add(7); Comparator<Integer> c=Integer::compare; list.sort(c); System.out.println(list); } }
实例方法引用--顾名思义就是调用已经存在的实例的方法,与静态方法引用不同的是类要先实例化,静态方法引用类无需实例化,直接用类名去调用
public class Test02 { public static void main(String[] args) { People people=new People("刘陌",23); Supplier<String> s=people::getName; fun(s); } public static void fun(Supplier<String> supplier){ String s = supplier.get(); System.out.println("姓名:"+s); } } @Data @NoArgsConstructor @AllArgsConstructor class People{ private String name; private Integer age; public static int fun(People p1, People p2){ return p1.getAge()-p2.getAge(); }
对象方法引用--类名::实例方法
public class Test03 { public static void main(String[] args) { Function<String,Integer> function=(str)->{ return str.length(); }; Function<String,Integer> function=String::length; Integer len=function.apply("hello"); System.out.println(len); // 比较两个字符串的内容是否一样 BiFunction<String,String,Boolean> bi=String::equals; Boolean apply = bi.apply("Hello", "Hello"); System.out.println(apply); } @Data @NoArgsConstructor @AllArgsConstructor static class People{ private String name; } }
构造方法引用
public class Test03 { public static void main(String[] args) { Function<String,People> f=People::new; People p = f.apply("张三"); System.out.println(p); } @Data @NoArgsConstructor @AllArgsConstructor static class People{ private String name; } }