Lambda表达式是给函数式接口(SAM接口)的变量或形参赋值的表达式。 Lambda表达式替代了原来使用匿名内部类的对象给函数式接口(SAM接口)的变量或形参赋值的形式。
匿名内部类:实现了这个接口,重写了接口的抽象方法,同时创建了对象。 Lambda表达式也要实现这个接口,重写接口的抽象方法,隐含的创建了对象。
既然Lambda表达式是SAM接口的变量或形参赋值的,那么实现接口这部分语法可以省略,SAM接口的抽象方法只有一个,因此方法签名可以省略一部分。例如:修饰符,返回值类型、方法名可以省略,但是其中的形参列表不能省略,因此这里表表现形参类型和形参名,这个在方法体的实现中要使用。
Lambda表达式语法格式: (形参列表) -> {Lambda体}
说明:(1)(形参列表)就是SAM接口的抽象方法的形参列表 (2){Lambda体}就是实现SAM接口的抽象方法的方法体 (3)->称为Lambda操作符,由“减号”和“大于号”构成,中间不能有空格
案例一: @Test public void test01(){ //使用Lambda表达式给Runnable接口的形参赋值,这个线程要打印“尚硅谷" //构造器:new Thread(Runnable target) //现在要用Lambda表达式给Runnable类型的target形参赋值 /* * 写好一个Lambda表达式关注两个事情: * (1)抽象方法长什么样 -->确定形参列表怎么写 * public void run() * (2)抽象方法怎么实现,即这个抽象方法要做什么事情 -->Lambda体 */ //new Thread(() -> {System.out.println("尚硅谷");}).start();//原始的Lambda这样写的 //优化 new Thread(() -> System.out.println("尚硅谷")).start(); }优化: (1)如果{Lambda体}只有一句语句,可以省略{}以及{}中的语句的结束;,如果{}没有省略的话,;就不能省略 (2)如果(形参列表)中形参的类型是已知的,获取可以推断,那么数据类型可以省略 (3)如果(形参列表)只有一个形参,并且数据类型也已经省略了,那么这个()可以省略了,如果数据类型没有省略,()不能省略 (4)如果{Lambda体}只有一句语句,并且是一个return语句,那么可以省略{}以及{}中的语句的结束;还有return。 (5)如果没有形参,()不能省略
案例二: @Test public void test02(){ /* * 在Java8版本,给Iterable<T>这个接口增加一个默认方法 * default void forEach(Consumer<? super T> action) 这个方法可以遍历容器中的元素,做xx事情 * * Collection<E>接口继承了Iterable<T>接口,说明Collection系列的集合都有这个方法,例如:ArrayList * */ ArrayList<String> list = new ArrayList<>(); list.add("hello"); list.add("world"); list.add("java"); list.add("atguigu"); /* * forEach方法的形参是Consumer类型,它是消费型接口的类型,是SAM接口,就可以使用Lambda表达式赋值 * (1)接口的抽象方法 * void accept(T t) 这里方法名不重要,只看返回值类型和形参列表 * (2)要如何实现这个抽象方法,例如:我这里要打印元素 */ // list.forEach((String str) -> {System.out.println(str);}); // 优化 // list.forEach((String str) -> System.out.println(str)); //再优化 list.forEach((str) -> System.out.println(str)); //再优化 list.forEach(str -> System.out.println(str)); } 案例三: @Test public void test03(){ //从集合中删除字符个数超过6个的 ArrayList<String> list = new ArrayList<>(); list.add("hello"); list.add("world"); list.add("java"); list.add("atguigu"); /* * Java8中Collection接口增加了一个方法 * default boolean removeIf(Predicate<? super E> filter) * 这个方法的形参是Predicate判断型接口,是SAM接口,可以使用Lambda表达式赋值 * * Predicate<T>判断型接口 * (1)抽象方法 * boolean test(T t) * (2)如何实现抽象方法 * 这里判断条件是 字符个数>6 */ /* list.removeIf((String str) -> { if(str.length()>6){ return true; }else{ return false; } });*/ //代码优化,跟Lambda没关系 //str.length()>6是true返回true,是false返回false,可以省略直接返回str.length()>6的值 list.removeIf((String str) -> {return str.length()>6;}); //再优化 因为Lambda体只有一句 list.removeIf(str -> str.length()>6); }1:Supplier和Consumer
public class Test04Lambda2 { @Test public void test01(){ /* * Java8中,有一个新的类:Stream类型,它代表一个数据加工流 * Stream数据加工流和IO流奴一样,IO流是文件读取和写到文件,是数据传输流,Stream是数据加工流 * java.util.stream.Stream<T>接口 * static <T> Stream<T> generate(Supplier<T> s) * * 这个静态方法的形参:Supplier<T>供给型接口的类型,SAM接口,可以使用Lambda表达式赋值 * 接口的静态方法通过“接口名.静态方法”调用 * * Supplier<T>接口 * (1)抽象方法 T get() * (2)抽象方法如何实现 * 例如:在抽象方法中实现,随机产生一个小数[0,1),返回值类型double * //写Double而不写double原因:泛型不能用基本数据类型,只能用引用数据类型 */ // Stream<Double> stream = Stream.generate(() -> {return Math.random();}); //优化 Stream<Double> stream = Stream.generate(() -> Math.random()); /* * 为了看效果,我再调用Stream<T>接口的void forEach(Consumer<? super T> action) * 这个方法形参是Consumer<T>消费型接口类型,SAM接口,也可以使用Lambda表达式赋值 * * Consumer<T>消费型接口: * (1)抽象方法 * void accept(T t) * (2)如何实现抽象方法 * 例如:打印流中的元素 * */ // stream.forEach((Double num) -> {System.out.println(num);}); //优化 stream.forEach(num -> System.out.println(num)); } }是一个无限流,不停的产生符合要求的小数
2:BiFunction JDK1.8时Map接口增加了一个方法: default void replaceAll(BiFunction<? super K,? super V,? extends V> function)
class Employee { private String name; private double salary; public Employee(String name, double salary) { super(); this.name = name; this.salary = salary; } public Employee() { super(); } public String getName() { return name; } public void setName(String name) { this.name = name; } public double getSalary() { return salary; } public void setSalary(double salary) { this.salary = salary; } @Override public String toString() { return "Employee [name=" + name + ", salary=" + salary + "]"; } @Test public void test01(){ HashMap<String,Employee> map = new HashMap<>(); map.put("张三", new Employee("张三", 8000)); map.put("李四", new Employee("李四", 9000)); map.put("王五", new Employee("王五", 12000)); map.put("赵六", new Employee("赵六", 11000)); //把原来薪资低于10000元的,修改为薪资为10000元,其他的不变 /* * replaceAll(BiFunction<? super K,? super V,? extends V> function) * * replaceAll的形参是BiFunction<T,U,R>接口类型,SAM接口,可以使用Lambda表达式赋值 * * BiFunction<T,U,R>接口: * (1)抽象方法 * R apply(T t, U u) * (2)如何实现抽象方法 * 例如:把原来value对象的薪资<10000元的替换(覆盖)为薪资是10000元 * * 如果抽象方法有返回值,那么实现抽象方法时,需要return语句。 * 这里看返回值类型是V类型,是value的类型 */ map.replaceAll((String key,Employee emp) -> { if(emp.getSalary()<10000){ emp.setSalary(10000); } return emp;//return放if判断外面,放if判断里面会报错,不管改不改,都要返回emp }); //优化 map.replaceAll((key,emp) -> { if(emp.getSalary()<10000){ emp.setSalary(10000); } return emp; }); } }