Java8之Lambda表达式使用解读
作者:代码大师麦克劳瑞
一、初识Lambda
Lambda 表达式(lambda expression)是一个匿名函数,Lambda表达式基于数学中的λ演算得名,直接对应于其中的lambda抽象(lambda abstraction),是一个匿名函数,即没有函数名的函数。
Lambda表达式可以表示闭包(注意和数学传统意义上的不同)。
这是来自万能的百度百科对于lambda表达式的解释,懂的都懂,不懂的真是听君一席话,如听一席话。
Lambda表达式在Java8中及后续版本占据了举足轻重的地位,对于函数式编程来说是必不可少的一环,所以学会lambda表达式,对于使用Java8的同学是必经之路
举个栗子,Java8中的stream你们不会没有用过吧?什么?你还在用Java7?阿巴阿巴阿巴…好吧,那我直接用代码举个栗子吧。
1.Lambda栗子
需求是这样的,二哥第一次来到了大城市,到了大城市就去了 大 保 健,这个时候肯定就要选女朋友了,根据姓名、大小、价位等,咳咳咳…说错了,是根据姓名、鞋码、身价来选择,二哥要求经理让这些女朋友按照身价来正序排队站好。
@Data @AllArgsConstructor public class Girl { private String name; private Double size; private Double price; }
public static void main(String[] args) { ArrayList<Girl> list = Lists.newArrayList(); list.add(new Girl("露西",33d,2000d)); list.add(new Girl("格蕾丝",36d,3000d)); list.add(new Girl("安娜",28d,1500d)); list.add(new Girl("克瑞斯",31d,1800d)); //匿名函数类实现 list.sort(new Comparator<Girl>() { @Override public int compare(Girl o1, Girl o2) { return o1.getPrice().compareTo(o2.getPrice()); } }); list.stream().forEach(System.out::println); Collections.shuffle(list); System.out.println("-------------我是分隔符-----------------"); //lambda实现 list.sort((Girl g1, Girl g2)-> g1.getPrice().compareTo(g2.getPrice())); list.stream().forEach(System.out::println); }
不难看出,两种方式都实现了让女朋友们按照身价排队。那么我们着重来看看Lambda表达式。
2.Lambda表达式的组成
(Girl g1, Girl g2)-> g1.getPrice().compareTo(g2.getPrice());
- 参数列表:本例中是两个Mask对象的参数,采用的是Comparator接口中compare方法的参数。
- 箭头:->把参数列表和主体分隔为两个部分。
- 主体:本例中是把比较价格的表达式作为Lambda表达式的返回。主体可以修改成另外一种写法,含义是一样的:
list.sort((Girl g1, Girl g2)-> { return g1.getPrice().compareTo(g2.getPrice()); });
由此可以看出,lambda表达式语法格式可以分为两种:
- 1.(parameters) -> expression //参数列表加单条表达式
- 2.(parameters) ->{ statements; } //参数列表加花括号和多条语句
以下是lambda表达式的重要特征:
- 可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
- 可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
- 可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
- 可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定表达式返回了一个数值。
3.举个栗子
// 1. 不需要参数,返回值为 5 () -> 5 // 2. 接收一个参数(数字类型),返回其2倍的值 x -> 2 * x // 3. 接受2个参数(数字),并返回他们的差值 (x, y) -> x – y // 4. 接收2个int型整数,返回他们的和 (int x, int y) -> x + y // 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void) (String s) -> System.out.print(s) // 6.接受两个int参数,多条语句进行比较返回1或者0 (int s1, int s2)->{ if(s1>s2){ return 0; } return 1; }
二、Lambda更进一步
1.类型推断
//lambda实现 list.sort((Girl g1, Girl g2)-> g1.getPrice().compareTo(g2.getPrice())); //lambda简化写法 list.sort((g1, g2)-> g1.getPrice().compareTo(g2.getPrice()));
2.方法引用
方法引用通过方法的名字来指向一个方法。方法引用可以使语言的构造更紧凑简洁,减少冗余代码。方法引用使用一对冒号 :: 。
Comparator<Girl> comparator = (g1, g2)-> g1.getPrice().compareTo(g2.getPrice()); //方法引用 Comparator.comparing(Girl::getPrice);
当你需要方法引用时,目标引用放在分隔符::前,方法的名称放在分隔符::后。
比如,上面的Girl::getPrice,就是引用了Mask中定义的getPrice方法。
方法名称后不需要加括号,因为我们并没有实际调用它。
方法引用提高了代码的可读性,也使逻辑更加清晰,在一些stream流中,相信大家也经常会用到。
例如:
List<String> collect = list.stream().map(Girl::getName).collect(Collectors.toList()); list.stream().forEach(System.out::println);
我们看到第一行通过Girl::getName方法引用,我们收集到了所有女孩的名字,那么第二行我们通过System.out::println打印出了list中的所有对象。
举个栗子:
我们先改造一下实体类,增加了空参构造函数,增加了几个方法,有静态方法和非静态方法。
@Data @AllArgsConstructor @NoArgsConstructor public class Girl { private String name; private Double size; private Double price; //Supplier是jdk1.8的接口,这里和lamda一起使用了 public static Girl create(final Supplier<Girl> supplier) { return supplier.get(); } public static void makeUp(final Girl girl) { System.out.println("化妆 " + girl.toString()); } public void follow(final Girl another) { System.out.println("Following the " + another.toString()); } public void dressUp() { System.out.println("更衣 " + this.toString()); } }
4种不同的方法引用
//构造器引用:它的语法是Class::new,或者更一般的Class< T >::new实例如下: Girl girl = Girl.create(Girl::new); List<Girl> girls = Arrays.asList(girl); //静态方法引用:它的语法是Class::static_method,实例如下: girls.forEach(Girl::makeUp); //特定类的任意对象的方法引用:它的语法是Class::method实例如下: girls.forEach(Girl::dressUp); //特定对象的方法引用:它的语法是instance::method实例如下: girls.forEach(girl::follow);
到这里,大家对lambda表达式应该有了初步的认识,可以在平时编码中多使用,毕竟实践出真知!!
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。