Lambda表达式是 Java 8 的新特性。许多语言都有 Lambda 的特性。
因此使用的 Java 环境一定要 8 以上的环境。
到底什么是 Lambda 表达式呢?
Lambda 表达式,也可称为闭包。Lambda 允许把函数作为一个方法的参数直接传递到方法中去。可以让我们不用费神去给函数起名。但是 Lambda 也只适合于简单的函数,对于复杂的函数,写成 Lambda 的形式反而会让人更加看不懂。
接下来用一个实例慢慢导入 Lambda,要完成的是一个判断Person的id是否大于90的功能
首先创建一个Person类,包含 id 属性1 packageperson;2 3 /// 4 / Person类5 /@authorjyroy6 /7 // 8 public classPerson {9 @SuppressWarnings("unused")10 public intid;11 12 publicPerson() {13 14 }15 16 public Person(intid) {17 this.id =id;18 }19 20 @Override21 publicString toString() {22 return "Person [id=" + id + "]";23 }24 25 }
用普通方法,在 for 循环中通过 if 进行条件判断 if(person.id>90) 1 packagenormal;2 3 importjava.util.ArrayList;4 importjava.util.List;5 importjava.util.Random;6 7 importlambda.Check;8 importperson.Person;9 10 public classTestLambda {11 @SuppressWarnings({ "rawtypes", "unused", "unchecked"})12 public static voidmain(String[] args) {13 Random r = new Random(); //随机生成100个数 14 List
结果
创建一个匿名类,通过匿名类来实现这个判断 id 大于90的功能。
首先提供匿名类需要的接口,用于创建一个判断的类1 packageanonymity;2 3 importperson.Person;4 5 public interfacePersonCheck {6 public booleantest(Person person);7 }
通过匿名类实现接口
1 //使用 匿名类的方式 筛选出大于90的数据 2 PersonCheck personCheck = newPersonCheck() {3 @Override4 public booleantest(Person person) {5 return person.id>90;6 }7 };
实现之后,就可以在judge函数中调用personCheck实例的test函数进行处理
1 packageanonymity;2 3 importjava.util.ArrayList;4 importjava.util.List;5 importjava.util.Random;6 7 importlambda.Check;8 importperson.Person;9 10 /// 11 / 匿名类方式12 /@authorjyroy13 /14 // 15 public classTestLambda {16 @SuppressWarnings({ "rawtypes", "unused", "unchecked"})17 public static voidmain(String[] args) {18 Random r = newRandom();19 List
结果
接下来就是Lambda方式了
先上 Lambda表达式的写法,运行过程序之后再做总结1 person->person.id>90
这便是一个Lambda表达式的形式,先记住这个形式,这个形式就是判断 person.id>90。
1 packagelambda;2 3 importjava.util.ArrayList;4 importjava.util.List;5 importjava.util.Random;6 7 importanonymity.PersonCheck;8 importperson.Person;9 10 /// 11 / Lambda表达式12 /@authorjyroy13 /14 // 15 public classTestLambda {16 17 @SuppressWarnings({ "rawtypes", "unused", "unchecked"})18 public static voidmain(String[] args) {19 Random r = newRandom();20 List
结果
实现了同样的效果
上面的程序中使用了 Lambda表达式,完成了判断的功能,而且相比匿名类的写法要简单非常多,使用 Lambda 表达式可以使代码变的更加简洁紧凑。
Lambda 表达式的语法格式:1 (parameters) ->expression2 或3 (parameters) ->{ statements; }
以下是lambda表达式的重要特征:
简单的例子1 //1. 不需要参数,返回值为 5 2 () -> 5 3 4 //2. 接收一个参数(数字类型),返回其2倍的值 5 x -> 2 /*x6 7 //3. 接受2个参数(数字),并返回他们的差值 8 (x, y) ->x – y9 10 //4. 接收2个int型整数,返回他们的和 11 (int x, int y) -> x +y12 13 //5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void) 14 (String s) -> System.out.print(s)
现在就可以解释上面的实例中的 Lambda表达式 的含义person->person.id>90即接收一个person参数,并返回大于person.id>90的数据
方法引用是用来直接访问类或者实例的已经存在的方法或者构造方法。方法引用提供了一种引用而不执行方法的方式,它需要由兼容的函数式接口构成的目标类型上下文。计算时,方法引用会创建函数式接口的一个实例。
可以看作是lambda的一种快捷写法,显式的指定方法的名称更具可读性。格式:目标引用+分隔符::+方法,例如,Dog::getAge就是引用了Dog类中定义的方法getAge。
注意方法引用是一个Lambda表达式,其中方法引用的操作符是双冒号"::"。
Lambda方法引用包含一下四种:
首先需要有一个静态方法1 public static booleantest(Person person) {2 return person.id>90 && person.id<95;3 }
在Lambda表达式中调用这个静态方法,因为是静态方法可以不用创建对象,所以直接用类名进行调用
1 judge(lists, person -> TestLambda.test(person));
利用方法引用调用静态方法的形式
1 judge(lists, TestLambda::test);
主程序为
1 packagereferences;2 3 importjava.util.ArrayList;4 importjava.util.List;5 importjava.util.Random;6 7 importanonymity.PersonCheck;8 importperson.Person;9 10 /// 11 / Lambda表达式12 /@authorjyroy13 /14 // 15 public classTestLambda {16 17 @SuppressWarnings({ "rawtypes", "unused", "unchecked"})18 public static voidmain(String[] args) {19 Random r = newRandom();20 List
和静态方法相似,,但是在传递方法的时候,因为不是静态方法,所以必须要利用对象进行传送1 packagereferences;2 3 importjava.util.ArrayList;4 importjava.util.List;5 importjava.util.Random;6 7 importanonymity.PersonCheck;8 importperson.Person;9 10 /// 11 / Lambda表达式12 /@authorjyroy13 /14 // 15 public classTestLambda {16 17 @SuppressWarnings({ "rawtypes", "unused", "unchecked"})18 public static voidmain(String[] args) {19 Random r = newRandom();20 List
Person类要添加一个成员方法,才能够进行成员方法的引用1 public booleantest3() {2 return this.id>90 && this.id<95;3 }
在Lambda表达式中使用 test3方法
1 judge(lists, person -> person.test3());
利用方法引用的写法为
1 judge(lists, Person::test3);
主程序为
1 packagereferences;2 3 importjava.util.ArrayList;4 importjava.util.List;5 importjava.util.Random;6 7 importanonymity.PersonCheck;8 importperson.Person;9 10 /// 11 / Lambda表达式12 /@authorjyroy13 /14 // 15 public classTestLambda {16 17 @SuppressWarnings({ "rawtypes", "unused", "unchecked"})18 public static voidmain(String[] args) {19 Random r = newRandom();20 List
需要有返回一个对象的方法
构造方法引用形式为1 ArrayList::new 2 Person::new
1 packagelambda;2 3 importjava.util.ArrayList;4 importjava.util.List;5 importjava.util.function.Supplier;6 7 public classTestLambda {8 public static voidmain(String[] args) {9 Supplier s = new Supplier
() {10 publicList get() {11 return newArrayList();12 }13 };14 //引用构造器 15 List list3 = getList(ArrayList::new);16 17 }18 19 public static List getList(Supplier
s){20 returns.get();21 }
在上面的程序中,遍历输出数据利用的是for循环的方式1 for(Person person:lists) {2 if(personCheck.test(person)) {3 System.out.println(person);4 }5 }
我们可以利用聚合操作来进行数据的输出
1 lists2 .stream()3 .filter(person -> person.id>95)4 .forEach(person -> System.out.println(person.id));
主程序为
1 packagenormal;2 3 importjava.util.ArrayList;4 importjava.util.List;5 importjava.util.Random;6 7 importlambda.Check;8 importperson.Person;9 10 public classTestLambda {11 @SuppressWarnings({ "rawtypes", "unused", "unchecked"})12 public static voidmain(String[] args) {13 Random r = newRandom();14 List
结果
我们对应上面的代码,可以看出,聚合操作分为三步
当然我们还要知道stream和管道的概念
Stream:Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到,前面处理的结果。注意:这个Stream和I/O中的InputStream,OutputStream是不一样的概念。
管道:指的是一系列的聚合操作。
管道又分3个部分:管道源、中间操作、结束操作
管道源:在这个例子里,源是一个List,可以用 .stream() 方法切换成管道源。但是数组没有stream() 方法,需要用 Arrays.stream(hs) 或者 Stream.of(hs)1 packagelambda;2 3 importjava.util.ArrayList;4 importjava.util.Arrays;5 importjava.util.HashMap;6 importjava.util.List;7 importjava.util.Random;8 9 importcharactor.Hero;10 11 public classTestAggregate {12 13 public static voidmain(String[] args) {14 Random r = newRandom();15 List
中间操作: 每个中间操作,又会返回一个Stream,比如.filter()又返回一个Stream, 中间操作是“懒”操作,并不会真正进行遍历。中间操作比较多,主要分两类对元素进行筛选 和 转换为其他形式的流
对元素进行筛选:filter 匹配distinct 去除重复(根据equals判断)sorted 自然排序sorted(Comparator
结束操作:当这个操作执行后,流就被使用“光”了,无法再被操作。所以这必定是流的最后一个操作。 结束操作不会返回Stream,但是会返回int、float、String、 Collection或者像forEach,什么都不返回, 结束操作才进行真正的遍历行为,在遍历的时候,才会去进行中间操作的相关判断.
常见结束操作如下:forEach() 遍历每个元素toArray() 转换为数组min(Comparator
首选准备100个Person对象,id都是随机数。分别用传统方式和聚合操作的方式,把id第三高的名称和id打印出来
Person.java1 packageaggregation;2 3 public classPerson {4 publicString name;5 public intid;6 7 public Person(String name, intid){8 this.name =name;9 this.id =id;10 }11 12 @Override13 publicString toString() {14 return "Person [name=" + name + ", id=" + id + "]";15 }16 }
TestLambda.java
1 packageaggregation;2 3 importjava.util.ArrayList;4 importjava.util.Collections;5 importjava.util.Comparator;6 importjava.util.List;7 importjava.util.Random;8 9 importlambda.Check;10 11 public classTestLambda {12 @SuppressWarnings({ "rawtypes", "unused", "unchecked"})13 public static voidmain(String[] args) {14 Random r = newRandom();15 List
结果